|
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Globalization;
- using System.Text;
- using System.Text.RegularExpressions;
-
- namespace Boomlagoon.JSON
- {
- public class JSONObject : IEnumerable<KeyValuePair<string, JSONValue>>, IEnumerable
- {
- public JSONObject()
- {
- }
-
- public JSONObject(JSONObject other)
- {
- this.values = new Dictionary<string, JSONValue>();
- if (other != null)
- {
- foreach (KeyValuePair<string, JSONValue> keyValuePair in other.values)
- {
- this.values[keyValuePair.Key] = new JSONValue(keyValuePair.Value);
- }
- }
- }
-
- public bool ContainsKey(string key)
- {
- return this.values.ContainsKey(key);
- }
-
- public JSONValue GetValue(string key)
- {
- JSONValue result;
- this.values.TryGetValue(key, out result);
- return result;
- }
-
- public string GetString(string key)
- {
- JSONValue value = this.GetValue(key);
- if (value == null)
- {
- JSONLogger.Error(key + "(string) == null");
- return string.Empty;
- }
- return value.Str;
- }
-
- public double GetNumber(string key)
- {
- JSONValue value = this.GetValue(key);
- if (value == null)
- {
- JSONLogger.Error(key + " == null");
- return double.NaN;
- }
- return value.Number;
- }
-
- public JSONObject GetObject(string key)
- {
- JSONValue value = this.GetValue(key);
- if (value == null)
- {
- JSONLogger.Error(key + " == null");
- return null;
- }
- return value.Obj;
- }
-
- public bool GetBoolean(string key)
- {
- JSONValue value = this.GetValue(key);
- if (value == null)
- {
- JSONLogger.Error(key + " == null");
- return false;
- }
- return value.Boolean;
- }
-
- public JSONArray GetArray(string key)
- {
- JSONValue value = this.GetValue(key);
- if (value == null)
- {
- JSONLogger.Error(key + " == null");
- return null;
- }
- return value.Array;
- }
-
- public JSONValue this[string key]
- {
- get
- {
- return this.GetValue(key);
- }
- set
- {
- this.values[key] = value;
- }
- }
-
- public void Add(string key, JSONValue value)
- {
- this.values[key] = value;
- }
-
- public void Add(KeyValuePair<string, JSONValue> pair)
- {
- this.values[pair.Key] = pair.Value;
- }
-
- public static JSONObject Parse(string jsonString)
- {
- if (string.IsNullOrEmpty(jsonString))
- {
- return null;
- }
- JSONValue jsonvalue = null;
- List<string> list = new List<string>();
- JSONObject.JSONParsingState jsonparsingState = JSONObject.JSONParsingState.Object;
- for (int i = 0; i < jsonString.Length; i++)
- {
- i = JSONObject.SkipWhitespace(jsonString, i);
- switch (jsonparsingState)
- {
- case JSONObject.JSONParsingState.Object:
- {
- if (jsonString[i] != '{')
- {
- return JSONObject.Fail('{', i);
- }
- JSONValue jsonvalue2 = new JSONObject();
- if (jsonvalue != null)
- {
- jsonvalue2.Parent = jsonvalue;
- }
- jsonvalue = jsonvalue2;
- jsonparsingState = JSONObject.JSONParsingState.Key;
- break;
- }
- case JSONObject.JSONParsingState.Array:
- {
- if (jsonString[i] != '[')
- {
- return JSONObject.Fail('[', i);
- }
- JSONValue jsonvalue3 = new JSONArray();
- if (jsonvalue != null)
- {
- jsonvalue3.Parent = jsonvalue;
- }
- jsonvalue = jsonvalue3;
- jsonparsingState = JSONObject.JSONParsingState.Value;
- break;
- }
- case JSONObject.JSONParsingState.EndObject:
- {
- if (jsonString[i] != '}')
- {
- return JSONObject.Fail('}', i);
- }
- if (jsonvalue.Parent == null)
- {
- return jsonvalue.Obj;
- }
- JSONValueType type = jsonvalue.Parent.Type;
- if (type != JSONValueType.Object)
- {
- if (type != JSONValueType.Array)
- {
- return JSONObject.Fail("valid object", i);
- }
- jsonvalue.Parent.Array.Add(new JSONValue(jsonvalue.Obj));
- }
- else
- {
- jsonvalue.Parent.Obj.values[list.Pop<string>()] = new JSONValue(jsonvalue.Obj);
- }
- jsonvalue = jsonvalue.Parent;
- jsonparsingState = JSONObject.JSONParsingState.ValueSeparator;
- break;
- }
- case JSONObject.JSONParsingState.EndArray:
- {
- if (jsonString[i] != ']')
- {
- return JSONObject.Fail(']', i);
- }
- if (jsonvalue.Parent == null)
- {
- return jsonvalue.Obj;
- }
- JSONValueType type2 = jsonvalue.Parent.Type;
- if (type2 != JSONValueType.Object)
- {
- if (type2 != JSONValueType.Array)
- {
- return JSONObject.Fail("valid object", i);
- }
- jsonvalue.Parent.Array.Add(new JSONValue(jsonvalue.Array));
- }
- else
- {
- jsonvalue.Parent.Obj.values[list.Pop<string>()] = new JSONValue(jsonvalue.Array);
- }
- jsonvalue = jsonvalue.Parent;
- jsonparsingState = JSONObject.JSONParsingState.ValueSeparator;
- break;
- }
- case JSONObject.JSONParsingState.Key:
- if (jsonString[i] == '}')
- {
- i--;
- jsonparsingState = JSONObject.JSONParsingState.EndObject;
- }
- else
- {
- string text = JSONObject.ParseString(jsonString, ref i);
- if (text == null)
- {
- return JSONObject.Fail("key string", i);
- }
- list.Add(text);
- jsonparsingState = JSONObject.JSONParsingState.KeyValueSeparator;
- }
- break;
- case JSONObject.JSONParsingState.Value:
- {
- char c = jsonString[i];
- if (c == '"')
- {
- jsonparsingState = JSONObject.JSONParsingState.String;
- }
- else if (char.IsDigit(c) || c == '-')
- {
- jsonparsingState = JSONObject.JSONParsingState.Number;
- }
- else
- {
- switch (c)
- {
- case '[':
- jsonparsingState = JSONObject.JSONParsingState.Array;
- break;
- default:
- if (c != 'f')
- {
- if (c == 'n')
- {
- jsonparsingState = JSONObject.JSONParsingState.Null;
- break;
- }
- if (c != 't')
- {
- if (c != '{')
- {
- return JSONObject.Fail("beginning of value", i);
- }
- jsonparsingState = JSONObject.JSONParsingState.Object;
- break;
- }
- }
- jsonparsingState = JSONObject.JSONParsingState.Boolean;
- break;
- case ']':
- if (jsonvalue.Type != JSONValueType.Array)
- {
- return JSONObject.Fail("valid array", i);
- }
- jsonparsingState = JSONObject.JSONParsingState.EndArray;
- break;
- }
- }
- i--;
- break;
- }
- case JSONObject.JSONParsingState.KeyValueSeparator:
- if (jsonString[i] != ':')
- {
- return JSONObject.Fail(':', i);
- }
- jsonparsingState = JSONObject.JSONParsingState.Value;
- break;
- case JSONObject.JSONParsingState.ValueSeparator:
- {
- char c2 = jsonString[i];
- if (c2 != ',')
- {
- if (c2 != ']')
- {
- if (c2 != '}')
- {
- return JSONObject.Fail(", } ]", i);
- }
- jsonparsingState = JSONObject.JSONParsingState.EndObject;
- i--;
- }
- else
- {
- jsonparsingState = JSONObject.JSONParsingState.EndArray;
- i--;
- }
- }
- else
- {
- jsonparsingState = ((jsonvalue.Type != JSONValueType.Object) ? JSONObject.JSONParsingState.Value : JSONObject.JSONParsingState.Key);
- }
- break;
- }
- case JSONObject.JSONParsingState.String:
- {
- string text2 = JSONObject.ParseString(jsonString, ref i);
- if (text2 == null)
- {
- return JSONObject.Fail("string value", i);
- }
- JSONValueType type3 = jsonvalue.Type;
- if (type3 != JSONValueType.Object)
- {
- if (type3 != JSONValueType.Array)
- {
- JSONLogger.Error("Fatal error, current JSON value not valid");
- return null;
- }
- jsonvalue.Array.Add(text2);
- }
- else
- {
- jsonvalue.Obj.values[list.Pop<string>()] = new JSONValue(text2);
- }
- jsonparsingState = JSONObject.JSONParsingState.ValueSeparator;
- break;
- }
- case JSONObject.JSONParsingState.Number:
- {
- double num = JSONObject.ParseNumber(jsonString, ref i);
- if (double.IsNaN(num))
- {
- return JSONObject.Fail("valid number", i);
- }
- JSONValueType type4 = jsonvalue.Type;
- if (type4 != JSONValueType.Object)
- {
- if (type4 != JSONValueType.Array)
- {
- JSONLogger.Error("Fatal error, current JSON value not valid");
- return null;
- }
- jsonvalue.Array.Add(num);
- }
- else
- {
- jsonvalue.Obj.values[list.Pop<string>()] = new JSONValue(num);
- }
- jsonparsingState = JSONObject.JSONParsingState.ValueSeparator;
- break;
- }
- case JSONObject.JSONParsingState.Boolean:
- if (jsonString[i] == 't')
- {
- if (jsonString.Length < i + 4 || jsonString[i + 1] != 'r' || jsonString[i + 2] != 'u' || jsonString[i + 3] != 'e')
- {
- return JSONObject.Fail("true", i);
- }
- JSONValueType type5 = jsonvalue.Type;
- if (type5 != JSONValueType.Object)
- {
- if (type5 != JSONValueType.Array)
- {
- JSONLogger.Error("Fatal error, current JSON value not valid");
- return null;
- }
- jsonvalue.Array.Add(new JSONValue(true));
- }
- else
- {
- jsonvalue.Obj.values[list.Pop<string>()] = new JSONValue(true);
- }
- i += 3;
- }
- else
- {
- if (jsonString.Length < i + 5 || jsonString[i + 1] != 'a' || jsonString[i + 2] != 'l' || jsonString[i + 3] != 's' || jsonString[i + 4] != 'e')
- {
- return JSONObject.Fail("false", i);
- }
- JSONValueType type6 = jsonvalue.Type;
- if (type6 != JSONValueType.Object)
- {
- if (type6 != JSONValueType.Array)
- {
- JSONLogger.Error("Fatal error, current JSON value not valid");
- return null;
- }
- jsonvalue.Array.Add(new JSONValue(false));
- }
- else
- {
- jsonvalue.Obj.values[list.Pop<string>()] = new JSONValue(false);
- }
- i += 4;
- }
- jsonparsingState = JSONObject.JSONParsingState.ValueSeparator;
- break;
- case JSONObject.JSONParsingState.Null:
- if (jsonString[i] == 'n')
- {
- if (jsonString.Length < i + 4 || jsonString[i + 1] != 'u' || jsonString[i + 2] != 'l' || jsonString[i + 3] != 'l')
- {
- return JSONObject.Fail("null", i);
- }
- JSONValueType type7 = jsonvalue.Type;
- if (type7 != JSONValueType.Object)
- {
- if (type7 != JSONValueType.Array)
- {
- JSONLogger.Error("Fatal error, current JSON value not valid");
- return null;
- }
- jsonvalue.Array.Add(new JSONValue(JSONValueType.Null));
- }
- else
- {
- jsonvalue.Obj.values[list.Pop<string>()] = new JSONValue(JSONValueType.Null);
- }
- i += 3;
- }
- jsonparsingState = JSONObject.JSONParsingState.ValueSeparator;
- break;
- }
- }
- JSONLogger.Error("Unexpected end of string");
- return null;
- }
-
- private static int SkipWhitespace(string str, int pos)
- {
- while (pos < str.Length && char.IsWhiteSpace(str[pos]))
- {
- pos++;
- }
- return pos;
- }
-
- private static string ParseString(string str, ref int startPosition)
- {
- if (str[startPosition] != '"' || startPosition + 1 >= str.Length)
- {
- JSONObject.Fail('"', startPosition);
- return null;
- }
- int num = str.IndexOf('"', startPosition + 1);
- if (num <= startPosition)
- {
- JSONObject.Fail('"', startPosition + 1);
- return null;
- }
- while (str[num - 1] == '\\')
- {
- num = str.IndexOf('"', num + 1);
- if (num <= startPosition)
- {
- JSONObject.Fail('"', startPosition + 1);
- return null;
- }
- }
- string text = string.Empty;
- if (num > startPosition + 1)
- {
- text = str.Substring(startPosition + 1, num - startPosition - 1);
- }
- startPosition = num;
- for (;;)
- {
- Match match = JSONObject.unicodeRegex.Match(text);
- if (!match.Success)
- {
- break;
- }
- string text2 = match.Groups[1].Captures[0].Value;
- JSONObject.unicodeBytes[1] = byte.Parse(text2.Substring(0, 2), NumberStyles.HexNumber);
- JSONObject.unicodeBytes[0] = byte.Parse(text2.Substring(2, 2), NumberStyles.HexNumber);
- text2 = Encoding.Unicode.GetString(JSONObject.unicodeBytes, 0, JSONObject.unicodeBytes.Length);
- text = text.Replace(match.Value, text2);
- }
- return text;
- }
-
- private static double ParseNumber(string str, ref int startPosition)
- {
- if (startPosition >= str.Length || (!char.IsDigit(str[startPosition]) && str[startPosition] != '-'))
- {
- return double.NaN;
- }
- int num = startPosition + 1;
- while (num < str.Length && str[num] != ',' && str[num] != ']' && str[num] != '}')
- {
- num++;
- }
- double result;
- if (!double.TryParse(str.Substring(startPosition, num - startPosition), NumberStyles.Float, CultureInfo.InvariantCulture, out result))
- {
- return double.NaN;
- }
- startPosition = num - 1;
- return result;
- }
-
- private static JSONObject Fail(char expected, int position)
- {
- return JSONObject.Fail(new string(expected, 1), position);
- }
-
- private static JSONObject Fail(string expected, int position)
- {
- JSONLogger.Error(string.Format("Invalid json string, expecting {0} at {1}", expected, position));
- return null;
- }
-
- public override string ToString()
- {
- StringBuilder stringBuilder = new StringBuilder();
- stringBuilder.Append('{');
- foreach (KeyValuePair<string, JSONValue> keyValuePair in this.values)
- {
- stringBuilder.Append("\"" + keyValuePair.Key + "\"");
- stringBuilder.Append(':');
- stringBuilder.Append(keyValuePair.Value.ToString());
- stringBuilder.Append(',');
- }
- if (this.values.Count > 0)
- {
- stringBuilder.Remove(stringBuilder.Length - 1, 1);
- }
- stringBuilder.Append('}');
- return stringBuilder.ToString();
- }
-
- public IEnumerator<KeyValuePair<string, JSONValue>> GetEnumerator()
- {
- return this.values.GetEnumerator();
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return this.values.GetEnumerator();
- }
-
- public void Clear()
- {
- this.values.Clear();
- }
-
- public void Remove(string key)
- {
- if (this.values.ContainsKey(key))
- {
- this.values.Remove(key);
- }
- }
-
- private readonly IDictionary<string, JSONValue> values = new Dictionary<string, JSONValue>();
-
- private static readonly Regex unicodeRegex = new Regex("\\\\u([0-9a-fA-F]{4})");
-
- private static readonly byte[] unicodeBytes = new byte[2];
-
- private enum JSONParsingState
- {
- Object,
- Array,
- EndObject,
- EndArray,
- Key,
- Value,
- KeyValueSeparator,
- ValueSeparator,
- String,
- Number,
- Boolean,
- Null
- }
- }
- }
|