989 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C#
		
	
	
	
		
		
			
		
	
	
			989 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C#
		
	
	
	
|  | #region Header | ||
|  | /** | ||
|  |  * JsonMapper.cs | ||
|  |  *   JSON to .Net object and object to JSON conversions. | ||
|  |  * | ||
|  |  * The authors disclaim copyright to this source code. For more details, see | ||
|  |  * the COPYING file included with this distribution. | ||
|  |  **/ | ||
|  | #endregion | ||
|  | 
 | ||
|  | 
 | ||
|  | using System; | ||
|  | using System.Collections; | ||
|  | using System.Collections.Generic; | ||
|  | using System.Globalization; | ||
|  | using System.IO; | ||
|  | using System.Reflection; | ||
|  | 
 | ||
|  | 
 | ||
|  | namespace AnyThinkAds.ThirdParty.LitJson | ||
|  | { | ||
|  |     internal struct PropertyMetadata | ||
|  |     { | ||
|  |         public MemberInfo Info; | ||
|  |         public bool       IsField; | ||
|  |         public Type       Type; | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     internal struct ArrayMetadata | ||
|  |     { | ||
|  |         private Type element_type; | ||
|  |         private bool is_array; | ||
|  |         private bool is_list; | ||
|  | 
 | ||
|  | 
 | ||
|  |         public Type ElementType { | ||
|  |             get { | ||
|  |                 if (element_type == null) | ||
|  |                     return typeof (JsonData); | ||
|  | 
 | ||
|  |                 return element_type; | ||
|  |             } | ||
|  | 
 | ||
|  |             set { element_type = value; } | ||
|  |         } | ||
|  | 
 | ||
|  |         public bool IsArray { | ||
|  |             get { return is_array; } | ||
|  |             set { is_array = value; } | ||
|  |         } | ||
|  | 
 | ||
|  |         public bool IsList { | ||
|  |             get { return is_list; } | ||
|  |             set { is_list = value; } | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     internal struct ObjectMetadata | ||
|  |     { | ||
|  |         private Type element_type; | ||
|  |         private bool is_dictionary; | ||
|  | 
 | ||
|  |         private IDictionary<string, PropertyMetadata> properties; | ||
|  | 
 | ||
|  | 
 | ||
|  |         public Type ElementType { | ||
|  |             get { | ||
|  |                 if (element_type == null) | ||
|  |                     return typeof (JsonData); | ||
|  | 
 | ||
|  |                 return element_type; | ||
|  |             } | ||
|  | 
 | ||
|  |             set { element_type = value; } | ||
|  |         } | ||
|  | 
 | ||
|  |         public bool IsDictionary { | ||
|  |             get { return is_dictionary; } | ||
|  |             set { is_dictionary = value; } | ||
|  |         } | ||
|  | 
 | ||
|  |         public IDictionary<string, PropertyMetadata> Properties { | ||
|  |             get { return properties; } | ||
|  |             set { properties = value; } | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     internal delegate void ExporterFunc    (object obj, JsonWriter writer); | ||
|  |     public   delegate void ExporterFunc<T> (T obj, JsonWriter writer); | ||
|  | 
 | ||
|  |     internal delegate object ImporterFunc                (object input); | ||
|  |     public   delegate TValue ImporterFunc<TJson, TValue> (TJson input); | ||
|  | 
 | ||
|  |     public delegate IJsonWrapper WrapperFactory (); | ||
|  | 
 | ||
|  | 
 | ||
|  |     public class JsonMapper | ||
|  |     { | ||
|  |         #region Fields | ||
|  |         private static readonly int max_nesting_depth; | ||
|  | 
 | ||
|  |         private static readonly IFormatProvider datetime_format; | ||
|  | 
 | ||
|  |         private static readonly IDictionary<Type, ExporterFunc> base_exporters_table; | ||
|  |         private static readonly IDictionary<Type, ExporterFunc> custom_exporters_table; | ||
|  | 
 | ||
|  |         private static readonly IDictionary<Type, | ||
|  |                 IDictionary<Type, ImporterFunc>> base_importers_table; | ||
|  |         private static readonly IDictionary<Type, | ||
|  |                 IDictionary<Type, ImporterFunc>> custom_importers_table; | ||
|  | 
 | ||
|  |         private static readonly IDictionary<Type, ArrayMetadata> array_metadata; | ||
|  |         private static readonly object array_metadata_lock = new Object (); | ||
|  | 
 | ||
|  |         private static readonly IDictionary<Type, | ||
|  |                 IDictionary<Type, MethodInfo>> conv_ops; | ||
|  |         private static readonly object conv_ops_lock = new Object (); | ||
|  | 
 | ||
|  |         private static readonly IDictionary<Type, ObjectMetadata> object_metadata; | ||
|  |         private static readonly object object_metadata_lock = new Object (); | ||
|  | 
 | ||
|  |         private static readonly IDictionary<Type, | ||
|  |                 IList<PropertyMetadata>> type_properties; | ||
|  |         private static readonly object type_properties_lock = new Object (); | ||
|  | 
 | ||
|  |         private static readonly JsonWriter      static_writer; | ||
|  |         private static readonly object static_writer_lock = new Object (); | ||
|  |         #endregion | ||
|  | 
 | ||
|  | 
 | ||
|  |         #region Constructors | ||
|  |         static JsonMapper () | ||
|  |         { | ||
|  |             max_nesting_depth = 100; | ||
|  | 
 | ||
|  |             array_metadata = new Dictionary<Type, ArrayMetadata> (); | ||
|  |             conv_ops = new Dictionary<Type, IDictionary<Type, MethodInfo>> (); | ||
|  |             object_metadata = new Dictionary<Type, ObjectMetadata> (); | ||
|  |             type_properties = new Dictionary<Type, | ||
|  |                             IList<PropertyMetadata>> (); | ||
|  | 
 | ||
|  |             static_writer = new JsonWriter (); | ||
|  | 
 | ||
|  |             datetime_format = DateTimeFormatInfo.InvariantInfo; | ||
|  | 
 | ||
|  |             base_exporters_table   = new Dictionary<Type, ExporterFunc> (); | ||
|  |             custom_exporters_table = new Dictionary<Type, ExporterFunc> (); | ||
|  | 
 | ||
|  |             base_importers_table = new Dictionary<Type, | ||
|  |                                  IDictionary<Type, ImporterFunc>> (); | ||
|  |             custom_importers_table = new Dictionary<Type, | ||
|  |                                    IDictionary<Type, ImporterFunc>> (); | ||
|  | 
 | ||
|  |             RegisterBaseExporters (); | ||
|  |             RegisterBaseImporters (); | ||
|  |         } | ||
|  |         #endregion | ||
|  | 
 | ||
|  | 
 | ||
|  |         #region Private Methods | ||
|  |         private static void AddArrayMetadata (Type type) | ||
|  |         { | ||
|  |             if (array_metadata.ContainsKey (type)) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             ArrayMetadata data = new ArrayMetadata (); | ||
|  | 
 | ||
|  |             data.IsArray = type.IsArray; | ||
|  | 
 | ||
|  |             if (type.GetInterface ("System.Collections.IList") != null) | ||
|  |                 data.IsList = true; | ||
|  | 
 | ||
|  |             foreach (PropertyInfo p_info in type.GetProperties ()) { | ||
|  |                 if (p_info.Name != "Item") | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 ParameterInfo[] parameters = p_info.GetIndexParameters (); | ||
|  | 
 | ||
|  |                 if (parameters.Length != 1) | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 if (parameters[0].ParameterType == typeof (int)) | ||
|  |                     data.ElementType = p_info.PropertyType; | ||
|  |             } | ||
|  | 
 | ||
|  |             lock (array_metadata_lock) { | ||
|  |                 try { | ||
|  |                     array_metadata.Add (type, data); | ||
|  |                 } catch (ArgumentException) { | ||
|  |                     return; | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         private static void AddObjectMetadata (Type type) | ||
|  |         { | ||
|  |             if (object_metadata.ContainsKey (type)) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             ObjectMetadata data = new ObjectMetadata (); | ||
|  | 
 | ||
|  |             if (type.GetInterface ("System.Collections.IDictionary") != null) | ||
|  |                 data.IsDictionary = true; | ||
|  | 
 | ||
|  |             data.Properties = new Dictionary<string, PropertyMetadata> (); | ||
|  | 
 | ||
|  |             foreach (PropertyInfo p_info in type.GetProperties ()) { | ||
|  |                 if (p_info.Name == "Item") { | ||
|  |                     ParameterInfo[] parameters = p_info.GetIndexParameters (); | ||
|  | 
 | ||
|  |                     if (parameters.Length != 1) | ||
|  |                         continue; | ||
|  | 
 | ||
|  |                     if (parameters[0].ParameterType == typeof (string)) | ||
|  |                         data.ElementType = p_info.PropertyType; | ||
|  | 
 | ||
|  |                     continue; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 PropertyMetadata p_data = new PropertyMetadata (); | ||
|  |                 p_data.Info = p_info; | ||
|  |                 p_data.Type = p_info.PropertyType; | ||
|  | 
 | ||
|  |                 data.Properties.Add (p_info.Name, p_data); | ||
|  |             } | ||
|  | 
 | ||
|  |             foreach (FieldInfo f_info in type.GetFields ()) { | ||
|  |                 PropertyMetadata p_data = new PropertyMetadata (); | ||
|  |                 p_data.Info = f_info; | ||
|  |                 p_data.IsField = true; | ||
|  |                 p_data.Type = f_info.FieldType; | ||
|  | 
 | ||
|  |                 data.Properties.Add (f_info.Name, p_data); | ||
|  |             } | ||
|  | 
 | ||
|  |             lock (object_metadata_lock) { | ||
|  |                 try { | ||
|  |                     object_metadata.Add (type, data); | ||
|  |                 } catch (ArgumentException) { | ||
|  |                     return; | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         private static void AddTypeProperties (Type type) | ||
|  |         { | ||
|  |             if (type_properties.ContainsKey (type)) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             IList<PropertyMetadata> props = new List<PropertyMetadata> (); | ||
|  | 
 | ||
|  |             foreach (PropertyInfo p_info in type.GetProperties ()) { | ||
|  |                 if (p_info.Name == "Item") | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 PropertyMetadata p_data = new PropertyMetadata (); | ||
|  |                 p_data.Info = p_info; | ||
|  |                 p_data.IsField = false; | ||
|  |                 props.Add (p_data); | ||
|  |             } | ||
|  | 
 | ||
|  |             foreach (FieldInfo f_info in type.GetFields ()) { | ||
|  |                 PropertyMetadata p_data = new PropertyMetadata (); | ||
|  |                 p_data.Info = f_info; | ||
|  |                 p_data.IsField = true; | ||
|  | 
 | ||
|  |                 props.Add (p_data); | ||
|  |             } | ||
|  | 
 | ||
|  |             lock (type_properties_lock) { | ||
|  |                 try { | ||
|  |                     type_properties.Add (type, props); | ||
|  |                 } catch (ArgumentException) { | ||
|  |                     return; | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         private static MethodInfo GetConvOp (Type t1, Type t2) | ||
|  |         { | ||
|  |             lock (conv_ops_lock) { | ||
|  |                 if (! conv_ops.ContainsKey (t1)) | ||
|  |                     conv_ops.Add (t1, new Dictionary<Type, MethodInfo> ()); | ||
|  |             } | ||
|  | 
 | ||
|  |             if (conv_ops[t1].ContainsKey (t2)) | ||
|  |                 return conv_ops[t1][t2]; | ||
|  | 
 | ||
|  |             MethodInfo op = t1.GetMethod ( | ||
|  |                 "op_Implicit", new Type[] { t2 }); | ||
|  | 
 | ||
|  |             lock (conv_ops_lock) { | ||
|  |                 try { | ||
|  |                     conv_ops[t1].Add (t2, op); | ||
|  |                 } catch (ArgumentException) { | ||
|  |                     return conv_ops[t1][t2]; | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             return op; | ||
|  |         } | ||
|  | 
 | ||
|  |         private static object ReadValue (Type inst_type, JsonReader reader) | ||
|  |         { | ||
|  |             reader.Read (); | ||
|  | 
 | ||
|  |             if (reader.Token == JsonToken.ArrayEnd) | ||
|  |                 return null; | ||
|  | 
 | ||
|  |             Type underlying_type = Nullable.GetUnderlyingType(inst_type); | ||
|  |             Type value_type = underlying_type ?? inst_type; | ||
|  | 
 | ||
|  |             if (reader.Token == JsonToken.Null) { | ||
|  |                 #if NETSTANDARD1_5 | ||
|  |                 if (inst_type.IsClass() || underlying_type != null) { | ||
|  |                     return null; | ||
|  |                 } | ||
|  |                 #else | ||
|  |                 if (inst_type.IsClass || underlying_type != null) { | ||
|  |                     return null; | ||
|  |                 } | ||
|  |                 #endif | ||
|  | 
 | ||
|  |                 throw new JsonException (String.Format ( | ||
|  |                             "Can't assign null to an instance of type {0}", | ||
|  |                             inst_type)); | ||
|  |             } | ||
|  | 
 | ||
|  |             if (reader.Token == JsonToken.Double || | ||
|  |                 reader.Token == JsonToken.Int || | ||
|  |                 reader.Token == JsonToken.Long || | ||
|  |                 reader.Token == JsonToken.String || | ||
|  |                 reader.Token == JsonToken.Boolean) { | ||
|  | 
 | ||
|  |                 Type json_type = reader.Value.GetType (); | ||
|  | 
 | ||
|  |                 if (value_type.IsAssignableFrom (json_type)) | ||
|  |                     return reader.Value; | ||
|  | 
 | ||
|  |                 // If there's a custom importer that fits, use it | ||
|  |                 if (custom_importers_table.ContainsKey (json_type) && | ||
|  |                     custom_importers_table[json_type].ContainsKey ( | ||
|  |                         value_type)) { | ||
|  | 
 | ||
|  |                     ImporterFunc importer = | ||
|  |                         custom_importers_table[json_type][value_type]; | ||
|  | 
 | ||
|  |                     return importer (reader.Value); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 // Maybe there's a base importer that works | ||
|  |                 if (base_importers_table.ContainsKey (json_type) && | ||
|  |                     base_importers_table[json_type].ContainsKey ( | ||
|  |                         value_type)) { | ||
|  | 
 | ||
|  |                     ImporterFunc importer = | ||
|  |                         base_importers_table[json_type][value_type]; | ||
|  | 
 | ||
|  |                     return importer (reader.Value); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 // Maybe it's an enum | ||
|  |                 #if NETSTANDARD1_5 | ||
|  |                 if (value_type.IsEnum()) | ||
|  |                     return Enum.ToObject (value_type, reader.Value); | ||
|  |                 #else | ||
|  |                 if (value_type.IsEnum) | ||
|  |                     return Enum.ToObject (value_type, reader.Value); | ||
|  |                 #endif | ||
|  |                 // Try using an implicit conversion operator | ||
|  |                 MethodInfo conv_op = GetConvOp (value_type, json_type); | ||
|  | 
 | ||
|  |                 if (conv_op != null) | ||
|  |                     return conv_op.Invoke (null, | ||
|  |                                            new object[] { reader.Value }); | ||
|  | 
 | ||
|  |                 // No luck | ||
|  |                 throw new JsonException (String.Format ( | ||
|  |                         "Can't assign value '{0}' (type {1}) to type {2}", | ||
|  |                         reader.Value, json_type, inst_type)); | ||
|  |             } | ||
|  | 
 | ||
|  |             object instance = null; | ||
|  | 
 | ||
|  |             if (reader.Token == JsonToken.ArrayStart) { | ||
|  | 
 | ||
|  |                 AddArrayMetadata (inst_type); | ||
|  |                 ArrayMetadata t_data = array_metadata[inst_type]; | ||
|  | 
 | ||
|  |                 if (! t_data.IsArray && ! t_data.IsList) | ||
|  |                     throw new JsonException (String.Format ( | ||
|  |                             "Type {0} can't act as an array", | ||
|  |                             inst_type)); | ||
|  | 
 | ||
|  |                 IList list; | ||
|  |                 Type elem_type; | ||
|  | 
 | ||
|  |                 if (! t_data.IsArray) { | ||
|  |                     list = (IList) Activator.CreateInstance (inst_type); | ||
|  |                     elem_type = t_data.ElementType; | ||
|  |                 } else { | ||
|  |                     list = new ArrayList (); | ||
|  |                     elem_type = inst_type.GetElementType (); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 list.Clear(); | ||
|  | 
 | ||
|  |                 while (true) { | ||
|  |                     object item = ReadValue (elem_type, reader); | ||
|  |                     if (item == null && reader.Token == JsonToken.ArrayEnd) | ||
|  |                         break; | ||
|  | 
 | ||
|  |                     list.Add (item); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 if (t_data.IsArray) { | ||
|  |                     int n = list.Count; | ||
|  |                     instance = Array.CreateInstance (elem_type, n); | ||
|  | 
 | ||
|  |                     for (int i = 0; i < n; i++) | ||
|  |                         ((Array) instance).SetValue (list[i], i); | ||
|  |                 } else | ||
|  |                     instance = list; | ||
|  | 
 | ||
|  |             } else if (reader.Token == JsonToken.ObjectStart) { | ||
|  |                 AddObjectMetadata (value_type); | ||
|  |                 ObjectMetadata t_data = object_metadata[value_type]; | ||
|  | 
 | ||
|  |                 instance = Activator.CreateInstance (value_type); | ||
|  | 
 | ||
|  |                 while (true) { | ||
|  |                     reader.Read (); | ||
|  | 
 | ||
|  |                     if (reader.Token == JsonToken.ObjectEnd) | ||
|  |                         break; | ||
|  | 
 | ||
|  |                     string property = (string) reader.Value; | ||
|  | 
 | ||
|  |                     if (t_data.Properties.ContainsKey (property)) { | ||
|  |                         PropertyMetadata prop_data = | ||
|  |                             t_data.Properties[property]; | ||
|  | 
 | ||
|  |                         if (prop_data.IsField) { | ||
|  |                             ((FieldInfo) prop_data.Info).SetValue ( | ||
|  |                                 instance, ReadValue (prop_data.Type, reader)); | ||
|  |                         } else { | ||
|  |                             PropertyInfo p_info = | ||
|  |                                 (PropertyInfo) prop_data.Info; | ||
|  | 
 | ||
|  |                             if (p_info.CanWrite) | ||
|  |                                 p_info.SetValue ( | ||
|  |                                     instance, | ||
|  |                                     ReadValue (prop_data.Type, reader), | ||
|  |                                     null); | ||
|  |                             else | ||
|  |                                 ReadValue (prop_data.Type, reader); | ||
|  |                         } | ||
|  | 
 | ||
|  |                     } else { | ||
|  |                         if (! t_data.IsDictionary) { | ||
|  | 
 | ||
|  |                             if (! reader.SkipNonMembers) { | ||
|  |                                 throw new JsonException (String.Format ( | ||
|  |                                         "The type {0} doesn't have the " + | ||
|  |                                         "property '{1}'", | ||
|  |                                         inst_type, property)); | ||
|  |                             } else { | ||
|  |                                 ReadSkip (reader); | ||
|  |                                 continue; | ||
|  |                             } | ||
|  |                         } | ||
|  | 
 | ||
|  |                         ((IDictionary) instance).Add ( | ||
|  |                             property, ReadValue ( | ||
|  |                                 t_data.ElementType, reader)); | ||
|  |                     } | ||
|  | 
 | ||
|  |                 } | ||
|  | 
 | ||
|  |             } | ||
|  | 
 | ||
|  |             return instance; | ||
|  |         } | ||
|  | 
 | ||
|  |         private static IJsonWrapper ReadValue (WrapperFactory factory, | ||
|  |                                                JsonReader reader) | ||
|  |         { | ||
|  |             reader.Read (); | ||
|  | 
 | ||
|  |             if (reader.Token == JsonToken.ArrayEnd || | ||
|  |                 reader.Token == JsonToken.Null) | ||
|  |                 return null; | ||
|  | 
 | ||
|  |             IJsonWrapper instance = factory (); | ||
|  | 
 | ||
|  |             if (reader.Token == JsonToken.String) { | ||
|  |                 instance.SetString ((string) reader.Value); | ||
|  |                 return instance; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (reader.Token == JsonToken.Double) { | ||
|  |                 instance.SetDouble ((double) reader.Value); | ||
|  |                 return instance; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (reader.Token == JsonToken.Int) { | ||
|  |                 instance.SetInt ((int) reader.Value); | ||
|  |                 return instance; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (reader.Token == JsonToken.Long) { | ||
|  |                 instance.SetLong ((long) reader.Value); | ||
|  |                 return instance; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (reader.Token == JsonToken.Boolean) { | ||
|  |                 instance.SetBoolean ((bool) reader.Value); | ||
|  |                 return instance; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (reader.Token == JsonToken.ArrayStart) { | ||
|  |                 instance.SetJsonType (JsonType.Array); | ||
|  | 
 | ||
|  |                 while (true) { | ||
|  |                     IJsonWrapper item = ReadValue (factory, reader); | ||
|  |                     if (item == null && reader.Token == JsonToken.ArrayEnd) | ||
|  |                         break; | ||
|  | 
 | ||
|  |                     ((IList) instance).Add (item); | ||
|  |                 } | ||
|  |             } | ||
|  |             else if (reader.Token == JsonToken.ObjectStart) { | ||
|  |                 instance.SetJsonType (JsonType.Object); | ||
|  | 
 | ||
|  |                 while (true) { | ||
|  |                     reader.Read (); | ||
|  | 
 | ||
|  |                     if (reader.Token == JsonToken.ObjectEnd) | ||
|  |                         break; | ||
|  | 
 | ||
|  |                     string property = (string) reader.Value; | ||
|  | 
 | ||
|  |                     ((IDictionary) instance)[property] = ReadValue ( | ||
|  |                         factory, reader); | ||
|  |                 } | ||
|  | 
 | ||
|  |             } | ||
|  | 
 | ||
|  |             return instance; | ||
|  |         } | ||
|  | 
 | ||
|  |         private static void ReadSkip (JsonReader reader) | ||
|  |         { | ||
|  |             ToWrapper ( | ||
|  |                 delegate { return new JsonMockWrapper (); }, reader); | ||
|  |         } | ||
|  | 
 | ||
|  |         private static void RegisterBaseExporters () | ||
|  |         { | ||
|  |             base_exporters_table[typeof (byte)] = | ||
|  |                 delegate (object obj, JsonWriter writer) { | ||
|  |                     writer.Write (Convert.ToInt32 ((byte) obj)); | ||
|  |                 }; | ||
|  | 
 | ||
|  |             base_exporters_table[typeof (char)] = | ||
|  |                 delegate (object obj, JsonWriter writer) { | ||
|  |                     writer.Write (Convert.ToString ((char) obj)); | ||
|  |                 }; | ||
|  | 
 | ||
|  |             base_exporters_table[typeof (DateTime)] = | ||
|  |                 delegate (object obj, JsonWriter writer) { | ||
|  |                     writer.Write (Convert.ToString ((DateTime) obj, | ||
|  |                                                     datetime_format)); | ||
|  |                 }; | ||
|  | 
 | ||
|  |             base_exporters_table[typeof (decimal)] = | ||
|  |                 delegate (object obj, JsonWriter writer) { | ||
|  |                     writer.Write ((decimal) obj); | ||
|  |                 }; | ||
|  | 
 | ||
|  |             base_exporters_table[typeof (sbyte)] = | ||
|  |                 delegate (object obj, JsonWriter writer) { | ||
|  |                     writer.Write (Convert.ToInt32 ((sbyte) obj)); | ||
|  |                 }; | ||
|  | 
 | ||
|  |             base_exporters_table[typeof (short)] = | ||
|  |                 delegate (object obj, JsonWriter writer) { | ||
|  |                     writer.Write (Convert.ToInt32 ((short) obj)); | ||
|  |                 }; | ||
|  | 
 | ||
|  |             base_exporters_table[typeof (ushort)] = | ||
|  |                 delegate (object obj, JsonWriter writer) { | ||
|  |                     writer.Write (Convert.ToInt32 ((ushort) obj)); | ||
|  |                 }; | ||
|  | 
 | ||
|  |             base_exporters_table[typeof (uint)] = | ||
|  |                 delegate (object obj, JsonWriter writer) { | ||
|  |                     writer.Write (Convert.ToUInt64 ((uint) obj)); | ||
|  |                 }; | ||
|  | 
 | ||
|  |             base_exporters_table[typeof (ulong)] = | ||
|  |                 delegate (object obj, JsonWriter writer) { | ||
|  |                     writer.Write ((ulong) obj); | ||
|  |                 }; | ||
|  | 
 | ||
|  |             base_exporters_table[typeof(DateTimeOffset)] = | ||
|  |                 delegate (object obj, JsonWriter writer) { | ||
|  |                     writer.Write(((DateTimeOffset)obj).ToString("yyyy-MM-ddTHH:mm:ss.fffffffzzz", datetime_format)); | ||
|  |                 }; | ||
|  |         } | ||
|  | 
 | ||
|  |         private static void RegisterBaseImporters () | ||
|  |         { | ||
|  |             ImporterFunc importer; | ||
|  | 
 | ||
|  |             importer = delegate (object input) { | ||
|  |                 return Convert.ToByte ((int) input); | ||
|  |             }; | ||
|  |             RegisterImporter (base_importers_table, typeof (int), | ||
|  |                               typeof (byte), importer); | ||
|  | 
 | ||
|  |             importer = delegate (object input) { | ||
|  |                 return Convert.ToUInt64 ((int) input); | ||
|  |             }; | ||
|  |             RegisterImporter (base_importers_table, typeof (int), | ||
|  |                               typeof (ulong), importer); | ||
|  | 
 | ||
|  |             importer = delegate (object input) { | ||
|  |                 return Convert.ToInt64((int)input); | ||
|  |             }; | ||
|  |             RegisterImporter(base_importers_table, typeof(int), | ||
|  |                               typeof(long), importer); | ||
|  | 
 | ||
|  |             importer = delegate (object input) { | ||
|  |                 return Convert.ToSByte ((int) input); | ||
|  |             }; | ||
|  |             RegisterImporter (base_importers_table, typeof (int), | ||
|  |                               typeof (sbyte), importer); | ||
|  | 
 | ||
|  |             importer = delegate (object input) { | ||
|  |                 return Convert.ToInt16 ((int) input); | ||
|  |             }; | ||
|  |             RegisterImporter (base_importers_table, typeof (int), | ||
|  |                               typeof (short), importer); | ||
|  | 
 | ||
|  |             importer = delegate (object input) { | ||
|  |                 return Convert.ToUInt16 ((int) input); | ||
|  |             }; | ||
|  |             RegisterImporter (base_importers_table, typeof (int), | ||
|  |                               typeof (ushort), importer); | ||
|  | 
 | ||
|  |             importer = delegate (object input) { | ||
|  |                 return Convert.ToUInt32 ((int) input); | ||
|  |             }; | ||
|  |             RegisterImporter (base_importers_table, typeof (int), | ||
|  |                               typeof (uint), importer); | ||
|  | 
 | ||
|  |             importer = delegate (object input) { | ||
|  |                 return Convert.ToSingle ((int) input); | ||
|  |             }; | ||
|  |             RegisterImporter (base_importers_table, typeof (int), | ||
|  |                               typeof (float), importer); | ||
|  | 
 | ||
|  |             importer = delegate (object input) { | ||
|  |                 return Convert.ToDouble ((int) input); | ||
|  |             }; | ||
|  |             RegisterImporter (base_importers_table, typeof (int), | ||
|  |                               typeof (double), importer); | ||
|  | 
 | ||
|  |             importer = delegate (object input) { | ||
|  |                 return Convert.ToDecimal ((double) input); | ||
|  |             }; | ||
|  |             RegisterImporter (base_importers_table, typeof (double), | ||
|  |                               typeof (decimal), importer); | ||
|  | 
 | ||
|  |             importer = delegate (object input) { | ||
|  |                 return Convert.ToSingle((double)input); | ||
|  |             }; | ||
|  |             RegisterImporter(base_importers_table, typeof(double), | ||
|  |                 typeof(float), importer); | ||
|  | 
 | ||
|  |             importer = delegate (object input) { | ||
|  |                 return Convert.ToUInt32 ((long) input); | ||
|  |             }; | ||
|  |             RegisterImporter (base_importers_table, typeof (long), | ||
|  |                               typeof (uint), importer); | ||
|  | 
 | ||
|  |             importer = delegate (object input) { | ||
|  |                 return Convert.ToChar ((string) input); | ||
|  |             }; | ||
|  |             RegisterImporter (base_importers_table, typeof (string), | ||
|  |                               typeof (char), importer); | ||
|  | 
 | ||
|  |             importer = delegate (object input) { | ||
|  |                 return Convert.ToDateTime ((string) input, datetime_format); | ||
|  |             }; | ||
|  |             RegisterImporter (base_importers_table, typeof (string), | ||
|  |                               typeof (DateTime), importer); | ||
|  | 
 | ||
|  |             importer = delegate (object input) { | ||
|  |                 return DateTimeOffset.Parse((string)input, datetime_format); | ||
|  |             }; | ||
|  |             RegisterImporter(base_importers_table, typeof(string), | ||
|  |                 typeof(DateTimeOffset), importer); | ||
|  |         } | ||
|  | 
 | ||
|  |         private static void RegisterImporter ( | ||
|  |             IDictionary<Type, IDictionary<Type, ImporterFunc>> table, | ||
|  |             Type json_type, Type value_type, ImporterFunc importer) | ||
|  |         { | ||
|  |             if (! table.ContainsKey (json_type)) | ||
|  |                 table.Add (json_type, new Dictionary<Type, ImporterFunc> ()); | ||
|  | 
 | ||
|  |             table[json_type][value_type] = importer; | ||
|  |         } | ||
|  | 
 | ||
|  |         private static void WriteValue (object obj, JsonWriter writer, | ||
|  |                                         bool writer_is_private, | ||
|  |                                         int depth) | ||
|  |         { | ||
|  |             if (depth > max_nesting_depth) | ||
|  |                 throw new JsonException ( | ||
|  |                     String.Format ("Max allowed object depth reached while " + | ||
|  |                                    "trying to export from type {0}", | ||
|  |                                    obj.GetType ())); | ||
|  | 
 | ||
|  |             if (obj == null) { | ||
|  |                 writer.WriteObjectStart(); | ||
|  |                 writer.WriteObjectEnd(); | ||
|  |                 return; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (obj is IJsonWrapper) { | ||
|  |                 if (writer_is_private) | ||
|  |                     writer.TextWriter.Write (((IJsonWrapper) obj).ToJson ()); | ||
|  |                 else | ||
|  |                     ((IJsonWrapper) obj).ToJson (writer); | ||
|  | 
 | ||
|  |                 return; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (obj is String) { | ||
|  |                 writer.Write ((string) obj); | ||
|  |                 return; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (obj is Double) { | ||
|  |                 writer.Write ((double) obj); | ||
|  |                 return; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (obj is Single) | ||
|  |             { | ||
|  |                 writer.Write((float)obj); | ||
|  |                 return; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (obj is Int32) { | ||
|  |                 writer.Write ((int) obj); | ||
|  |                 return; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (obj is Boolean) { | ||
|  |                 writer.Write ((bool) obj); | ||
|  |                 return; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (obj is Int64) { | ||
|  |                 writer.Write ((long) obj); | ||
|  |                 return; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (obj is Array) { | ||
|  |                 writer.WriteArrayStart (); | ||
|  | 
 | ||
|  |                 foreach (object elem in (Array) obj) | ||
|  |                     WriteValue (elem, writer, writer_is_private, depth + 1); | ||
|  | 
 | ||
|  |                 writer.WriteArrayEnd (); | ||
|  | 
 | ||
|  |                 return; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (obj is IList) { | ||
|  |                 writer.WriteArrayStart (); | ||
|  |                 foreach (object elem in (IList) obj) | ||
|  |                     WriteValue (elem, writer, writer_is_private, depth + 1); | ||
|  |                 writer.WriteArrayEnd (); | ||
|  | 
 | ||
|  |                 return; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (obj is IDictionary dictionary) { | ||
|  |                 writer.WriteObjectStart (); | ||
|  |                 foreach (DictionaryEntry entry in dictionary) { | ||
|  |                     var propertyName = entry.Key is string key ? | ||
|  |                         key | ||
|  |                         : Convert.ToString(entry.Key, CultureInfo.InvariantCulture); | ||
|  |                     writer.WritePropertyName (propertyName); | ||
|  |                     WriteValue (entry.Value, writer, writer_is_private, | ||
|  |                                 depth + 1); | ||
|  |                 } | ||
|  |                 writer.WriteObjectEnd (); | ||
|  | 
 | ||
|  |                 return; | ||
|  |             } | ||
|  | 
 | ||
|  |             Type obj_type = obj.GetType (); | ||
|  | 
 | ||
|  |             // See if there's a custom exporter for the object | ||
|  |             if (custom_exporters_table.ContainsKey (obj_type)) { | ||
|  |                 ExporterFunc exporter = custom_exporters_table[obj_type]; | ||
|  |                 exporter (obj, writer); | ||
|  | 
 | ||
|  |                 return; | ||
|  |             } | ||
|  | 
 | ||
|  |             // If not, maybe there's a base exporter | ||
|  |             if (base_exporters_table.ContainsKey (obj_type)) { | ||
|  |                 ExporterFunc exporter = base_exporters_table[obj_type]; | ||
|  |                 exporter (obj, writer); | ||
|  | 
 | ||
|  |                 return; | ||
|  |             } | ||
|  | 
 | ||
|  |             // Last option, let's see if it's an enum | ||
|  |             if (obj is Enum) { | ||
|  |                 Type e_type = Enum.GetUnderlyingType (obj_type); | ||
|  | 
 | ||
|  |                 if (e_type == typeof (long)) | ||
|  |                     writer.Write ((long) obj); | ||
|  |                 else if (e_type == typeof (uint)) | ||
|  |                     writer.Write ((uint) obj); | ||
|  |                 else if (e_type == typeof (ulong)) | ||
|  |                     writer.Write ((ulong) obj); | ||
|  |                 else if (e_type == typeof(ushort)) | ||
|  |                     writer.Write ((ushort)obj); | ||
|  |                 else if (e_type == typeof(short)) | ||
|  |                     writer.Write ((short)obj); | ||
|  |                 else if (e_type == typeof(byte)) | ||
|  |                     writer.Write ((byte)obj); | ||
|  |                 else if (e_type == typeof(sbyte)) | ||
|  |                     writer.Write ((sbyte)obj); | ||
|  |                 else | ||
|  |                     writer.Write ((int) obj); | ||
|  | 
 | ||
|  |                 return; | ||
|  |             } | ||
|  | 
 | ||
|  |             // Okay, so it looks like the input should be exported as an | ||
|  |             // object | ||
|  |             AddTypeProperties (obj_type); | ||
|  |             IList<PropertyMetadata> props = type_properties[obj_type]; | ||
|  | 
 | ||
|  |             writer.WriteObjectStart (); | ||
|  |             foreach (PropertyMetadata p_data in props) { | ||
|  |                 if (p_data.IsField) { | ||
|  |                     writer.WritePropertyName (p_data.Info.Name); | ||
|  |                     WriteValue (((FieldInfo) p_data.Info).GetValue (obj), | ||
|  |                                 writer, writer_is_private, depth + 1); | ||
|  |                 } | ||
|  |                 else { | ||
|  |                     PropertyInfo p_info = (PropertyInfo) p_data.Info; | ||
|  | 
 | ||
|  |                     if (p_info.CanRead) { | ||
|  |                         writer.WritePropertyName (p_data.Info.Name); | ||
|  |                         WriteValue (p_info.GetValue (obj, null), | ||
|  |                                     writer, writer_is_private, depth + 1); | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  |             writer.WriteObjectEnd (); | ||
|  |         } | ||
|  |         #endregion | ||
|  | 
 | ||
|  | 
 | ||
|  |         public static string ToJson (object obj) | ||
|  |         { | ||
|  |             lock (static_writer_lock) { | ||
|  |                 static_writer.Reset (); | ||
|  | 
 | ||
|  |                 WriteValue (obj, static_writer, true, 0); | ||
|  | 
 | ||
|  |                 return static_writer.ToString (); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public static void ToJson (object obj, JsonWriter writer) | ||
|  |         { | ||
|  |             WriteValue (obj, writer, false, 0); | ||
|  |         } | ||
|  | 
 | ||
|  |         public static JsonData ToObject (JsonReader reader) | ||
|  |         { | ||
|  |             return (JsonData) ToWrapper ( | ||
|  |                 delegate { return new JsonData (); }, reader); | ||
|  |         } | ||
|  | 
 | ||
|  |         public static JsonData ToObject (TextReader reader) | ||
|  |         { | ||
|  |             JsonReader json_reader = new JsonReader (reader); | ||
|  | 
 | ||
|  |             return (JsonData) ToWrapper ( | ||
|  |                 delegate { return new JsonData (); }, json_reader); | ||
|  |         } | ||
|  | 
 | ||
|  |         public static JsonData ToObject (string json) | ||
|  |         { | ||
|  |             return (JsonData) ToWrapper ( | ||
|  |                 delegate { return new JsonData (); }, json); | ||
|  |         } | ||
|  | 
 | ||
|  |         public static T ToObject<T> (JsonReader reader) | ||
|  |         { | ||
|  |             return (T) ReadValue (typeof (T), reader); | ||
|  |         } | ||
|  | 
 | ||
|  |         public static T ToObject<T> (TextReader reader) | ||
|  |         { | ||
|  |             JsonReader json_reader = new JsonReader (reader); | ||
|  | 
 | ||
|  |             return (T) ReadValue (typeof (T), json_reader); | ||
|  |         } | ||
|  | 
 | ||
|  |         public static T ToObject<T> (string json) | ||
|  |         { | ||
|  |             JsonReader reader = new JsonReader (json); | ||
|  | 
 | ||
|  |             return (T) ReadValue (typeof (T), reader); | ||
|  |         } | ||
|  | 
 | ||
|  |         public static object ToObject(string json, Type ConvertType ) | ||
|  |         { | ||
|  |             JsonReader reader = new JsonReader(json); | ||
|  | 
 | ||
|  |             return ReadValue(ConvertType, reader); | ||
|  |         } | ||
|  | 
 | ||
|  |         public static IJsonWrapper ToWrapper (WrapperFactory factory, | ||
|  |                                               JsonReader reader) | ||
|  |         { | ||
|  |             return ReadValue (factory, reader); | ||
|  |         } | ||
|  | 
 | ||
|  |         public static IJsonWrapper ToWrapper (WrapperFactory factory, | ||
|  |                                               string json) | ||
|  |         { | ||
|  |             JsonReader reader = new JsonReader (json); | ||
|  | 
 | ||
|  |             return ReadValue (factory, reader); | ||
|  |         } | ||
|  | 
 | ||
|  |         public static void RegisterExporter<T> (ExporterFunc<T> exporter) | ||
|  |         { | ||
|  |             ExporterFunc exporter_wrapper = | ||
|  |                 delegate (object obj, JsonWriter writer) { | ||
|  |                     exporter ((T) obj, writer); | ||
|  |                 }; | ||
|  | 
 | ||
|  |             custom_exporters_table[typeof (T)] = exporter_wrapper; | ||
|  |         } | ||
|  | 
 | ||
|  |         public static void RegisterImporter<TJson, TValue> ( | ||
|  |             ImporterFunc<TJson, TValue> importer) | ||
|  |         { | ||
|  |             ImporterFunc importer_wrapper = | ||
|  |                 delegate (object input) { | ||
|  |                     return importer ((TJson) input); | ||
|  |                 }; | ||
|  | 
 | ||
|  |             RegisterImporter (custom_importers_table, typeof (TJson), | ||
|  |                               typeof (TValue), importer_wrapper); | ||
|  |         } | ||
|  | 
 | ||
|  |         public static void UnregisterExporters () | ||
|  |         { | ||
|  |             custom_exporters_table.Clear (); | ||
|  |         } | ||
|  | 
 | ||
|  |         public static void UnregisterImporters () | ||
|  |         { | ||
|  |             custom_importers_table.Clear (); | ||
|  |         } | ||
|  |     } | ||
|  | } |