123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Data;
- using System.Globalization;
- using System.Reflection;
- using System.Reflection.Emit;
- using System.Text;
- namespace CP.Common.fastJSON
- {
- /// <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 ArrayList and Hashtable.
- /// All numbers are parsed to doubles.
- /// </summary>
- internal class JsonParser
- {
- private const int TOKEN_NONE = 0;
- private const int TOKEN_CURLY_OPEN = 1;
- private const int TOKEN_CURLY_CLOSE = 2;
- private const int TOKEN_SQUARED_OPEN = 3;
- private const int TOKEN_SQUARED_CLOSE = 4;
- private const int TOKEN_COLON = 5;
- private const int TOKEN_COMMA = 6;
- private const int TOKEN_STRING = 7;
- private const int TOKEN_NUMBER = 8;
- private const int TOKEN_TRUE = 9;
- private const int TOKEN_FALSE = 10;
- private const int TOKEN_NULL = 11;
- /// <summary>
- /// Parses the string json into a value
- /// </summary>
- /// <param name="json">A JSON string.</param>
- /// <returns>An ArrayList, a dictionary, a double, a string, null, true, or false</returns>
- internal static object JsonDecode(string json)
- {
- bool success = true;
- return JsonDecode(json, ref success);
- }
- /// <summary>
- /// Parses the string json into a value; and fills 'success' with the successfullness of the parse.
- /// </summary>
- /// <param name="json">A JSON string.</param>
- /// <param name="success">Successful parse?</param>
- /// <returns>An ArrayList, a Hashtable, a double, a string, null, true, or false</returns>
- private static object JsonDecode(string json, ref bool success)
- {
- success = true;
- if (json != null)
- {
- char[] charArray = json.ToCharArray();
- int index = 0;
- object value = ParseValue(charArray, ref index, ref success);
- return value;
- }
- else
- {
- return null;
- }
- }
- protected static Dictionary<string, object> ParseObject(char[] json, ref int index, ref bool success)
- {
- Dictionary<string, object> table = new Dictionary<string, object>();
- int token;
- // {
- NextToken(json, ref index);
- bool done = false;
- while (!done)
- {
- token = LookAhead(json, index);
- if (token == TOKEN_NONE)
- {
- success = false;
- return null;
- }
- else if (token == TOKEN_COMMA)
- {
- NextToken(json, ref index);
- }
- else if (token == TOKEN_CURLY_CLOSE)
- {
- NextToken(json, ref index);
- return table;
- }
- else
- {
- // name
- string name = ParseString(json, ref index, ref success);
- if (!success)
- {
- success = false;
- return null;
- }
- // :
- token = NextToken(json, ref index);
- if (token != TOKEN_COLON)
- {
- success = false;
- return null;
- }
- // value
- object value = ParseValue(json, ref index, ref success);
- if (!success)
- {
- success = false;
- return null;
- }
- table[name] = value;
- }
- }
- return table;
- }
- protected static ArrayList ParseArray(char[] json, ref int index, ref bool success)
- {
- ArrayList array = new ArrayList();
- NextToken(json, ref index);
- bool done = false;
- while (!done)
- {
- int token = LookAhead(json, index);
- if (token == TOKEN_NONE)
- {
- success = false;
- return null;
- }
- else if (token == TOKEN_COMMA)
- {
- NextToken(json, ref index);
- }
- else if (token == TOKEN_SQUARED_CLOSE)
- {
- NextToken(json, ref index);
- break;
- }
- else
- {
- object value = ParseValue(json, ref index, ref success);
- if (!success)
- {
- return null;
- }
- array.Add(value);
- }
- }
- return array;
- }
- protected static object ParseValue(char[] json, ref int index, ref bool success)
- {
- switch (LookAhead(json, index))
- {
- case TOKEN_NUMBER:
- return ParseNumber(json, ref index, ref success);
- case TOKEN_STRING:
- return ParseString(json, ref index, ref success);
- case TOKEN_CURLY_OPEN:
- return ParseObject(json, ref index, ref success);
- case TOKEN_SQUARED_OPEN:
- return ParseArray(json, ref index, ref success);
- case TOKEN_TRUE:
- NextToken(json, ref index);
- return true;
- case TOKEN_FALSE:
- NextToken(json, ref index);
- return false;
- case TOKEN_NULL:
- NextToken(json, ref index);
- return null;
- case TOKEN_NONE:
- break;
- }
- success = false;
- return null;
- }
- protected static string ParseString(char[] json, ref int index, ref bool success)
- {
- StringBuilder s = new StringBuilder();
- char c;
- EatWhitespace(json, ref index);
- // "
- c = json[index++];
- bool complete = false;
- while (!complete)
- {
- if (index == json.Length)
- {
- break;
- }
- c = json[index++];
- if (c == '"')
- {
- complete = true;
- break;
- }
- else if (c == '\\')
- {
- if (index == json.Length)
- {
- break;
- }
- c = json[index++];
- if (c == '"')
- {
- s.Append('"');
- }
- else if (c == '\\')
- {
- s.Append('\\');
- }
- else if (c == '/')
- {
- s.Append('/');
- }
- else if (c == 'b')
- {
- s.Append('\b');
- }
- else if (c == 'f')
- {
- s.Append('\f');
- }
- else if (c == 'n')
- {
- s.Append('\n');
- }
- else if (c == 'r')
- {
- s.Append('\r');
- }
- else if (c == 't')
- {
- s.Append('\t');
- }
- else if (c == 'u')
- {
- int remainingLength = json.Length - index;
- if (remainingLength >= 4)
- {
- // parse the 32 bit hex into an integer codepoint
- uint codePoint;
- if (!(success = UInt32.TryParse(new string(json, index, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out codePoint)))
- {
- return "";
- }
- // convert the integer codepoint to a unicode char and add to string
- s.Append(Char.ConvertFromUtf32((int)codePoint));
- // skip 4 chars
- index += 4;
- }
- else
- {
- break;
- }
- }
- }
- else
- {
- s.Append(c);
- }
- }
- if (!complete)
- {
- success = false;
- return null;
- }
- return s.ToString();
- }
- protected static string ParseNumber(char[] json, ref int index, ref bool success)
- {
- EatWhitespace(json, ref index);
- int lastIndex = GetLastIndexOfNumber(json, index);
- int charLength = (lastIndex - index) + 1;
- string number = new string(json, index, charLength);
- success = true;
- index = lastIndex + 1;
- return number;
- }
- protected static int GetLastIndexOfNumber(char[] json, int index)
- {
- int lastIndex;
- for (lastIndex = index; lastIndex < json.Length; lastIndex++)
- {
- if ("0123456789+-.eE".IndexOf(json[lastIndex]) == -1)
- {
- break;
- }
- }
- return lastIndex - 1;
- }
- protected static void EatWhitespace(char[] json, ref int index)
- {
- for (; index < json.Length; index++)
- {
- if (" \t\n\r".IndexOf(json[index]) == -1)
- {
- break;
- }
- }
- }
- protected static int LookAhead(char[] json, int index)
- {
- int saveIndex = index;
- return NextToken(json, ref saveIndex);
- }
- protected static int NextToken(char[] json, ref int index)
- {
- EatWhitespace(json, ref index);
- if (index == json.Length)
- {
- return TOKEN_NONE;
- }
- char c = json[index];
- index++;
- switch (c)
- {
- case '{':
- return TOKEN_CURLY_OPEN;
- case '}':
- return TOKEN_CURLY_CLOSE;
- case '[':
- return TOKEN_SQUARED_OPEN;
- case ']':
- return TOKEN_SQUARED_CLOSE;
- case ',':
- return TOKEN_COMMA;
- case '"':
- return TOKEN_STRING;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- case '-':
- return TOKEN_NUMBER;
- case ':':
- return TOKEN_COLON;
- }
- index--;
- int remainingLength = json.Length - index;
- // false
- if (remainingLength >= 5)
- {
- if (json[index] == 'f' &&
- json[index + 1] == 'a' &&
- json[index + 2] == 'l' &&
- json[index + 3] == 's' &&
- json[index + 4] == 'e')
- {
- index += 5;
- return TOKEN_FALSE;
- }
- }
- // true
- if (remainingLength >= 4)
- {
- if (json[index] == 't' &&
- json[index + 1] == 'r' &&
- json[index + 2] == 'u' &&
- json[index + 3] == 'e')
- {
- index += 4;
- return TOKEN_TRUE;
- }
- }
- // null
- if (remainingLength >= 4)
- {
- if (json[index] == 'n' &&
- json[index + 1] == 'u' &&
- json[index + 2] == 'l' &&
- json[index + 3] == 'l')
- {
- index += 4;
- return TOKEN_NULL;
- }
- }
- return TOKEN_NONE;
- }
- protected static bool SerializeValue(object value, StringBuilder builder)
- {
- bool success = true;
- if (value is string)
- {
- success = SerializeString((string)value, builder);
- }
- else if (value is Hashtable)
- {
- success = SerializeObject((Hashtable)value, builder);
- }
- else if (value is ArrayList)
- {
- success = SerializeArray((ArrayList)value, builder);
- }
- else if (IsNumeric(value))
- {
- success = SerializeNumber(Convert.ToDouble(value), builder);
- }
- else if ((value is Boolean) && ((Boolean)value == true))
- {
- builder.Append("true");
- }
- else if ((value is Boolean) && ((Boolean)value == false))
- {
- builder.Append("false");
- }
- else if (value == null)
- {
- builder.Append("null");
- }
- else
- {
- success = false;
- }
- return success;
- }
- protected static bool SerializeObject(Hashtable anObject, StringBuilder builder)
- {
- builder.Append("{");
- IDictionaryEnumerator e = anObject.GetEnumerator();
- bool first = true;
- while (e.MoveNext())
- {
- string key = e.Key.ToString();
- object value = e.Value;
- if (!first)
- {
- builder.Append(", ");
- }
- SerializeString(key, builder);
- builder.Append(":");
- if (!SerializeValue(value, builder))
- {
- return false;
- }
- first = false;
- }
- builder.Append("}");
- return true;
- }
- protected static bool SerializeArray(ArrayList anArray, StringBuilder builder)
- {
- builder.Append("[");
- bool first = true;
- for (int i = 0; i < anArray.Count; i++)
- {
- object value = anArray[i];
- if (!first)
- {
- builder.Append(", ");
- }
- if (!SerializeValue(value, builder))
- {
- return false;
- }
- first = false;
- }
- builder.Append("]");
- return true;
- }
- protected static bool SerializeString(string aString, StringBuilder builder)
- {
- builder.Append("\"");
- char[] charArray = aString.ToCharArray();
- for (int i = 0; i < charArray.Length; i++)
- {
- char c = charArray[i];
- if (c == '"')
- {
- builder.Append("\\\"");
- }
- else if (c == '\\')
- {
- builder.Append("\\\\");
- }
- else if (c == '\b')
- {
- builder.Append("\\b");
- }
- else if (c == '\f')
- {
- builder.Append("\\f");
- }
- else if (c == '\n')
- {
- builder.Append("\\n");
- }
- else if (c == '\r')
- {
- builder.Append("\\r");
- }
- else if (c == '\t')
- {
- builder.Append("\\t");
- }
- else
- {
- int codepoint = Convert.ToInt32(c);
- if ((codepoint >= 32) && (codepoint <= 126))
- {
- builder.Append(c);
- }
- else
- {
- builder.Append("\\u" + Convert.ToString(codepoint, 16).PadLeft(4, '0'));
- }
- }
- }
- builder.Append("\"");
- return true;
- }
- protected static bool SerializeNumber(double number, StringBuilder builder)
- {
- builder.Append(Convert.ToString(number, CultureInfo.InvariantCulture));
- return true;
- }
- protected static bool IsNumeric(object o)
- {
- double result;
- return (o == null) ? false : Double.TryParse(o.ToString(), out result);
- }
- }
- }
|