| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626 | /* * Copyright (c) 2013 Calvin Rien * * Based on the JSON parser by Patrick van Bergen * http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html * * Simplified it so that it doesn't throw exceptions * and can be used in Unity iPhone with maximum code stripping. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */using System.Globalization;namespace SRF{    using System;    using System.Collections;    using System.Collections.Generic;    using System.IO;    using System.Text;    // Example usage:    //    //  using UnityEngine;    //  using System.Collections;    //  using System.Collections.Generic;    //  using MiniJSON;    //    //  public class MiniJSONTest : MonoBehaviour {    //      void Start () {    //          var jsonString = "{ \"array\": [1.44,2,3], " +    //                          "\"object\": {\"key1\":\"value1\", \"key2\":256}, " +    //                          "\"string\": \"The quick brown fox \\\"jumps\\\" over the lazy dog \", " +    //                          "\"unicode\": \"\\u3041 Men\u00fa sesi\u00f3n\", " +    //                          "\"int\": 65536, " +    //                          "\"float\": 3.1415926, " +    //                          "\"bool\": true, " +    //                          "\"null\": null }";    //    //          var dict = Json.Deserialize(jsonString) as Dictionary<string,object>;    //    //          Debug.Log("deserialized: " + dict.GetType());    //          Debug.Log("dict['array'][0]: " + ((List<object>) dict["array"])[0]);    //          Debug.Log("dict['string']: " + (string) dict["string"]);    //          Debug.Log("dict['float']: " + (double) dict["float"]); // floats come out as doubles    //          Debug.Log("dict['int']: " + (long) dict["int"]); // ints come out as longs    //          Debug.Log("dict['unicode']: " + (string) dict["unicode"]);    //    //          var str = Json.Serialize(dict);    //    //          Debug.Log("serialized: " + str);    //      }    //  }    /// <summary>    /// This class encodes and decodes JSON strings.    /// Spec. details, see http://www.json.org/    /// JSON uses Arrays and Objects. These correspond here to the datatypes IList and IDictionary.    /// All numbers are parsed to doubles.    /// </summary>    public static class Json    {        /// <summary>        /// Parses the string json into a value        /// </summary>        /// <param name="json">A JSON string.</param>        /// <returns>An List<object>, a Dictionary<string, object>, a double, an integer,a string, null, true, or false</returns>        public static object Deserialize(string json)        {            // save the string for debug information            if (json == null)            {                return null;            }            return Parser.Parse(json);        }        /// <summary>        /// Converts a IDictionary / IList object or a simple type (string, int, etc.) into a JSON string        /// </summary>        /// <param name="json">A Dictionary<string, object> / List<object></param>        /// <returns>A JSON encoded string, or null if object 'json' is not serializable</returns>        public static string Serialize(object obj)        {            return Serializer.Serialize(obj);        }        private sealed class Parser : IDisposable        {            private const string WORD_BREAK = "{}[],:\"";            private StringReader json;            private Parser(string jsonString)            {                json = new StringReader(jsonString);            }            private char PeekChar            {                get { return Convert.ToChar(json.Peek()); }            }            private char NextChar            {                get { return Convert.ToChar(json.Read()); }            }            private string NextWord            {                get                {                    var word = new StringBuilder();                    while (!IsWordBreak(PeekChar))                    {                        word.Append(NextChar);                        if (json.Peek() == -1)                        {                            break;                        }                    }                    return word.ToString();                }            }            private TOKEN NextToken            {                get                {                    EatWhitespace();                    if (json.Peek() == -1)                    {                        return TOKEN.NONE;                    }                    switch (PeekChar)                    {                        case '{':                            return TOKEN.CURLY_OPEN;                        case '}':                            json.Read();                            return TOKEN.CURLY_CLOSE;                        case '[':                            return TOKEN.SQUARED_OPEN;                        case ']':                            json.Read();                            return TOKEN.SQUARED_CLOSE;                        case ',':                            json.Read();                            return TOKEN.COMMA;                        case '"':                            return TOKEN.STRING;                        case ':':                            return TOKEN.COLON;                        case '0':                        case '1':                        case '2':                        case '3':                        case '4':                        case '5':                        case '6':                        case '7':                        case '8':                        case '9':                        case '-':                            return TOKEN.NUMBER;                    }                    switch (NextWord)                    {                        case "false":                            return TOKEN.FALSE;                        case "true":                            return TOKEN.TRUE;                        case "null":                            return TOKEN.NULL;                    }                    return TOKEN.NONE;                }            }            public void Dispose()            {                json.Dispose();                json = null;            }            public static bool IsWordBreak(char c)            {                return char.IsWhiteSpace(c) || WORD_BREAK.IndexOf(c) != -1;            }            public static object Parse(string jsonString)            {                using (var instance = new Parser(jsonString))                {                    return instance.ParseValue();                }            }            private Dictionary<string, object> ParseObject()            {                var table = new Dictionary<string, object>();                // ditch opening brace                json.Read();                // {                while (true)                {                    switch (NextToken)                    {                        case TOKEN.NONE:                            return null;                        case TOKEN.COMMA:                            continue;                        case TOKEN.CURLY_CLOSE:                            return table;                        default:                            // name                            var name = ParseString();                            if (name == null)                            {                                return null;                            }                            // :                            if (NextToken != TOKEN.COLON)                            {                                return null;                            }                            // ditch the colon                            json.Read();                            // value                            table[name] = ParseValue();                            break;                    }                }            }            private List<object> ParseArray()            {                var array = new List<object>();                // ditch opening bracket                json.Read();                // [                var parsing = true;                while (parsing)                {                    var nextToken = NextToken;                    switch (nextToken)                    {                        case TOKEN.NONE:                            return null;                        case TOKEN.COMMA:                            continue;                        case TOKEN.SQUARED_CLOSE:                            parsing = false;                            break;                        default:                            var value = ParseByToken(nextToken);                            array.Add(value);                            break;                    }                }                return array;            }            private object ParseValue()            {                var nextToken = NextToken;                return ParseByToken(nextToken);            }            private object ParseByToken(TOKEN token)            {                switch (token)                {                    case TOKEN.STRING:                        return ParseString();                    case TOKEN.NUMBER:                        return ParseNumber();                    case TOKEN.CURLY_OPEN:                        return ParseObject();                    case TOKEN.SQUARED_OPEN:                        return ParseArray();                    case TOKEN.TRUE:                        return true;                    case TOKEN.FALSE:                        return false;                    case TOKEN.NULL:                        return null;                    default:                        return null;                }            }            private string ParseString()            {                var s = new StringBuilder();                char c;                // ditch opening quote                json.Read();                var parsing = true;                while (parsing)                {                    if (json.Peek() == -1)                    {                        parsing = false;                        break;                    }                    c = NextChar;                    switch (c)                    {                        case '"':                            parsing = false;                            break;                        case '\\':                            if (json.Peek() == -1)                            {                                parsing = false;                                break;                            }                            c = NextChar;                            switch (c)                            {                                case '"':                                case '\\':                                case '/':                                    s.Append(c);                                    break;                                case 'b':                                    s.Append('\b');                                    break;                                case 'f':                                    s.Append('\f');                                    break;                                case 'n':                                    s.Append('\n');                                    break;                                case 'r':                                    s.Append('\r');                                    break;                                case 't':                                    s.Append('\t');                                    break;                                case 'u':                                    var hex = new char[4];                                    for (var i = 0; i < 4; i++)                                    {                                        hex[i] = NextChar;                                    }                                    s.Append((char) Convert.ToInt32(new string(hex), 16));                                    break;                            }                            break;                        default:                            s.Append(c);                            break;                    }                }                return s.ToString();            }            private object ParseNumber()            {                var number = NextWord;                if (number.IndexOf('.') == -1)                {                    long parsedInt;                    long.TryParse(number, out parsedInt);                    return parsedInt;                }                double parsedDouble;                double.TryParse(number, out parsedDouble);                return parsedDouble;            }            private void EatWhitespace()            {                while (char.IsWhiteSpace(PeekChar))                {                    json.Read();                    if (json.Peek() == -1)                    {                        break;                    }                }            }            private enum TOKEN            {                NONE,                CURLY_OPEN,                CURLY_CLOSE,                SQUARED_OPEN,                SQUARED_CLOSE,                COLON,                COMMA,                STRING,                NUMBER,                TRUE,                FALSE,                NULL            };        }        private sealed class Serializer        {            private StringBuilder builder;            private Serializer()            {                builder = new StringBuilder();            }            public static string Serialize(object obj)            {                var instance = new Serializer();                instance.SerializeValue(obj);                return instance.builder.ToString();            }            private void SerializeValue(object value)            {                IList asList;                IDictionary asDict;                string asStr;                if (value == null)                {                    builder.Append("null");                }                else if ((asStr = value as string) != null)                {                    SerializeString(asStr);                }                else if (value is bool)                {                    builder.Append((bool) value ? "true" : "false");                }                else if ((asList = value as IList) != null)                {                    SerializeArray(asList);                }                else if ((asDict = value as IDictionary) != null)                {                    SerializeObject(asDict);                }                else if (value is char)                {                    SerializeString(new string((char) value, 1));                }                else                {                    SerializeOther(value);                }            }            private void SerializeObject(IDictionary obj)            {                var first = true;                builder.Append('{');                foreach (var e in obj.Keys)                {                    if (!first)                    {                        builder.Append(',');                    }                    SerializeString(e.ToString());                    builder.Append(':');                    SerializeValue(obj[e]);                    first = false;                }                builder.Append('}');            }            private void SerializeArray(IList anArray)            {                builder.Append('[');                var first = true;                foreach (var obj in anArray)                {                    if (!first)                    {                        builder.Append(',');                    }                    SerializeValue(obj);                    first = false;                }                builder.Append(']');            }            private void SerializeString(string str)            {                builder.Append('\"');                var charArray = str.ToCharArray();                foreach (var c in charArray)                {                    switch (c)                    {                        case '"':                            builder.Append("\\\"");                            break;                        case '\\':                            builder.Append("\\\\");                            break;                        case '\b':                            builder.Append("\\b");                            break;                        case '\f':                            builder.Append("\\f");                            break;                        case '\n':                            builder.Append("\\n");                            break;                        case '\r':                            builder.Append("\\r");                            break;                        case '\t':                            builder.Append("\\t");                            break;                        default:                            var codepoint = Convert.ToInt32(c);                            if ((codepoint >= 32) && (codepoint <= 126))                            {                                builder.Append(c);                            }                            else                            {                                builder.Append("\\u");                                builder.Append(codepoint.ToString("x4"));                            }                            break;                    }                }                builder.Append('\"');            }            private void SerializeOther(object value)            {                // NOTE: decimals lose precision during serialization.                // They always have, I'm just letting you know.                // Previously floats and doubles lost precision too.                if (value is float)                {                    builder.Append(((float) value).ToString("R", CultureInfo.InvariantCulture));                }                else if (value is int                         || value is uint                         || value is long                         || value is sbyte                         || value is byte                         || value is short                         || value is ushort                         || value is ulong)                {                    builder.Append(value);                }                else if (value is double                         || value is decimal)                {                    builder.Append(Convert.ToDouble(value).ToString("R", CultureInfo.InvariantCulture));                }                else                {                    SerializeString(value.ToString());                }            }        }    }}
 |