| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321 |
- #define PRETTY //Comment out when you no longer need to read JSON to disable pretty Print system-wide
- //Using doubles will cause errors in VectorTemplates.cs; Unity speaks floats
- #define USEFLOAT //Use floats for numbers instead of doubles (enable if you're getting too many significant digits in string output)
- //#define POOLING //Currently using a build setting for this one (also it's experimental)
- using System.Diagnostics;
- using UnityEngine;
- using System.Collections;
- using System.Collections.Generic;
- using System.Text;
- using Debug = UnityEngine.Debug;
- /*
- * http://www.opensource.org/licenses/lgpl-2.1.php
- * JSONObject class
- * for use with Unity
- * Copyright Matt Schoen 2010 - 2013
- */
- public class JSONObject
- {
- #if POOLING
- const int MAX_POOL_SIZE = 10000;
- public static Queue<JSONObject> releaseQueue = new Queue<JSONObject>();
- #endif
- const int MAX_DEPTH = 100;
- const string INFINITY = "\"INFINITY\"";
- const string NEGINFINITY = "\"NEGINFINITY\"";
- const string NaN = "\"NaN\"";
- static readonly char[] WHITESPACE = new[] { ' ', '\r', '\n', '\t' };
- public enum Type
- {
- NULL,
- STRING,
- NUMBER,
- LONG,
- OBJECT,
- ARRAY,
- BOOL,
- BAKED
- }
- public bool isContainer { get { return (type == Type.ARRAY || type == Type.OBJECT); } }
- public Type type = Type.NULL;
- public int Count {
- get {
- if (list == null)
- return -1;
- return list.Count;
- }
- }
- public List<JSONObject> list;
- public List<string> keys;
- public string str;
- #if USEFLOAT
- long nValue;
- float fValue;
- public long n {
- get { return nValue; }
- set {
- nValue = value;
- fValue = nValue;
- isIntNumber = true;
- }
- }
- public int i { get { return (int)n; } }
- public long l { get { return n; } set { n = value; } }
- public float f {
- get { return fValue; }
- set {
- fValue = value;
- nValue = (int)fValue;
- isIntNumber = false;
- }
- }
- public bool isIntNumber { get; private set; }
- #else
- public double n;
- public float f {
- get {
- return (float)n;
- }
- }
- #endif
- public bool b;
- public delegate void AddJSONConents (JSONObject self);
- public static JSONObject nullJO { get { return Create (Type.NULL); } }
- //an empty, null object
- public static JSONObject newObj { get { return Create (Type.OBJECT); } }
- //an empty object
- public static JSONObject arr { get { return Create (Type.ARRAY); } }
- //an empty array
- public JSONObject (Type t)
- {
- type = t;
- switch (t) {
- case Type.ARRAY:
- list = new List<JSONObject> ();
- break;
- case Type.OBJECT:
- list = new List<JSONObject> ();
- keys = new List<string> ();
- break;
- }
- }
- public JSONObject (bool b)
- {
- type = Type.BOOL;
- this.b = b;
- }
- public JSONObject (long l)
- {
- type = Type.LONG;
- this.l = l;
- }
- #if USEFLOAT
- public JSONObject (float f)
- {
- type = Type.NUMBER;
- this.f = f;
- }
- #else
- public JSONObject(double d) {
- type = Type.NUMBER;
- n = d;
- }
- #endif
- public JSONObject (Dictionary<string, string> dic)
- {
- type = Type.OBJECT;
- keys = new List<string> ();
- list = new List<JSONObject> ();
- //Not sure if it's worth removing the foreach here
- foreach (KeyValuePair<string, string> kvp in dic) {
- keys.Add (kvp.Key);
- list.Add (CreateStringObject (kvp.Value));
- }
- }
- public JSONObject (Dictionary<string, JSONObject> dic)
- {
- type = Type.OBJECT;
- keys = new List<string> ();
- list = new List<JSONObject> ();
- //Not sure if it's worth removing the foreach here
- foreach (KeyValuePair<string, JSONObject> kvp in dic) {
- keys.Add (kvp.Key);
- list.Add (kvp.Value);
- }
- }
- public JSONObject (AddJSONConents content)
- {
- content.Invoke (this);
- }
- public JSONObject (JSONObject[] objs)
- {
- type = Type.ARRAY;
- list = new List<JSONObject> (objs);
- }
- //Convenience function for creating a JSONObject containing a string. This is not part of the constructor so that malformed JSON data doesn't just turn into a string object
- public static JSONObject StringObject (string val)
- {
- return CreateStringObject (val);
- }
- public void Absorb (JSONObject obj)
- {
- list.AddRange (obj.list);
- keys.AddRange (obj.keys);
- str = obj.str;
- #if USEFLOAT
- nValue = obj.nValue;
- fValue = obj.fValue;
- #else
- n = obj.n;
- #endif
- b = obj.b;
- type = obj.type;
- }
- public static JSONObject Create ()
- {
- #if POOLING
- JSONObject result = null;
- while(result == null && releaseQueue.Count > 0) {
- result = releaseQueue.Dequeue();
- #if DEV
- //The following cases should NEVER HAPPEN (but they do...)
- if(result == null)
- Debug.Log("wtf " + releaseQueue.Count);
- else if(result.list != null)
- Debug.Log("wtflist " + result.list.Count);
- #endif
- }
- if(result != null)
- return result;
- #endif
- return new JSONObject ();
- }
- public static JSONObject Create (Type t)
- {
- JSONObject Obj = Create ();
- Obj.type = t;
- switch (t) {
- case Type.ARRAY:
- Obj.list = new List<JSONObject> ();
- break;
- case Type.OBJECT:
- Obj.list = new List<JSONObject> ();
- Obj.keys = new List<string> ();
- break;
- }
- return Obj;
- }
- public static JSONObject Create (bool val)
- {
- JSONObject Obj = Create ();
- Obj.type = Type.BOOL;
- Obj.b = val;
- return Obj;
- }
- public static JSONObject Create (float val)
- {
- JSONObject Obj = Create ();
- Obj.type = Type.NUMBER;
- #if USEFLOAT
- Obj.f = val;
- #else
- Obj.n = val;
- #endif
- return Obj;
- }
- public static JSONObject Create (int val)
- {
- JSONObject Obj = Create ();
- Obj.type = Type.NUMBER;
- Obj.n = val;
- return Obj;
- }
- public static JSONObject Create(long val)
- {
- JSONObject Obj = Create();
- Obj.type = Type.LONG;
- Obj.l = val;
- return Obj;
- }
- public static JSONObject CreateStringObject (string val)
- {
- JSONObject Obj = Create ();
- Obj.type = Type.STRING;
- Obj.str = val;
- return Obj;
- }
- public static JSONObject CreateBakedObject (string val)
- {
- JSONObject bakedObject = Create ();
- bakedObject.type = Type.BAKED;
- bakedObject.str = val;
- return bakedObject;
- }
- /// <summary>
- /// Create a JSONObject by parsing string data
- /// </summary>
- /// <param name="val">The string to be parsed</param>
- /// <param name="maxDepth">The maximum depth for the parser to search. Set this to to 1 for the first level,
- /// 2 for the first 2 levels, etc. It defaults to -2 because -1 is the depth value that is parsed (see below)</param>
- /// <param name="storeExcessLevels">Whether to store levels beyond maxDepth in baked JSONObjects</param>
- /// <param name="strict">Whether to be strict in the parsing. For example, non-strict parsing will successfully
- /// parse "a string" into a string-type </param>
- /// <returns></returns>
- public static JSONObject Create (string val, int maxDepth = -2, bool storeExcessLevels = false, bool strict = false)
- {
- JSONObject Obj = Create ();
- Obj.Parse (val, maxDepth, storeExcessLevels, strict);
- return Obj;
- }
- public static JSONObject Create (AddJSONConents content)
- {
- JSONObject Obj = Create ();
- content.Invoke (Obj);
- return Obj;
- }
- public static JSONObject Create (Dictionary<string, string> dic)
- {
- JSONObject Obj = Create ();
- Obj.type = Type.OBJECT;
- Obj.keys = new List<string> ();
- Obj.list = new List<JSONObject> ();
- //Not sure if it's worth removing the foreach here
- foreach (KeyValuePair<string, string> kvp in dic) {
- Obj.keys.Add (kvp.Key);
- Obj.list.Add (CreateStringObject (kvp.Value));
- }
- return Obj;
- }
- public static JSONObject Create (int[] vals)
- {
- JSONObject resultObj = Create ();
- resultObj.type = Type.ARRAY;
- resultObj.list = new List<JSONObject> ();
- foreach (int v in vals)
- resultObj.list.Add (Create (v));
- return resultObj;
- }
- public static JSONObject CreateArrayJson (params int[] param)
- {
- return Create (param);
- }
- public JSONObject ()
- {
- }
- #region PARSE
- public JSONObject (string str, int maxDepth = -2, bool storeExcessLevels = false, bool strict = false)
- { //create a new JSONObject from a string (this will also create any children, and parse the whole string)
- Parse (str, maxDepth, storeExcessLevels, strict);
- }
- // public static bool output_debug = false;
- void Parse (string inStr, int maxDepth = -2, bool storeExcessLevels = false, bool strict = false)
- {
- if (!string.IsNullOrEmpty (inStr)) {
- inStr = inStr.Trim (WHITESPACE);
- if (strict) {
- if (inStr [0] != '[' && inStr [0] != '{') {
- type = Type.NULL;
- Debug.LogWarning ("Improper (strict) JSON formatting. First character must be [ or {");
- return;
- }
- }
- if (inStr.Length > 0) {
- if (string.Compare (inStr, "true", true) == 0) {
- type = Type.BOOL;
- b = true;
- } else if (string.Compare (inStr, "false", true) == 0) {
- type = Type.BOOL;
- b = false;
- } else if (string.Compare (inStr, "null", true) == 0) {
- type = Type.NULL;
- //#if USEFLOAT
- } else if (inStr == INFINITY) {
- type = Type.NUMBER;
- f = float.PositiveInfinity;
- } else if (inStr == NEGINFINITY) {
- type = Type.NUMBER;
- f = float.NegativeInfinity;
- } else if (inStr == NaN) {
- type = Type.NUMBER;
- f = float.NaN;
- //#else
- // } else if(str == INFINITY) {
- // type = Type.NUMBER;
- // n = double.PositiveInfinity;
- // } else if(str == NEGINFINITY) {
- // type = Type.NUMBER;
- // n = double.NegativeInfinity;
- // } else if(str == NaN) {
- // type = Type.NUMBER;
- // n = double.NaN;
- //#endif
- } else if (inStr [0] == '"') {
- type = Type.STRING;
- str = inStr.Substring (1, inStr.Length - 2);
- if (str.Length > 0 && str.Contains ("\\u")) {
- str = UnicodeUtil.Convert (str);
- }
- } else {
- int tokenTmp = 1;
- /*
- * Checking for the following formatting (www.json.org)
- * object - {"field1":value,"field2":value}
- * array - [value,value,value]
- * value - string - "string"
- * - number - 0.0
- * - bool - true -or- false
- * - null - null
- */
- int offset = 0;
- switch (inStr [offset]) {
- case '{':
- type = Type.OBJECT;
- keys = new List<string> ();
- list = new List<JSONObject> ();
- break;
- case '[':
- type = Type.ARRAY;
- list = new List<JSONObject> ();
- break;
- default:
- try {
- #if USEFLOAT
- if (inStr.IndexOf ('.') >= 0 || inStr.IndexOf ('e') >= 0 || inStr.IndexOf ('E') >= 0) {
- f = System.Convert.ToSingle (inStr);
- } else {
- n = System.Convert.ToInt64 (inStr);
- }
- #else
- n = System.Convert.ToDouble(str);
- #endif
- type = Type.NUMBER;
- } catch (System.FormatException) {
- type = Type.NULL;
- //Debug.LogWarning ("improper JSON formatting:" + str);
- }
- return;
- }
- string propName = "";
- bool openQuote = false;
- bool inProp = false;
- int depth = 0;
- while (++offset < inStr.Length) {
- if (System.Array.IndexOf (WHITESPACE, inStr [offset]) > -1)
- continue;
- if (inStr [offset] == '\\')
- offset += 2;
- if (inStr [offset] == '"') {
- if (openQuote) {
- if (!inProp && depth == 0 && type == Type.OBJECT)
- propName = inStr.Substring (tokenTmp + 1, offset - tokenTmp - 1);
- openQuote = false;
- } else {
- if (depth == 0 && type == Type.OBJECT)
- tokenTmp = offset;
- openQuote = true;
- }
- }
- if (openQuote)
- continue;
- if (type == Type.OBJECT && depth == 0) {
- if (inStr [offset] == ':') {
- tokenTmp = offset + 1;
- inProp = true;
- }
- }
- if (inStr [offset] == '[' || inStr [offset] == '{') {
- depth++;
- } else if (inStr [offset] == ']' || inStr [offset] == '}') {
- depth--;
- }
- //if (encounter a ',' at top level) || a closing ]/}
- if ((inStr [offset] == ',' && depth == 0) || depth < 0) {
- inProp = false;
- string inner = inStr.Substring (tokenTmp, offset - tokenTmp).Trim (WHITESPACE);
- if (inner.Length > 0) {
- // if (output_debug) {
- // Log.D ("{0}", inner);
- // if (inner.CompareTo ("1442809048") == 0)
- // Log.D ("{0}", inner);
- // }
- if (type == Type.OBJECT)
- keys.Add (propName);
- if (maxDepth != -1) //maxDepth of -1 is the end of the line
- list.Add (Create (inner, (maxDepth < -1) ? -2 : maxDepth - 1));
- else if (storeExcessLevels)
- list.Add (CreateBakedObject (inner));
- }
- tokenTmp = offset + 1;
- }
- }
- }
- } else
- type = Type.NULL;
- } else
- type = Type.NULL; //If the string is missing, this is a null
- //Profiler.EndSample();
- }
- #endregion
- public bool IsNumber { get { return type == Type.NUMBER; } }
- public bool IsNull { get { return type == Type.NULL; } }
- public bool IsString { get { return type == Type.STRING; } }
- public bool IsBool { get { return type == Type.BOOL; } }
- public bool IsArray { get { return type == Type.ARRAY; } }
- public bool IsObject { get { return type == Type.OBJECT; } }
- public void Add (bool val)
- {
- Add (Create (val));
- }
- public void Add (float val)
- {
- Add (Create (val));
- }
- public void Add(long val)
- {
- Add (Create(val));
- }
- public void Add (int val)
- {
- Add (Create (val));
- }
- public void Add (string str)
- {
- Add (CreateStringObject (str));
- }
- public void Add (AddJSONConents content)
- {
- Add (Create (content));
- }
- public void Add (JSONObject obj)
- {
- if (obj) { //Don't do anything if the object is null
- if (type != Type.ARRAY) {
- type = Type.ARRAY; //Congratulations, son, you're an ARRAY now
- if (list == null)
- list = new List<JSONObject> ();
- }
- list.Add (obj);
- }
- }
- public void AddBoolField (string name, bool val)
- {
- AddField (name, Create (val));
- }
- public void AddField (string name, bool val)
- {
- AddField (name, Create (val));
- }
- public void AddField (string name, float val)
- {
- AddField (name, Create (val));
- }
- public void AddField (string name, int val)
- {
- AddField (name, Create (val));
- }
- public void AddField(string name, long val)
- {
- AddField(name, Create(val));
- }
- public void AddField (string name, AddJSONConents content)
- {
- AddField (name, Create (content));
- }
- public void AddField (string name, string val)
- {
- AddField (name, CreateStringObject (val));
- }
- public void AddField (string name, JSONObject obj)
- {
- if (obj) { //Don't do anything if the object is null
- if (type != Type.OBJECT) {
- if (keys == null)
- keys = new List<string> ();
- if (type == Type.ARRAY) {
- for (int i = 0; i < list.Count; i++)
- keys.Add (i + "");
- } else if (list == null)
- list = new List<JSONObject> ();
- type = Type.OBJECT; //Congratulations, son, you're an OBJECT now
- }
- keys.Add (name);
- list.Add (obj);
- }
- }
- public void SetField (string name, bool val)
- {
- SetField (name, Create (val));
- }
- public void SetField (string name, float val)
- {
- SetField (name, Create (val));
- }
- public void SetField (string name, int val)
- {
- SetField (name, Create (val));
- }
- public void SetField (string name, JSONObject obj)
- {
- if (HasField (name)) {
- list.Remove (this [name]);
- keys.Remove (name);
- }
- AddField (name, obj);
- }
- public void RemoveField (string name)
- {
- if (keys.IndexOf (name) > -1) {
- list.RemoveAt (keys.IndexOf (name));
- keys.Remove (name);
- }
- }
- public delegate void FieldNotFound (string name);
- public delegate void GetFieldResponse (JSONObject obj);
- public void GetField (ref bool field, string name, FieldNotFound fail = null)
- {
- if (type == Type.OBJECT) {
- int index = keys.IndexOf (name);
- if (index >= 0) {
- field = list [index].b;
- return;
- }
- }
- if (fail != null)
- fail.Invoke (name);
- }
- //#if USEFLOAT
- public void GetField (ref float field, string name, FieldNotFound fail = null)
- {
- //#else
- //public void GetField(ref double field, string name, FieldNotFound fail = null) {
- //#endif
- if (type == Type.OBJECT) {
- int index = keys.IndexOf (name);
- if (index >= 0) {
- field = list [index].f;
- return;
- }
- }
- if (fail != null)
- fail.Invoke (name);
- }
- public void GetField (ref int field, string name, FieldNotFound fail = null)
- {
- if (type == Type.OBJECT) {
- int index = keys.IndexOf (name);
- if (index >= 0) {
- field = (int)list [index].n;
- return;
- }
- }
- if (fail != null)
- fail.Invoke (name);
- }
- public void GetField (ref uint field, string name, FieldNotFound fail = null)
- {
- if (type == Type.OBJECT) {
- int index = keys.IndexOf (name);
- if (index >= 0) {
- field = (uint)list [index].n;
- return;
- }
- }
- if (fail != null)
- fail.Invoke (name);
- }
- public void GetField (ref string field, string name, FieldNotFound fail = null)
- {
- if (type == Type.OBJECT) {
- int index = keys.IndexOf (name);
- if (index >= 0) {
- field = list [index].str;
- return;
- }
- }
- if (fail != null)
- fail.Invoke (name);
- }
- public void GetField (string name, GetFieldResponse response, FieldNotFound fail = null)
- {
- if (response != null && type == Type.OBJECT) {
- int index = keys.IndexOf (name);
- if (index >= 0) {
- response.Invoke (list [index]);
- return;
- }
- }
- if (fail != null)
- fail.Invoke (name);
- }
- public JSONObject GetField (string name)
- {
- if (type == Type.OBJECT)
- for (int i = 0; i < keys.Count; i++)
- if (keys [i] == name)
- return list [i];
- return null;
- }
- public bool HasFields (string[] names)
- {
- for (int i = 0; i < names.Length; i++)
- if (!keys.Contains (names [i]))
- return false;
- return true;
- }
- public bool HasField (string name)
- {
- if (type == Type.OBJECT)
- for (int i = 0; i < keys.Count; i++)
- if (keys [i] == name)
- return true;
- return false;
- }
- public void Clear ()
- {
- type = Type.NULL;
- if (list != null)
- list.Clear ();
- if (keys != null)
- keys.Clear ();
- str = "";
- n = 0;
- b = false;
- }
- /// <summary>
- /// Copy a JSONObject. This could probably work better
- /// </summary>
- /// <returns></returns>
- public JSONObject Copy ()
- {
- return Create (Print ());
- }
- /*
- * The Merge function is experimental. Use at your own risk.
- */
- public void Merge (JSONObject obj)
- {
- MergeRecur (this, obj);
- }
- /// <summary>
- /// Merge object right into left recursively
- /// </summary>
- /// <param name="left">The left (base) object</param>
- /// <param name="right">The right (new) object</param>
- static void MergeRecur (JSONObject left, JSONObject right)
- {
- if (left.type == Type.NULL)
- left.Absorb (right);
- else if (left.type == Type.OBJECT && right.type == Type.OBJECT) {
- for (int i = 0; i < right.list.Count; i++) {
- string key = right.keys [i];
- if (right [i].isContainer) {
- if (left.HasField (key))
- MergeRecur (left [key], right [i]);
- else
- left.AddField (key, right [i]);
- } else {
- if (left.HasField (key))
- left.SetField (key, right [i]);
- else
- left.AddField (key, right [i]);
- }
- }
- } else if (left.type == Type.ARRAY && right.type == Type.ARRAY) {
- if (right.Count > left.Count) {
- Debug.LogError ("Cannot merge arrays when right object has more elements");
- return;
- }
- for (int i = 0; i < right.list.Count; i++) {
- if (left [i].type == right [i].type) { //Only overwrite with the same type
- if (left [i].isContainer)
- MergeRecur (left [i], right [i]);
- else {
- left [i] = right [i];
- }
- }
- }
- }
- }
- public void Bake ()
- {
- if (type != Type.BAKED) {
- str = Print ();
- type = Type.BAKED;
- }
- }
- public IEnumerable BakeAsync ()
- {
- if (type != Type.BAKED) {
- foreach (string s in PrintAsync()) {
- if (s == null)
- yield return s;
- else {
- str = s;
- }
- }
- type = Type.BAKED;
- }
- }
- #pragma warning disable 219
- public string Print (bool pretty = false)
- {
- StringBuilder builder = new StringBuilder ();
- Stringify (0, builder, pretty);
- return builder.ToString ();
- }
- public IEnumerable<string> PrintAsync (bool pretty = false)
- {
- StringBuilder builder = new StringBuilder ();
- printWatch.Reset ();
- printWatch.Start ();
- foreach (IEnumerable e in StringifyAsync(0, builder, pretty)) {
- yield return null;
- }
- yield return builder.ToString ();
- }
- #pragma warning restore 219
- #region STRINGIFY
- const float maxFrameTime = 0.008f;
- static readonly Stopwatch printWatch = new Stopwatch ();
- IEnumerable StringifyAsync (int depth, StringBuilder builder, bool pretty = false)
- { //Convert the JSONObject into a string
- //Profiler.BeginSample("JSONprint");
- if (depth++ > MAX_DEPTH) {
- Debug.Log ("reached max depth!");
- yield break;
- }
- if (printWatch.Elapsed.TotalSeconds > maxFrameTime) {
- printWatch.Reset ();
- yield return null;
- printWatch.Start ();
- }
- switch (type) {
- case Type.BAKED:
- builder.Append (str);
- break;
- case Type.STRING:
- builder.AppendFormat ("\"{0}\"", str);
- break;
- case Type.NUMBER:
- //#if USEFLOAT
- if (float.IsInfinity (f))
- builder.Append (INFINITY);
- else if (float.IsNegativeInfinity (f))
- builder.Append (NEGINFINITY);
- else if (float.IsNaN (f))
- builder.Append (NaN);
- //#else
- // if(double.IsInfinity(n))
- // builder.Append(INFINITY);
- // else if(double.IsNegativeInfinity(n))
- // builder.Append(NEGINFINITY);
- // else if(double.IsNaN(n))
- // builder.Append(NaN);
- //#endif
- else {
- builder.Append (isIntNumber ? n.ToString () : f.ToString ());
- }
- break;
- case Type.OBJECT:
- builder.Append ("{");
- if (list.Count > 0) {
- #if(PRETTY) //for a bit more readability, comment the define above to disable system-wide
- if (pretty)
- builder.Append ("\n");
- #endif
- for (int i = 0; i < list.Count; i++) {
- string key = keys [i];
- JSONObject obj = list [i];
- if (obj) {
- #if(PRETTY)
- if (pretty)
- for (int j = 0; j < depth; j++)
- builder.Append ("\t"); //for a bit more readability
- #endif
- builder.AppendFormat ("\"{0}\":", key);
- foreach (IEnumerable e in obj.StringifyAsync(depth, builder, pretty))
- yield return e;
- builder.Append (",");
- #if(PRETTY)
- if (pretty)
- builder.Append ("\n");
- #endif
- }
- }
- //#if(PRETTY)
- if (pretty)
- builder.Length -= 2;
- else
- //#endif
- builder.Length--;
- }
- #if(PRETTY)
- if (pretty && list.Count > 0) {
- builder.Append ("\n");
- for (int j = 0; j < depth - 1; j++)
- builder.Append ("\t"); //for a bit more readability
- }
- #endif
- builder.Append ("}");
- break;
- case Type.ARRAY:
- builder.Append ("[");
- if (list.Count > 0) {
- #if(PRETTY)
- if (pretty)
- builder.Append ("\n"); //for a bit more readability
- #endif
- for (int i = 0; i < list.Count; i++) {
- if (list [i]) {
- #if(PRETTY)
- if (pretty)
- for (int j = 0; j < depth; j++)
- builder.Append ("\t"); //for a bit more readability
- #endif
- foreach (IEnumerable e in list[i].StringifyAsync(depth, builder, pretty))
- yield return e;
- builder.Append (",");
- #if(PRETTY)
- if (pretty)
- builder.Append ("\n"); //for a bit more readability
- #endif
- }
- }
- //#if(PRETTY)
- if (pretty)
- builder.Length -= 2;
- else
- //#endif
- builder.Length--;
- }
- #if(PRETTY)
- if (pretty && list.Count > 0) {
- builder.Append ("\n");
- for (int j = 0; j < depth - 1; j++)
- builder.Append ("\t"); //for a bit more readability
- }
- #endif
- builder.Append ("]");
- break;
- case Type.BOOL:
- if (b)
- builder.Append ("true");
- else
- builder.Append ("false");
- break;
- case Type.NULL:
- builder.Append ("null");
- break;
- }
- //Profiler.EndSample();
- }
- //TODO: Refactor Stringify functions to share core logic
- /*
- * I know, I know, this is really bad form. It turns out that there is a
- * significant amount of garbage created when calling as a coroutine, so this
- * method is duplicated. Hopefully there won't be too many future changes, but
- * I would still like a more elegant way to optionaly yield
- */
- void Stringify (int depth, StringBuilder builder, bool pretty = false)
- { //Convert the JSONObject into a string
- //Profiler.BeginSample("JSONprint");
- if (depth++ > MAX_DEPTH) {
- Debug.Log ("reached max depth!");
- return;
- }
- switch (type) {
- case Type.BAKED:
- builder.Append (str);
- break;
- case Type.STRING:
- builder.AppendFormat ("\"{0}\"", str);
- break;
- case Type.NUMBER:
- case Type.LONG:
- //#if USEFLOAT
- if (float.IsInfinity (f))
- builder.Append (INFINITY);
- else if (float.IsNegativeInfinity (f))
- builder.Append (NEGINFINITY);
- else if (float.IsNaN (f))
- builder.Append (NaN);
- //#else
- // if(double.IsInfinity(n))
- // builder.Append(INFINITY);
- // else if(double.IsNegativeInfinity(n))
- // builder.Append(NEGINFINITY);
- // else if(double.IsNaN(n))
- // builder.Append(NaN);
- //#endif
- else
- builder.Append (isIntNumber ? n.ToString () : f.ToString ());
- break;
- case Type.OBJECT:
- builder.Append ("{");
- if (list.Count > 0) {
- #if(PRETTY) //for a bit more readability, comment the define above to disable system-wide
- if (pretty)
- builder.Append ("\n");
- #endif
- for (int i = 0; i < list.Count; i++) {
- string key = keys [i];
- JSONObject obj = list [i];
- if (obj) {
- #if(PRETTY)
- if (pretty)
- for (int j = 0; j < depth; j++)
- builder.Append ("\t"); //for a bit more readability
- #endif
- builder.AppendFormat ("\"{0}\":", key);
- obj.Stringify (depth, builder, pretty);
- builder.Append (",");
- #if(PRETTY)
- if (pretty)
- builder.Append ("\n");
- #endif
- }
- }
- //#if(PRETTY)
- if (pretty)
- builder.Length -= 2;
- else
- //#endif
- builder.Length--;
- }
- #if(PRETTY)
- if (pretty && list.Count > 0) {
- builder.Append ("\n");
- for (int j = 0; j < depth - 1; j++)
- builder.Append ("\t"); //for a bit more readability
- }
- #endif
- builder.Append ("}");
- break;
- case Type.ARRAY:
- builder.Append ("[");
- if (list.Count > 0) {
- #if(PRETTY)
- if (pretty)
- builder.Append ("\n"); //for a bit more readability
- #endif
- for (int i = 0; i < list.Count; i++) {
- if (list [i]) {
- #if(PRETTY)
- if (pretty)
- for (int j = 0; j < depth; j++)
- builder.Append ("\t"); //for a bit more readability
- #endif
- list [i].Stringify (depth, builder, pretty);
- builder.Append (",");
- #if(PRETTY)
- if (pretty)
- builder.Append ("\n"); //for a bit more readability
- #endif
- }
- }
- //#if(PRETTY)
- if (pretty)
- builder.Length -= 2;
- else
- //#endif
- builder.Length--;
- }
- #if(PRETTY)
- if (pretty && list.Count > 0) {
- builder.Append ("\n");
- for (int j = 0; j < depth - 1; j++)
- builder.Append ("\t"); //for a bit more readability
- }
- #endif
- builder.Append ("]");
- break;
- case Type.BOOL:
- if (b)
- builder.Append ("true");
- else
- builder.Append ("false");
- break;
- case Type.NULL:
- builder.Append ("null");
- break;
- }
- //Profiler.EndSample();
- }
- #endregion
- public static implicit operator WWWForm (JSONObject obj)
- {
- WWWForm form = new WWWForm ();
- for (int i = 0; i < obj.list.Count; i++) {
- string key = i + "";
- if (obj.type == Type.OBJECT)
- key = obj.keys [i];
- string val = obj.list [i].ToString ();
- if (obj.list [i].type == Type.STRING)
- val = val.Replace ("\"", "");
- form.AddField (key, val);
- }
- return form;
- }
- public JSONObject this [int index] {
- get {
- if (list.Count > index)
- return list [index];
- return null;
- }
- set {
- if (list.Count > index)
- list [index] = value;
- }
- }
- public JSONObject this [string index] {
- get {
- return GetField (index);
- }
- set {
- SetField (index, value);
- }
- }
- public override string ToString ()
- {
- return Print ();
- }
- public string ToString (bool pretty)
- {
- return Print (pretty);
- }
- public Dictionary<string, string> ToDictionary ()
- {
- if (type == Type.OBJECT) {
- Dictionary<string, string> result = new Dictionary<string, string> ();
- for (int i = 0; i < list.Count; i++) {
- JSONObject val = list [i];
- switch (val.type) {
- case Type.STRING:
- result.Add (keys [i], val.str);
- break;
- case Type.NUMBER:
- result.Add (keys [i], val.f + "");
- break;
- case Type.BOOL:
- result.Add (keys [i], val.b + "");
- break;
- default:
- Debug.LogWarning ("Omitting object: " + keys [i] + " in dictionary conversion");
- break;
- }
- }
- return result;
- }
- Debug.LogWarning ("Tried to turn non-Object JSONObject into a dictionary");
- return null;
- }
- public static implicit operator bool (JSONObject o)
- {
- return o != null;
- }
- public static JSONObject toJSONObject (object o)
- {
- IList asList;
- IDictionary asDict;
- string asStr;
- //Log.D ("Test,o:{0}", o);
- if (o == null) {
- return new JSONObject (Type.NULL);
- } else if ((asStr = o as string) != null) {
- return CreateStringObject (asStr);
- } else if (o is bool) {
- return new JSONObject ((bool)o);
- } else if ((asList = o as IList) != null) {
- //Log.D("a4,o:{0},asList{1}",o,asList);
- JSONObject jList = new JSONObject (Type.ARRAY);
- for (int i = 0; i < asList.Count; i++) {
- jList.Add (toJSONObject (asList [i]));
- }
- //Log.D("jList:{0}",jList);
- return jList;
- } else if ((asDict = o as IDictionary) != null) {
- JSONObject jDict = new JSONObject (Type.OBJECT);
- foreach (string key in asDict.Keys) {
- jDict.AddField (key, toJSONObject (asDict [key]));
- }
- return jDict;
- } else if (o is char) {
- return CreateStringObject (o.ToString ());
- } else if (o is float) {
- //Log.D("[ float ]v:{0}, type:{1}.", o, o.GetType());
- return new JSONObject ((float)o);
- } else if (o is int) {
- //Log.D("[ int ]v:{0}, type:{1}.", o, o.GetType());
- return new JSONObject ((int)o);
- } else if (o is long) {
- //Log.D("[ long ]v:{0}, float:{2}, type:{1}.", o, o.GetType(), (long)o);
- return new JSONObject ((long)o);
- }else if(o is double)
- {
- return new JSONObject((float)(double)o);
- }
- else {
- DebugHelper.LogError(string.Format("[ toJSONObject ]unsupported type:{0}.", o.GetType()));
- }
- return null;
- }
- #if POOLING
- static bool pool = true;
- public static void ClearPool() {
- pool = false;
- releaseQueue.Clear();
- pool = true;
- }
- ~JSONObject() {
- if(pool && releaseQueue.Count < MAX_POOL_SIZE) {
- type = Type.NULL;
- list = null;
- keys = null;
- str = "";
- n = 0;
- b = false;
- releaseQueue.Enqueue(this);
- }
- }
- #endif
- public float ParseF ()
- {
- return IsString ? float.Parse (str) : 0f;
- }
- public static Vector3 ParseVector3FromJson (JSONObject json)
- {
- try {
- return new Vector3 (float.Parse (json [0].str), float.Parse (json [1].str), float.Parse (json [2].str));
- } catch {
- return Vector3.zero;
- }
- }
- public static Vector3 ParseVector2FromJson (JSONObject json)
- {
- try {
- return new Vector2 (float.Parse (json [0].str), float.Parse (json [1].str));
- } catch {
- return Vector2.zero;
- }
- }
- public static float[] ParseFloatArrayFromJson (JSONObject json)
- {
- try {
- float[] result = new float[json.Count];
- for (int i = 0; i < result.Length; i++) {
- result [i] = float.Parse (json [i].str);
- }
- return result;
- } catch {
- return new float[0];
- }
- }
- }
|