/* INFINITY CODE 2013-2019 */ /* http://www.infinity-code.com */ using System; using System.Collections.Generic; using System.Reflection; using System.Text; using InfinityCode.RealWorldTerrain.Utils; using UnityEngine; namespace InfinityCode.RealWorldTerrain.JSON { /// /// The wrapper for JSON dictonary. /// public class RealWorldTerrainJsonObject : RealWorldTerrainJsonItem { private Dictionary _table; /// /// Dictionary of items /// public Dictionary table { get { return _table; } } public override RealWorldTerrainJsonItem this[string key] { get { return Get(key); } } public override RealWorldTerrainJsonItem this[int index] { get { if (index < 0) return null; int i = 0; foreach (KeyValuePair pair in _table) { if (i == index) return pair.Value; i++; } return null; } } /// /// Constructor /// public RealWorldTerrainJsonObject() { _table = new Dictionary(); } /// /// Adds element to the dictionary /// /// Key /// Value public void Add(string name, RealWorldTerrainJsonItem value) { _table[name] = value; } public void Add(string name, object value) { if (value is string || value is bool || value is int || value is long || value is short || value is float || value is double) _table[name] = new RealWorldTerrainJsonValue(value); else if (value is UnityEngine.Object) { _table[name] = new RealWorldTerrainJsonValue((value as UnityEngine.Object).GetInstanceID()); } else _table[name] = RealWorldTerrainJson.Serialize(value, BindingFlags.Instance | BindingFlags.Public); } public void Add(string name, object value, RealWorldTerrainJsonValue.ValueType valueType) { _table[name] = new RealWorldTerrainJsonValue(value, valueType); } public override RealWorldTerrainJsonItem AppendObject(object obj) { Combine(RealWorldTerrainJson.Serialize(obj)); return this; } /// /// Combines two JSON Object. /// /// Other JSON Object /// Overwrite the existing values? public void Combine(RealWorldTerrainJsonItem other, bool overwriteExistingValues = false) { RealWorldTerrainJsonObject otherObj = other as RealWorldTerrainJsonObject; if (otherObj == null) throw new Exception("Only RealWorldTerrainJsonObject is allowed to be combined."); Dictionary otherDict = otherObj.table; foreach (KeyValuePair pair in otherDict) { if (overwriteExistingValues || !_table.ContainsKey(pair.Key)) _table[pair.Key] = pair.Value; } } public bool Contains(string key) { return _table.ContainsKey(key); } public RealWorldTerrainJsonArray CreateArray(string name) { RealWorldTerrainJsonArray array = new RealWorldTerrainJsonArray(); Add(name, array); return array; } public RealWorldTerrainJsonObject CreateObject(string name) { RealWorldTerrainJsonObject obj = new RealWorldTerrainJsonObject(); Add(name, obj); return obj; } public override object Deserialize(Type type, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public) { IEnumerable members = RealWorldTerrainReflectionHelper.GetMembers(type, bindingFlags); return Deserialize(type, members, bindingFlags); } /// /// Deserializes current element /// /// Type /// Members of variable /// Object public object Deserialize(Type type, IEnumerable members, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public) { object v = Activator.CreateInstance(type); DeserializeObject(v, members, bindingFlags); return v; } public void DeserializeObject(object obj, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public) { IEnumerable members = RealWorldTerrainReflectionHelper.GetMembers(obj.GetType(), bindingFlags); DeserializeObject(obj, members); } public void DeserializeObject(object obj, IEnumerable members, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public) { foreach (MemberInfo member in members) { #if !NETFX_CORE MemberTypes memberType = member.MemberType; if (memberType != MemberTypes.Field && memberType != MemberTypes.Property) continue; #else MemberTypes memberType; if (member is PropertyInfo) memberType = MemberTypes.Property; else if (member is FieldInfo) memberType = MemberTypes.Field; else continue; #endif if (memberType == MemberTypes.Property && !((PropertyInfo) member).CanWrite) continue; RealWorldTerrainJsonItem item; #if !NETFX_CORE object[] attributes = member.GetCustomAttributes(typeof(RealWorldTerrainJson.AliasAttribute), true); RealWorldTerrainJson.AliasAttribute alias = attributes.Length > 0 ? attributes[0] as RealWorldTerrainJson.AliasAttribute : null; #else IEnumerable attributes = member.GetCustomAttributes(typeof(RealWorldTerrainJson.AliasAttribute), true); RealWorldTerrainJson.AliasAttribute alias = null; foreach (Attribute a in attributes) { alias = a as RealWorldTerrainJson.AliasAttribute; break; } #endif if (alias == null || !alias.ignoreFieldName) { if (_table.TryGetValue(member.Name, out item)) { Type t = memberType == MemberTypes.Field ? ((FieldInfo) member).FieldType : ((PropertyInfo) member).PropertyType; if (memberType == MemberTypes.Field) ((FieldInfo) member).SetValue(obj, item.Deserialize(t, bindingFlags)); else ((PropertyInfo) member).SetValue(obj, item.Deserialize(t, bindingFlags), null); continue; } } if (alias != null) { for (int j = 0; j < alias.aliases.Length; j++) { if (_table.TryGetValue(alias.aliases[j], out item)) { Type t = memberType == MemberTypes.Field ? ((FieldInfo) member).FieldType : ((PropertyInfo) member).PropertyType; if (memberType == MemberTypes.Field) ((FieldInfo) member).SetValue(obj, item.Deserialize(t, bindingFlags)); else ((PropertyInfo) member).SetValue(obj, item.Deserialize(t, bindingFlags), null); break; } } } } } private RealWorldTerrainJsonItem Get(string key) { if (string.IsNullOrEmpty(key)) return null; if (key.Length > 2 && key[0] == '/' && key[1] == '/') { string k = key.Substring(2); if (string.IsNullOrEmpty(k) || k.StartsWith("//")) return null; return GetAll(k); } return GetThis(key); } private RealWorldTerrainJsonItem GetThis(string key) { RealWorldTerrainJsonItem item; int index = -1; for (int i = 0; i < key.Length; i++) { if (key[i] == '/') { index = i; break; } } if (index != -1) { string k = key.Substring(0, index); if (!string.IsNullOrEmpty(k)) { if (_table.TryGetValue(k, out item)) { string nextPart = key.Substring(index + 1); return item[nextPart]; } } return null; } if (_table.TryGetValue(key, out item)) return item; return null; } public override RealWorldTerrainJsonItem GetAll(string k) { RealWorldTerrainJsonItem item = GetThis(k); RealWorldTerrainJsonArray arr = null; if (item != null) { arr = new RealWorldTerrainJsonArray(); arr.Add(item); } var enumerator = _table.GetEnumerator(); while (enumerator.MoveNext()) { item = enumerator.Current.Value; RealWorldTerrainJsonArray subArr = item.GetAll(k) as RealWorldTerrainJsonArray; if (subArr != null) { if (arr == null) arr = new RealWorldTerrainJsonArray(); arr.AddRange(subArr); } } return arr; } public override IEnumerator GetEnumerator() { return _table.Values.GetEnumerator(); } /// /// Parse a string that contains JSON dictonary /// /// String that contains JSON dictonary /// Instance public static RealWorldTerrainJsonObject ParseObject(string json) { return RealWorldTerrainJson.Parse(json) as RealWorldTerrainJsonObject; } public RealWorldTerrainJsonItem Remove(string key) { RealWorldTerrainJsonItem item; if (_table.TryGetValue(key, out item)) { _table.Remove(key); return item; } return null; } public override void ToJSON(StringBuilder b) { b.Append("{"); bool hasChilds = false; foreach (KeyValuePair pair in _table) { b.Append("\"").Append(pair.Key).Append("\"").Append(":"); pair.Value.ToJSON(b); b.Append(","); hasChilds = true; } if (hasChilds) b.Remove(b.Length - 1, 1); b.Append("}"); } public override object Value(Type type) { if (RealWorldTerrainReflectionHelper.IsValueType(type)) return Activator.CreateInstance(type); return Deserialize(type); } } }