|
|
Line 163: |
Line 163: |
| ---- | | ---- |
| | | |
− | =The JSONObject class= | + | =The Code= |
− | <syntaxhighlight lang="csharp">
| + | The code is now available on [https://github.com/mtschoen/JSONObject github]. |
− | #define PRETTY //Comment out when you no longer need to read JSON to disable pretty print system-wide
| + | |
− | #define USEFLOAT //Use floats for numbers instead of doubles (enable if you're getting too many significant digits in string output)
| + | |
− | | + | |
− | using UnityEngine;
| + | |
− | using System.Collections;
| + | |
− | using System.Collections.Generic;
| + | |
− | | + | |
− | /*
| + | |
− | * http://www.opensource.org/licenses/lgpl-2.1.php
| + | |
− | * JSONObject class v.1.4.1
| + | |
− | * for use with Unity
| + | |
− | * Copyright Matt Schoen 2010 - 2013
| + | |
− | */
| + | |
− | | + | |
− | public class JSONObject {
| + | |
− | const int MAX_DEPTH = 1000;
| + | |
− | const string INFINITY = "\"INFINITY\"";
| + | |
− | const string NEGINFINITY = "\"NEGINFINITY\"";
| + | |
− | const string NaN = "\"NaN\"";
| + | |
− | public static char[] WHITESPACE = new char[] { ' ', '\r', '\n', '\t' };
| + | |
− | public enum Type { NULL, STRING, NUMBER, OBJECT, ARRAY, BOOL }
| + | |
− | public bool isContainer { get { return (type == Type.ARRAY || type == Type.OBJECT); } }
| + | |
− | public JSONObject parent;
| + | |
− | public Type type = Type.NULL;
| + | |
− | public int Count {
| + | |
− | get {
| + | |
− | if(list == null)
| + | |
− | return -1;
| + | |
− | return list.Count;
| + | |
− | }
| + | |
− | }
| + | |
− | //TODO: Switch to list
| + | |
− | public List<JSONObject> list;
| + | |
− | public List<string> keys;
| + | |
− | public string str;
| + | |
− | #if USEFLOAT
| + | |
− | public float n;
| + | |
− | public float f {
| + | |
− | get {
| + | |
− | return n;
| + | |
− | }
| + | |
− | }
| + | |
− | #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 new JSONObject(JSONObject.Type.NULL); } } //an empty, null object
| + | |
− | public static JSONObject obj { get { return new JSONObject(JSONObject.Type.OBJECT); } } //an empty object
| + | |
− | public static JSONObject arr { get { return new JSONObject(JSONObject.Type.ARRAY); } } //an empty array
| + | |
− | | + | |
− | public JSONObject(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(float f) {
| + | |
− | type = Type.NUMBER;
| + | |
− | this.n = f;
| + | |
− | }
| + | |
− | public JSONObject(Dictionary<string, string> dic) {
| + | |
− | type = Type.OBJECT;
| + | |
− | keys = new List<string>();
| + | |
− | list = new List<JSONObject>();
| + | |
− | foreach(KeyValuePair<string, string> kvp in dic) {
| + | |
− | keys.Add(kvp.Key);
| + | |
− | list.Add(new JSONObject { type = Type.STRING, str = kvp.Value });
| + | |
− | }
| + | |
− | }
| + | |
− | public JSONObject(Dictionary<string, JSONObject> dic) {
| + | |
− | type = Type.OBJECT;
| + | |
− | keys = new List<string>();
| + | |
− | list = new List<JSONObject>();
| + | |
− | 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 new JSONObject { type = JSONObject.Type.STRING, str = val }; }
| + | |
− | public void Absorb(JSONObject obj) {
| + | |
− | list.AddRange(obj.list);
| + | |
− | keys.AddRange(obj.keys);
| + | |
− | str = obj.str;
| + | |
− | n = obj.n;
| + | |
− | b = obj.b;
| + | |
− | type = obj.type;
| + | |
− | }
| + | |
− | public JSONObject() { }
| + | |
− | #region PARSE
| + | |
− | public JSONObject(string str, bool strict = false) { //create a new JSONObject from a string (this will also create any children, and parse the whole string)
| + | |
− | if(str != null) {
| + | |
− | str = str.Trim(WHITESPACE);
| + | |
− | if(strict) {
| + | |
− | if(str[0] != '[' && str[0] != '{') {
| + | |
− | type = Type.NULL;
| + | |
− | Debug.LogWarning("Improper (strict) JSON formatting. First character must be [ or {");
| + | |
− | return;
| + | |
− | }
| + | |
− | }
| + | |
− | if(str.Length > 0) {
| + | |
− | if(string.Compare(str, "true", true) == 0) {
| + | |
− | type = Type.BOOL;
| + | |
− | b = true;
| + | |
− | } else if(string.Compare(str, "false", true) == 0) {
| + | |
− | type = Type.BOOL;
| + | |
− | b = false;
| + | |
− | } else if(string.Compare(str, "null", true) == 0) {
| + | |
− | type = Type.NULL;
| + | |
− | #if USEFLOAT
| + | |
− | } else if(str == INFINITY) {
| + | |
− | type = Type.NUMBER;
| + | |
− | n = float.PositiveInfinity;
| + | |
− | } else if(str == NEGINFINITY) {
| + | |
− | type = Type.NUMBER;
| + | |
− | n = float.NegativeInfinity;
| + | |
− | } else if(str == NaN) {
| + | |
− | type = Type.NUMBER;
| + | |
− | n = 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(str[0] == '"') {
| + | |
− | type = Type.STRING;
| + | |
− | this.str = str.Substring(1, str.Length - 2);
| + | |
− | } else {
| + | |
− | try {
| + | |
− | #if USEFLOAT
| + | |
− | n = System.Convert.ToSingle(str);
| + | |
− | #else
| + | |
− | n = System.Convert.ToDouble(str);
| + | |
− | #endif
| + | |
− | type = Type.NUMBER;
| + | |
− | } catch(System.FormatException) {
| + | |
− | int token_tmp = 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(str[offset]) {
| + | |
− | case '{':
| + | |
− | type = Type.OBJECT;
| + | |
− | keys = new List<string>();
| + | |
− | list = new List<JSONObject>();
| + | |
− | break;
| + | |
− | case '[':
| + | |
− | type = JSONObject.Type.ARRAY;
| + | |
− | list = new List<JSONObject>();
| + | |
− | break;
| + | |
− | default:
| + | |
− | type = Type.NULL;
| + | |
− | Debug.LogWarning("improper JSON formatting:" + str);
| + | |
− | return;
| + | |
− | }
| + | |
− | string propName = "";
| + | |
− | bool openQuote = false;
| + | |
− | bool inProp = false;
| + | |
− | int depth = 0;
| + | |
− | while(++offset < str.Length) {
| + | |
− | if(System.Array.IndexOf<char>(WHITESPACE, str[offset]) > -1)
| + | |
− | continue;
| + | |
− | if(str[offset] == '\"') {
| + | |
− | if(openQuote) {
| + | |
− | if(!inProp && depth == 0 && type == Type.OBJECT)
| + | |
− | propName = str.Substring(token_tmp + 1, offset - token_tmp - 1);
| + | |
− | openQuote = false;
| + | |
− | } else {
| + | |
− | if(depth == 0 && type == Type.OBJECT)
| + | |
− | token_tmp = offset;
| + | |
− | openQuote = true;
| + | |
− | }
| + | |
− | }
| + | |
− | if(openQuote)
| + | |
− | continue;
| + | |
− | if(type == Type.OBJECT && depth == 0) {
| + | |
− | if(str[offset] == ':') {
| + | |
− | token_tmp = offset + 1;
| + | |
− | inProp = true;
| + | |
− | }
| + | |
− | }
| + | |
− |
| + | |
− | if(str[offset] == '[' || str[offset] == '{') {
| + | |
− | depth++;
| + | |
− | } else if(str[offset] == ']' || str[offset] == '}') {
| + | |
− | depth--;
| + | |
− | }
| + | |
− | //if (encounter a ',' at top level) || a closing ]/}
| + | |
− | if((str[offset] == ',' && depth == 0) || depth < 0) {
| + | |
− | inProp = false;
| + | |
− | string inner = str.Substring(token_tmp, offset - token_tmp).Trim(WHITESPACE);
| + | |
− | if(inner.Length > 0) {
| + | |
− | if(type == Type.OBJECT)
| + | |
− | keys.Add(propName);
| + | |
− | list.Add(new JSONObject(inner));
| + | |
− | }
| + | |
− | token_tmp = offset + 1;
| + | |
− | }
| + | |
− | }
| + | |
− | }
| + | |
− | }
| + | |
− | } else type = Type.NULL;
| + | |
− | } else type = Type.NULL; //If the string is missing, this is a null
| + | |
− | }
| + | |
− | #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(new JSONObject(val)); }
| + | |
− | public void Add(float val) { Add(new JSONObject(val)); }
| + | |
− | public void Add(int val) { Add(new JSONObject(val)); }
| + | |
− | public void Add(string str) { Add(StringObject(str)); }
| + | |
− | public void Add(AddJSONConents content) { Add(new JSONObject(content)); }
| + | |
− | public void Add(JSONObject obj) {
| + | |
− | if(obj) { //Don't do anything if the object is null
| + | |
− | if(type != JSONObject.Type.ARRAY) {
| + | |
− | type = JSONObject.Type.ARRAY; //Congratulations, son, you're an ARRAY now
| + | |
− | if(list == null)
| + | |
− | list = new List<JSONObject>();
| + | |
− | }
| + | |
− | list.Add(obj);
| + | |
− | }
| + | |
− | }
| + | |
− | public void AddField(string name, bool val) { AddField(name, new JSONObject(val)); }
| + | |
− | public void AddField(string name, float val) { AddField(name, new JSONObject(val)); }
| + | |
− | public void AddField(string name, int val) { AddField(name, new JSONObject(val)); }
| + | |
− | public void AddField(string name, AddJSONConents content) { AddField(name, new JSONObject(content)); }
| + | |
− | public void AddField(string name, string val) { AddField(name, StringObject(val)); }
| + | |
− | public void AddField(string name, JSONObject obj) {
| + | |
− | if(obj) { //Don't do anything if the object is null
| + | |
− | if(type != JSONObject.Type.OBJECT) {
| + | |
− | 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 = JSONObject.Type.OBJECT; //Congratulations, son, you're an OBJECT now
| + | |
− | }
| + | |
− | keys.Add(name);
| + | |
− | list.Add(obj);
| + | |
− | }
| + | |
− | }
| + | |
− | public void SetField(string name, bool val) { SetField(name, new JSONObject(val)); }
| + | |
− | public void SetField(string name, float val) { SetField(name, new JSONObject(val)); }
| + | |
− | public void SetField(string name, int val) { SetField(name, new JSONObject(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 bool GetField(ref bool field, string name, bool fallback) {
| + | |
− | if (GetField(ref field, name)) { return true; }
| + | |
− | field = fallback;
| + | |
− | return false;
| + | |
− | }
| + | |
− | public bool 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 true;
| + | |
− | }
| + | |
− | }
| + | |
− | if(fail != null) fail.Invoke(name);
| + | |
− | return false;
| + | |
− | }
| + | |
− | #if USEFLOAT
| + | |
− | public bool GetField(ref float field, string name, float fallback) {
| + | |
− | #else
| + | |
− | public bool GetField(ref double field, string name, double fallback) {
| + | |
− | #endif
| + | |
− | if (GetField(ref field, name)) { return true; }
| + | |
− | field = fallback;
| + | |
− | return false;
| + | |
− | }
| + | |
− | #if USEFLOAT
| + | |
− | public bool GetField(ref float field, string name, FieldNotFound fail = null) {
| + | |
− | #else
| + | |
− | public bool 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].n;
| + | |
− | return true;
| + | |
− | }
| + | |
− | }
| + | |
− | if(fail != null) fail.Invoke(name);
| + | |
− | return false;
| + | |
− | }
| + | |
− | public bool GetField(ref int field, string name, int fallback) {
| + | |
− | if (GetField(ref field, name)) { return true; }
| + | |
− | field = fallback;
| + | |
− | return false;
| + | |
− | }
| + | |
− | public bool GetField(ref int field, string name, FieldNotFound fail = null) {
| + | |
− | if(type == JSONObject.Type.OBJECT) {
| + | |
− | int index = keys.IndexOf(name);
| + | |
− | if(index >= 0) {
| + | |
− | field = (int)list[index].n;
| + | |
− | return true;
| + | |
− | }
| + | |
− | }
| + | |
− | if(fail != null) fail.Invoke(name);
| + | |
− | return false;
| + | |
− | }
| + | |
− | public bool GetField(ref uint field, string name, uint fallback) {
| + | |
− | if (GetField(ref field, name)) { return true; }
| + | |
− | field = fallback;
| + | |
− | return false;
| + | |
− | }
| + | |
− | public bool GetField(ref uint field, string name, FieldNotFound fail = null) {
| + | |
− | if(type == JSONObject.Type.OBJECT) {
| + | |
− | int index = keys.IndexOf(name);
| + | |
− | if(index >= 0) {
| + | |
− | field = (uint)list[index].n;
| + | |
− | return true;
| + | |
− | }
| + | |
− | }
| + | |
− | if(fail != null) fail.Invoke(name);
| + | |
− | return false;
| + | |
− | }
| + | |
− | public bool GetField(ref string field, string name, string fallback) {
| + | |
− | if (GetField(ref field, name)) { return true; }
| + | |
− | field = fallback;
| + | |
− | return false;
| + | |
− | }
| + | |
− | public bool GetField(ref string field, string name, FieldNotFound fail = null) {
| + | |
− | if(type == JSONObject.Type.OBJECT) {
| + | |
− | int index = keys.IndexOf(name);
| + | |
− | if(index >= 0) {
| + | |
− | field = list[index].str;
| + | |
− | return true;
| + | |
− | }
| + | |
− | }
| + | |
− | if(fail != null) fail.Invoke(name);
| + | |
− | return false;
| + | |
− | }
| + | |
− | 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 == JSONObject.Type.OBJECT)
| + | |
− | for(int i = 0; i < keys.Count; i++)
| + | |
− | if((string)keys[i] == name)
| + | |
− | return (JSONObject)list[i];
| + | |
− | return null;
| + | |
− | }
| + | |
− | public bool HasFields(string[] names) {
| + | |
− | foreach(string name in names)
| + | |
− | if(!keys.Contains(name))
| + | |
− | return false;
| + | |
− | return true;
| + | |
− | }
| + | |
− | public bool HasField(string name) {
| + | |
− | if(type == JSONObject.Type.OBJECT)
| + | |
− | for(int i = 0; i < keys.Count; i++)
| + | |
− | if((string)keys[i] == name)
| + | |
− | return true;
| + | |
− | return false;
| + | |
− | }
| + | |
− | public void Clear() {
| + | |
− | type = JSONObject.Type.NULL;
| + | |
− | if(list != null)
| + | |
− | list.Clear();
| + | |
− | if (keys != null)
| + | |
− | keys.Clear();
| + | |
− | str = "";
| + | |
− | n = 0;
| + | |
− | b = false;
| + | |
− | }
| + | |
− | public JSONObject Copy() {
| + | |
− | return new JSONObject(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 == JSONObject.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 = (string)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 string print(bool pretty = false) {
| + | |
− | return print(0, pretty);
| + | |
− | }
| + | |
− | #region STRINGIFY
| + | |
− | public string print(int depth, bool pretty = false) { //Convert the JSONObject into a string
| + | |
− | if(depth++ > MAX_DEPTH) {
| + | |
− | Debug.Log("reached max depth!");
| + | |
− | return "";
| + | |
− | }
| + | |
− | string str = "";
| + | |
− | switch(type) {
| + | |
− | case Type.STRING:
| + | |
− | str = "\"" + this.str + "\"";
| + | |
− | break;
| + | |
− | case Type.NUMBER:
| + | |
− | #if USEFLOAT
| + | |
− | if(float.IsInfinity(n))
| + | |
− | str = INFINITY;
| + | |
− | else if(float.IsNegativeInfinity(n))
| + | |
− | str = NEGINFINITY;
| + | |
− | else if(float.IsNaN(n))
| + | |
− | str = NaN;
| + | |
− | #else
| + | |
− | if(double.IsInfinity(n))
| + | |
− | str = INFINITY;
| + | |
− | else if(double.IsNegativeInfinity(n))
| + | |
− | str = NEGINFINITY;
| + | |
− | else if(double.IsNaN(n))
| + | |
− | str = NaN;
| + | |
− | #endif
| + | |
− | else
| + | |
− | str += n;
| + | |
− | break;
| + | |
− | | + | |
− | case JSONObject.Type.OBJECT:
| + | |
− | str = "{";
| + | |
− | if(list.Count > 0) {
| + | |
− | #if(PRETTY) //for a bit more readability, comment the define above to disable system-wide
| + | |
− | if(pretty)
| + | |
− | str += "\n";
| + | |
− | #endif
| + | |
− | for(int i = 0; i < list.Count; i++) {
| + | |
− | string key = (string)keys[i];
| + | |
− | JSONObject obj = (JSONObject)list[i];
| + | |
− | if(obj) {
| + | |
− | #if(PRETTY)
| + | |
− | if(pretty)
| + | |
− | for(int j = 0; j < depth; j++)
| + | |
− | str += "\t"; //for a bit more readability
| + | |
− | #endif
| + | |
− | str += "\"" + key + "\":";
| + | |
− | str += obj.print(depth, pretty) + ",";
| + | |
− | #if(PRETTY)
| + | |
− | if(pretty)
| + | |
− | str += "\n";
| + | |
− | #endif
| + | |
− | }
| + | |
− | }
| + | |
− | #if(PRETTY)
| + | |
− | if(pretty)
| + | |
− | str = str.Substring(0, str.Length - 1); //BOP: This line shows up twice on purpose: once to remove the \n if readable is true and once to remove the comma
| + | |
− | #endif
| + | |
− | str = str.Substring(0, str.Length - 1);
| + | |
− | }
| + | |
− | #if(PRETTY)
| + | |
− | if(pretty && list.Count > 0) {
| + | |
− | str += "\n";
| + | |
− | for(int j = 0; j < depth - 1; j++)
| + | |
− | str += "\t"; //for a bit more readability
| + | |
− | }
| + | |
− | #endif
| + | |
− | str += "}";
| + | |
− | break;
| + | |
− | case JSONObject.Type.ARRAY:
| + | |
− | str = "[";
| + | |
− | if(list.Count > 0) {
| + | |
− | #if(PRETTY)
| + | |
− | if(pretty)
| + | |
− | str += "\n"; //for a bit more readability
| + | |
− | #endif
| + | |
− | foreach(JSONObject obj in list) {
| + | |
− | if(obj) {
| + | |
− | #if(PRETTY)
| + | |
− | if(pretty)
| + | |
− | for(int j = 0; j < depth; j++)
| + | |
− | str += "\t"; //for a bit more readability
| + | |
− | #endif
| + | |
− | str += obj.print(depth, pretty) + ",";
| + | |
− | #if(PRETTY)
| + | |
− | if(pretty)
| + | |
− | str += "\n"; //for a bit more readability
| + | |
− | #endif
| + | |
− | }
| + | |
− | }
| + | |
− | #if(PRETTY)
| + | |
− | if(pretty)
| + | |
− | str = str.Substring(0, str.Length - 1); //BOP: This line shows up twice on purpose: once to remove the \n if readable is true and once to remove the comma
| + | |
− | #endif
| + | |
− | str = str.Substring(0, str.Length - 1);
| + | |
− | }
| + | |
− | #if(PRETTY)
| + | |
− | if(pretty && list.Count > 0) {
| + | |
− | str += "\n";
| + | |
− | for(int j = 0; j < depth - 1; j++)
| + | |
− | str += "\t"; //for a bit more readability
| + | |
− | }
| + | |
− | #endif
| + | |
− | str += "]";
| + | |
− | break;
| + | |
− | case Type.BOOL:
| + | |
− | if(b)
| + | |
− | str = "true";
| + | |
− | else
| + | |
− | str = "false";
| + | |
− | break;
| + | |
− | case Type.NULL:
| + | |
− | str = "null";
| + | |
− | break;
| + | |
− | }
| + | |
− | return str;
| + | |
− | }
| + | |
− | #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 (JSONObject)list[index];
| + | |
− | else 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 = (JSONObject)list[i];
| + | |
− | switch(val.type) {
| + | |
− | case Type.STRING: result.Add((string)keys[i], val.str); break;
| + | |
− | case Type.NUMBER: result.Add((string)keys[i], val.n + ""); break;
| + | |
− | case Type.BOOL: result.Add((string)keys[i], val.b + ""); break;
| + | |
− | default: Debug.LogWarning("Omitting object: " + (string)keys[i] + " in dictionary conversion"); break;
| + | |
− | }
| + | |
− | }
| + | |
− | return result;
| + | |
− | } else Debug.LogWarning("Tried to turn non-Object JSONObject into a dictionary");
| + | |
− | return null;
| + | |
− | }
| + | |
− | public static implicit operator bool(JSONObject o) {
| + | |
− | return (object)o != null;
| + | |
− | }
| + | |
− | }
| + | |
− | </syntaxhighlight>
| + | |
− | | + | |
− | =The JSONChecker Window=
| + | |
− | <syntaxhighlight lang="csharp">
| + | |
− | //#define PERFTEST //For testing performance of parse/stringify. Turn on editor profiling to see how we're doing | + | |
− | | + | |
− | using UnityEngine;
| + | |
− | using UnityEditor;
| + | |
− | | + | |
− | public class JSONChecker : EditorWindow {
| + | |
− | string JSON = @"{
| + | |
− | ""TestObject"": {
| + | |
− | ""SomeText"": ""Blah"",
| + | |
− | ""SomeObject"": {
| + | |
− | ""SomeNumber"": 42,
| + | |
− | ""SomeBool"": true,
| + | |
− | ""SomeNull"": null
| + | |
− | },
| + | |
− |
| + | |
− | ""SomeEmptyObject"": { },
| + | |
− | ""SomeEmptyArray"": [ ],
| + | |
− | ""EmbeddedObject"": ""{\""field\"":\""Value with \\\""escaped quotes\\\""\""}""
| + | |
− | }
| + | |
− | }"; //dat string literal...
| + | |
− | JSONObject j;
| + | |
− | [MenuItem("Window/JSONChecker")]
| + | |
− | static void Init() {
| + | |
− | GetWindow(typeof(JSONChecker));
| + | |
− | }
| + | |
− | void OnGUI() {
| + | |
− | JSON = EditorGUILayout.TextArea(JSON);
| + | |
− | GUI.enabled = !string.IsNullOrEmpty(JSON);
| + | |
− | if(GUILayout.Button("Check JSON")) {
| + | |
− | #if PERFTEST
| + | |
− | Profiler.BeginSample("JSONParse");
| + | |
− | j = JSONObject.Create(JSON);
| + | |
− | Profiler.EndSample();
| + | |
− | Profiler.BeginSample("JSONStringify");
| + | |
− | j.ToString(true);
| + | |
− | Profiler.EndSample();
| + | |
− | #else
| + | |
− | j = JSONObject.Create(JSON);
| + | |
− | #endif
| + | |
− | Debug.Log(j.ToString(true));
| + | |
− | }
| + | |
− | if(j) {
| + | |
− | //Debug.Log(System.GC.GetTotalMemory(false) + "");
| + | |
− | if(j.type == JSONObject.Type.NULL)
| + | |
− | GUILayout.Label("JSON fail:\n" + j.ToString(true));
| + | |
− | else
| + | |
− | GUILayout.Label("JSON success:\n" + j.ToString(true));
| + | |
− | | + | |
− | }
| + | |
− | }
| + | |
− | }
| + | |
− | </syntaxhighlight>
| + | |
− | | + | |
− | =JSONTemplates Classes=
| + | |
− | <syntaxhighlight lang="csharp">
| + | |
− | using UnityEngine;
| + | |
− | using System.Collections.Generic;
| + | |
− | using System.Reflection;
| + | |
− | | + | |
− | /*
| + | |
− | * http://www.opensource.org/licenses/lgpl-2.1.php
| + | |
− | * JSONTemplates class
| + | |
− | * for use with Unity
| + | |
− | * Copyright Matt Schoen 2010
| + | |
− | */
| + | |
− | | + | |
− | public static partial class JSONTemplates {
| + | |
− | static readonly HashSet<object> touched = new HashSet<object>();
| + | |
− | | + | |
− | public static JSONObject TOJSON(object obj) { //For a generic guess
| + | |
− | if(touched.Add(obj)) {
| + | |
− | JSONObject result = JSONObject.obj;
| + | |
− | //Fields
| + | |
− | FieldInfo[] fieldinfo = obj.GetType().GetFields();
| + | |
− | foreach(FieldInfo fi in fieldinfo) {
| + | |
− | JSONObject val = JSONObject.nullJO;
| + | |
− | if(!fi.GetValue(obj).Equals(null)) {
| + | |
− | MethodInfo info = typeof(JSONTemplates).GetMethod("From" + fi.FieldType.Name);
| + | |
− | if(info != null) {
| + | |
− | object[] parms = new object[1];
| + | |
− | parms[0] = fi.GetValue(obj);
| + | |
− | val = (JSONObject)info.Invoke(null, parms);
| + | |
− | } else if(fi.FieldType == typeof(string))
| + | |
− | val = JSONObject.CreateStringObject(fi.GetValue(obj).ToString());
| + | |
− | else
| + | |
− | val = JSONObject.Create(fi.GetValue(obj).ToString());
| + | |
− | }
| + | |
− | if(val) {
| + | |
− | if(val.type != JSONObject.Type.NULL)
| + | |
− | result.AddField(fi.Name, val);
| + | |
− | else Debug.LogWarning("Null for this non-null object, property " + fi.Name + " of class " + obj.GetType().Name + ". Object type is " + fi.FieldType.Name);
| + | |
− | }
| + | |
− | }
| + | |
− | //Properties
| + | |
− | PropertyInfo[] propertyInfo = obj.GetType().GetProperties();
| + | |
− | foreach(PropertyInfo pi in propertyInfo) {
| + | |
− | //This section should mirror part of AssetFactory.AddScripts()
| + | |
− | JSONObject val = JSONObject.nullJO;
| + | |
− | if(!pi.GetValue(obj, null).Equals(null)) {
| + | |
− | MethodInfo info = typeof(JSONTemplates).GetMethod("From" + pi.PropertyType.Name);
| + | |
− | if(info != null) {
| + | |
− | object[] parms = new object[1];
| + | |
− | parms[0] = pi.GetValue(obj, null);
| + | |
− | val = (JSONObject)info.Invoke(null, parms);
| + | |
− | } else if(pi.PropertyType == typeof(string))
| + | |
− | val = JSONObject.CreateStringObject(pi.GetValue(obj, null).ToString());
| + | |
− | else
| + | |
− | val = JSONObject.Create(pi.GetValue(obj, null).ToString());
| + | |
− | }
| + | |
− | if(val) {
| + | |
− | if(val.type != JSONObject.Type.NULL)
| + | |
− | result.AddField(pi.Name, val);
| + | |
− | else Debug.LogWarning("Null for this non-null object, property " + pi.Name + " of class " + obj.GetType().Name + ". Object type is " + pi.PropertyType.Name);
| + | |
− | }
| + | |
− | }
| + | |
− | return result;
| + | |
− | }
| + | |
− | Debug.LogWarning("trying to save the same data twice");
| + | |
− | return JSONObject.nullJO;
| + | |
− | }
| + | |
− | }
| + | |
− | | + | |
− | /*
| + | |
− | * Some helpful code templates for the JSON class
| + | |
− | *
| + | |
− | * LOOP THROUGH OBJECT
| + | |
− | for(int i = 0; i < obj.Count; i++){
| + | |
− | if(obj.keys[i] != null){
| + | |
− | switch((string)obj.keys[i]){
| + | |
− | case "key1":
| + | |
− | do stuff with (JSONObject)obj.list[i];
| + | |
− | break;
| + | |
− | case "key2":
| + | |
− | do stuff with (JSONObject)obj.list[i];
| + | |
− | break;
| + | |
− | }
| + | |
− | }
| + | |
− | }
| + | |
− | *
| + | |
− | * LOOP THROUGH ARRAY
| + | |
− | foreach(JSONObject ob in obj.list)
| + | |
− | do stuff with ob;
| + | |
− | */
| + | |
− | | + | |
− | using UnityEngine;
| + | |
− | | + | |
− | public static partial class JSONTemplates {
| + | |
− | | + | |
− | /*
| + | |
− | * Vector2
| + | |
− | */
| + | |
− | public static Vector2 ToVector2(JSONObject obj) {
| + | |
− | float x = obj["x"] ? obj["x"].f : 0;
| + | |
− | float y = obj["y"] ? obj["y"].f : 0;
| + | |
− | return new Vector2(x, y);
| + | |
− | }
| + | |
− | public static JSONObject FromVector2(Vector2 v) {
| + | |
− | JSONObject vdata = JSONObject.obj;
| + | |
− | if(v.x != 0) vdata.AddField("x", v.x);
| + | |
− | if(v.y != 0) vdata.AddField("y", v.y);
| + | |
− | return vdata;
| + | |
− | }
| + | |
− | /*
| + | |
− | * Vector3
| + | |
− | */
| + | |
− | public static JSONObject FromVector3(Vector3 v) {
| + | |
− | JSONObject vdata = JSONObject.obj;
| + | |
− | if(v.x != 0) vdata.AddField("x", v.x);
| + | |
− | if(v.y != 0) vdata.AddField("y", v.y);
| + | |
− | if(v.z != 0) vdata.AddField("z", v.z);
| + | |
− | return vdata;
| + | |
− | }
| + | |
− | public static Vector3 ToVector3(JSONObject obj) {
| + | |
− | float x = obj["x"] ? obj["x"].f : 0;
| + | |
− | float y = obj["y"] ? obj["y"].f : 0;
| + | |
− | float z = obj["z"] ? obj["z"].f : 0;
| + | |
− | return new Vector3(x, y, z);
| + | |
− | }
| + | |
− | /*
| + | |
− | * Vector4
| + | |
− | */
| + | |
− | public static JSONObject FromVector4(Vector4 v) {
| + | |
− | JSONObject vdata = JSONObject.obj;
| + | |
− | if(v.x != 0) vdata.AddField("x", v.x);
| + | |
− | if(v.y != 0) vdata.AddField("y", v.y);
| + | |
− | if(v.z != 0) vdata.AddField("z", v.z);
| + | |
− | if(v.w != 0) vdata.AddField("w", v.w);
| + | |
− | return vdata;
| + | |
− | }
| + | |
− | public static Vector4 ToVector4(JSONObject obj) {
| + | |
− | float x = obj["x"] ? obj["x"].f : 0;
| + | |
− | float y = obj["y"] ? obj["y"].f : 0;
| + | |
− | float z = obj["z"] ? obj["z"].f : 0;
| + | |
− | float w = obj["w"] ? obj["w"].f : 0;
| + | |
− | return new Vector4(x, y, z, w);
| + | |
− | }
| + | |
− | /*
| + | |
− | * Matrix4x4
| + | |
− | */
| + | |
− | public static JSONObject FromMatrix4x4(Matrix4x4 m) {
| + | |
− | JSONObject mdata = JSONObject.obj;
| + | |
− | if(m.m00 != 0) mdata.AddField("m00", m.m00);
| + | |
− | if(m.m01 != 0) mdata.AddField("m01", m.m01);
| + | |
− | if(m.m02 != 0) mdata.AddField("m02", m.m02);
| + | |
− | if(m.m03 != 0) mdata.AddField("m03", m.m03);
| + | |
− | if(m.m10 != 0) mdata.AddField("m10", m.m10);
| + | |
− | if(m.m11 != 0) mdata.AddField("m11", m.m11);
| + | |
− | if(m.m12 != 0) mdata.AddField("m12", m.m12);
| + | |
− | if(m.m13 != 0) mdata.AddField("m13", m.m13);
| + | |
− | if(m.m20 != 0) mdata.AddField("m20", m.m20);
| + | |
− | if(m.m21 != 0) mdata.AddField("m21", m.m21);
| + | |
− | if(m.m22 != 0) mdata.AddField("m22", m.m22);
| + | |
− | if(m.m23 != 0) mdata.AddField("m23", m.m23);
| + | |
− | if(m.m30 != 0) mdata.AddField("m30", m.m30);
| + | |
− | if(m.m31 != 0) mdata.AddField("m31", m.m31);
| + | |
− | if(m.m32 != 0) mdata.AddField("m32", m.m32);
| + | |
− | if(m.m33 != 0) mdata.AddField("m33", m.m33);
| + | |
− | return mdata;
| + | |
− | }
| + | |
− | public static Matrix4x4 ToMatrix4x4(JSONObject obj) {
| + | |
− | Matrix4x4 result = new Matrix4x4();
| + | |
− | if(obj["m00"]) result.m00 = obj["m00"].f;
| + | |
− | if(obj["m01"]) result.m01 = obj["m01"].f;
| + | |
− | if(obj["m02"]) result.m02 = obj["m02"].f;
| + | |
− | if(obj["m03"]) result.m03 = obj["m03"].f;
| + | |
− | if(obj["m10"]) result.m10 = obj["m10"].f;
| + | |
− | if(obj["m11"]) result.m11 = obj["m11"].f;
| + | |
− | if(obj["m12"]) result.m12 = obj["m12"].f;
| + | |
− | if(obj["m13"]) result.m13 = obj["m13"].f;
| + | |
− | if(obj["m20"]) result.m20 = obj["m20"].f;
| + | |
− | if(obj["m21"]) result.m21 = obj["m21"].f;
| + | |
− | if(obj["m22"]) result.m22 = obj["m22"].f;
| + | |
− | if(obj["m23"]) result.m23 = obj["m23"].f;
| + | |
− | if(obj["m30"]) result.m30 = obj["m30"].f;
| + | |
− | if(obj["m31"]) result.m31 = obj["m31"].f;
| + | |
− | if(obj["m32"]) result.m32 = obj["m32"].f;
| + | |
− | if(obj["m33"]) result.m33 = obj["m33"].f;
| + | |
− | return result;
| + | |
− | }
| + | |
− | /*
| + | |
− | * Quaternion
| + | |
− | */
| + | |
− | public static JSONObject FromQuaternion(Quaternion q) {
| + | |
− | JSONObject qdata = JSONObject.obj;
| + | |
− | if(q.w != 0) qdata.AddField("w", q.w);
| + | |
− | if(q.x != 0) qdata.AddField("x", q.x);
| + | |
− | if(q.y != 0) qdata.AddField("y", q.y);
| + | |
− | if(q.z != 0) qdata.AddField("z", q.z);
| + | |
− | return qdata;
| + | |
− | }
| + | |
− | public static Quaternion ToQuaternion(JSONObject obj) {
| + | |
− | float x = obj["x"] ? obj["x"].f : 0;
| + | |
− | float y = obj["y"] ? obj["y"].f : 0;
| + | |
− | float z = obj["z"] ? obj["z"].f : 0;
| + | |
− | float w = obj["w"] ? obj["w"].f : 0;
| + | |
− | return new Quaternion(x, y, z, w);
| + | |
− | }
| + | |
− | /*
| + | |
− | * Color
| + | |
− | */
| + | |
− | public static JSONObject FromColor(Color c) {
| + | |
− | JSONObject cdata = JSONObject.obj;
| + | |
− | if(c.r != 0) cdata.AddField("r", c.r);
| + | |
− | if(c.g != 0) cdata.AddField("g", c.g);
| + | |
− | if(c.b != 0) cdata.AddField("b", c.b);
| + | |
− | if(c.a != 0) cdata.AddField("a", c.a);
| + | |
− | return cdata;
| + | |
− | }
| + | |
− | public static Color ToColor(JSONObject obj) {
| + | |
− | Color c = new Color();
| + | |
− | for(int i = 0; i < obj.Count; i++) {
| + | |
− | switch(obj.keys[i]) {
| + | |
− | case "r": c.r = obj[i].f; break;
| + | |
− | case "g": c.g = obj[i].f; break;
| + | |
− | case "b": c.b = obj[i].f; break;
| + | |
− | case "a": c.a = obj[i].f; break;
| + | |
− | }
| + | |
− | }
| + | |
− | return c;
| + | |
− | }
| + | |
− | /*
| + | |
− | * Layer Mask
| + | |
− | */
| + | |
− | public static JSONObject FromLayerMask(LayerMask l) {
| + | |
− | JSONObject result = JSONObject.obj;
| + | |
− | result.AddField("value", l.value);
| + | |
− | return result;
| + | |
− | }
| + | |
− | public static LayerMask ToLayerMask(JSONObject obj) {
| + | |
− | LayerMask l = new LayerMask {value = (int)obj["value"].n};
| + | |
− | return l;
| + | |
− | }
| + | |
− | public static JSONObject FromRect(Rect r) {
| + | |
− | JSONObject result = JSONObject.obj;
| + | |
− | if(r.x != 0) result.AddField("x", r.x);
| + | |
− | if(r.y != 0) result.AddField("y", r.y);
| + | |
− | if(r.height != 0) result.AddField("height", r.height);
| + | |
− | if(r.width != 0) result.AddField("width", r.width);
| + | |
− | return result;
| + | |
− | }
| + | |
− | public static Rect ToRect(JSONObject obj) {
| + | |
− | Rect r = new Rect();
| + | |
− | for(int i = 0; i < obj.Count; i++) {
| + | |
− | switch(obj.keys[i]) {
| + | |
− | case "x": r.x = obj[i].f; break;
| + | |
− | case "y": r.y = obj[i].f; break;
| + | |
− | case "height": r.height = obj[i].f; break;
| + | |
− | case "width": r.width = obj[i].f; break;
| + | |
− | }
| + | |
− | }
| + | |
− | return r;
| + | |
− | }
| + | |
− | public static JSONObject FromRectOffset(RectOffset r) {
| + | |
− | JSONObject result = JSONObject.obj;
| + | |
− | if(r.bottom != 0) result.AddField("bottom", r.bottom);
| + | |
− | if(r.left != 0) result.AddField("left", r.left);
| + | |
− | if(r.right != 0) result.AddField("right", r.right);
| + | |
− | if(r.top != 0) result.AddField("top", r.top);
| + | |
− | return result;
| + | |
− | }
| + | |
− | public static RectOffset ToRectOffset(JSONObject obj) {
| + | |
− | RectOffset r = new RectOffset();
| + | |
− | for(int i = 0; i < obj.Count; i++) {
| + | |
− | switch(obj.keys[i]) {
| + | |
− | case "bottom": r.bottom = (int)obj[i].n; break;
| + | |
− | case "left": r.left = (int)obj[i].n; break;
| + | |
− | case "right": r.right = (int)obj[i].n; break;
| + | |
− | case "top": r.top = (int)obj[i].n; break;
| + | |
− | }
| + | |
− | }
| + | |
− | return r;
| + | |
− | }
| + | |
− |
| + | |
− | public static AnimationCurve ToAnimationCurve(JSONObject obj){
| + | |
− | AnimationCurve a = new AnimationCurve();
| + | |
− | if(obj.HasField("keys")){
| + | |
− | JSONObject keys = obj.GetField("keys");
| + | |
− | for(int i =0; i < keys.list.Count;i++){
| + | |
− | a.AddKey(ToKeyframe(keys[i]));
| + | |
− | }
| + | |
− | }
| + | |
− | if(obj.HasField("preWrapMode"))
| + | |
− | a.preWrapMode = (WrapMode)((int)obj.GetField("preWrapMode").n);
| + | |
− | if(obj.HasField("postWrapMode"))
| + | |
− | a.postWrapMode = (WrapMode)((int)obj.GetField("postWrapMode").n);
| + | |
− | return a;
| + | |
− | }
| + | |
− |
| + | |
− | public static JSONObject FromAnimationCurve(AnimationCurve a){
| + | |
− | JSONObject result = JSONObject.obj;
| + | |
− | result.AddField("preWrapMode", a.preWrapMode.ToString());
| + | |
− | result.AddField("postWrapMode", a.postWrapMode.ToString());
| + | |
− | if(a.keys.Length > 0){
| + | |
− | JSONObject keysJSON = JSONObject.Create();
| + | |
− | for(int i =0; i < a.keys.Length;i++){
| + | |
− | keysJSON.Add(FromKeyframe(a.keys[i]));
| + | |
− | }
| + | |
− | result.AddField("keys", keysJSON);
| + | |
− | }
| + | |
− | return result;
| + | |
− | }
| + | |
− |
| + | |
− | public static Keyframe ToKeyframe(JSONObject obj){
| + | |
− | Keyframe k = new Keyframe(obj.HasField("time")? obj.GetField("time").n : 0, obj.HasField("value")? obj.GetField("value").n : 0);
| + | |
− | if(obj.HasField("inTangent")) k.inTangent = obj.GetField("inTangent").n;
| + | |
− | if(obj.HasField("outTangent")) k.outTangent = obj.GetField("outTangent").n;
| + | |
− | if(obj.HasField("tangentMode")) k.tangentMode = (int)obj.GetField("tangentMode").n;
| + | |
− |
| + | |
− | return k;
| + | |
− | }
| + | |
− | public static JSONObject FromKeyframe(Keyframe k){
| + | |
− | JSONObject result = JSONObject.obj;
| + | |
− | if(k.inTangent != 0) result.AddField("inTangent", k.inTangent);
| + | |
− | if(k.outTangent != 0) result.AddField("outTangent", k.outTangent);
| + | |
− | if(k.tangentMode != 0) result.AddField("tangentMode", k.tangentMode);
| + | |
− | if(k.time != 0) result.AddField("time", k.time);
| + | |
− | if(k.value != 0) result.AddField("value", k.value);
| + | |
− | return result;
| + | |
− | }
| + | |
− |
| + | |
− | }
| + | |
− | | + | |
− | </syntaxhighlight>
| + | |
| | | |
| =Change Log= | | =Change Log= |
I came across the need to send structured data to and from a server on one of my projects, and figured it would be worth my while to use JSON. When I looked into the issue, I tried a few of the C# implementations listed on json.org, but found them to be too complicated to work with and expand upon. So, I've written a very simple JSONObject class, which can be generically used to encode/decode data into a simple container. This page assumes that you know what JSON is, and how it works. It's rather simple, just go to json.org for a visual description of the encoding format.
Update: The code has been updated to version 1.4 to incorporate user-submitted patches and bug reports. This fixes issues dealing with whitespace in the format, as well as empty arrays and objects, and escaped quotes within strings.
Users should not have to modify the JSONObject class themselves, and must follow the very simple proceedures outlined below:
It should be pretty obvious what this parser can and cannot do. If anyone reading this is a JSON buff (is there such a thing?) please feel free to expand and modify the parser to be more compliant. Currently I am using the .NET System.Convert namespace functions for parsing the data itself. It parses strings and numbers, which was all that I needed of it, but unless the formatting is supported by System.Convert, it may not incorporate all proper JSON strings. Also, having never written a JSON parser before, I don't doubt that I could improve the efficiency or correctness of the parser. It serves my purpose, and hopefully will help you with your project! Let me know if you make any improvements :)
Also, you JSON buffs (really, who would admit to being a JSON buff...) might also notice from my feature list that this thing isn't exactly to specifications. Here is where it differs:
Encoding is something of a hard-coded process. This is because I have no idea what your data is! It would be great if this were some sort of interface for taking an entire class and encoding it's number/string fields, but it's not. I've come up with a few clever ways of using loops and/or recursive methods to cut down of the amount of code I have to write when I use this tool, but they're pretty project-specific.
Note: This section used to be WRONG! And now it's OLD! Will update later... this will all still work, but there are now a couple of ways to skin this cat.
NEW! The constructor, Add, and AddField functions now support a nested delegate structure. This is useful if you need to create a nested JSONObject in a single line. For example:
Decoding is much simpler on the input end, and again, what you do with the JSONObject will vary on a per-project basis. One of the more complicated way to extract the data is with a recursive function, as drafted below. Calling the constructor with a properly formatted JSON string will return the root object (or array) containing all of its children, in one neat reference! The data is in a public ArrayList called list, with a matching key list (called keys!) if the root is an Object. If that's confusing, take a glance over the following code and the print() method in the JSONOBject class. If there is an error in the JSON formatting (or if there's an error with my code!) the debug console will read "improper JSON formatting".
NEW! Decoding now also supports a delegate format which will automatically check if a field exists before processing the data, providing an optional parameter for an OnFieldNotFound response. For example:
I've added a string and int [] index to the class, so you can now retrieve data as such (from above):
I'll fill these in later...