diff --git a/JSON-dynamic.cs b/JSON-dynamic.cs
new file mode 100644
index 0000000..1929af3
--- /dev/null
+++ b/JSON-dynamic.cs
@@ -0,0 +1,600 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text;
+
+namespace Procurios.Public
+{
+ ///
+ /// 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 List and Dictionary.
+ /// All numbers are parsed to doubles.
+ ///
+ public class JSON
+ {
+ public const int TOKEN_NONE = 0;
+ public const int TOKEN_CURLY_OPEN = 1;
+ public const int TOKEN_CURLY_CLOSE = 2;
+ public const int TOKEN_SQUARED_OPEN = 3;
+ public const int TOKEN_SQUARED_CLOSE = 4;
+ public const int TOKEN_COLON = 5;
+ public const int TOKEN_COMMA = 6;
+ public const int TOKEN_STRING = 7;
+ public const int TOKEN_NUMBER = 8;
+ public const int TOKEN_TRUE = 9;
+ public const int TOKEN_FALSE = 10;
+ public const int TOKEN_NULL = 11;
+
+ private const int BUILDER_CAPACITY = 2000;
+
+ ///
+ /// Parses the string json into a value
+ ///
+ /// A JSON string.
+ /// An ArrayList, a Hashtable, a double, a string, null, true, or false
+ public static dynamic JsonDecode(string json)
+ {
+ bool success = true;
+
+ return JsonDecode(json, ref success);
+ }
+
+ ///
+ /// Parses the string json into a value; and fills 'success' with the successfullness of the parse.
+ ///
+ /// A JSON string.
+ /// Successful parse?
+ /// An ArrayList, a Hashtable, a double, a string, null, true, or false
+ public static dynamic JsonDecode(string json, ref bool success)
+ {
+ success = true;
+ if (json != null)
+ {
+ char[] charArray = json.ToCharArray();
+ int index = 0;
+ dynamic value = ParseValue(charArray, ref index, ref success);
+ return value;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ ///
+ /// Converts a Hashtable / ArrayList object into a JSON string
+ ///
+ /// A Hashtable / ArrayList
+ /// A JSON encoded string, or null if object 'json' is not serializable
+ public static string JsonEncode(object json)
+ {
+ StringBuilder builder = new StringBuilder(BUILDER_CAPACITY);
+ bool success = SerializeValue(json, builder);
+ return (success ? builder.ToString() : null);
+ }
+
+ protected static dynamic ParseObject(char[] json, ref int index, ref bool success)
+ {
+ Dictionary table = new Dictionary();
+ int token;
+
+ // {
+ NextToken(json, ref index);
+
+ bool done = false;
+ while (!done)
+ {
+ token = LookAhead(json, index);
+ if (token == JSON.TOKEN_NONE)
+ {
+ success = false;
+ return null;
+ }
+ else if (token == JSON.TOKEN_COMMA)
+ {
+ NextToken(json, ref index);
+ }
+ else if (token == JSON.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 != JSON.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 dynamic ParseArray(char[] json, ref int index, ref bool success)
+ {
+ List array = new List();
+
+ // [
+ NextToken(json, ref index);
+
+ bool done = false;
+ while (!done)
+ {
+ int token = LookAhead(json, index);
+ if (token == JSON.TOKEN_NONE)
+ {
+ success = false;
+ return null;
+ }
+ else if (token == JSON.TOKEN_COMMA)
+ {
+ NextToken(json, ref index);
+ }
+ else if (token == JSON.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 dynamic ParseValue(char[] json, ref int index, ref bool success)
+ {
+ switch (LookAhead(json, index))
+ {
+ case JSON.TOKEN_STRING:
+ return ParseString(json, ref index, ref success);
+ case JSON.TOKEN_NUMBER:
+ return ParseNumber(json, ref index, ref success);
+ case JSON.TOKEN_CURLY_OPEN:
+ return ParseObject(json, ref index, ref success);
+ case JSON.TOKEN_SQUARED_OPEN:
+ return ParseArray(json, ref index, ref success);
+ case JSON.TOKEN_TRUE:
+ NextToken(json, ref index);
+ return true;
+ case JSON.TOKEN_FALSE:
+ NextToken(json, ref index);
+ return false;
+ case JSON.TOKEN_NULL:
+ NextToken(json, ref index);
+ return null;
+ case JSON.TOKEN_NONE:
+ break;
+ }
+
+ success = false;
+ return null;
+ }
+
+ protected static string ParseString(char[] json, ref int index, ref bool success)
+ {
+ StringBuilder s = new StringBuilder(BUILDER_CAPACITY);
+ 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 double ParseNumber(char[] json, ref int index, ref bool success)
+ {
+ EatWhitespace(json, ref index);
+
+ int lastIndex = GetLastIndexOfNumber(json, index);
+ int charLength = (lastIndex - index) + 1;
+
+ double number;
+ success = Double.TryParse(new string(json, index, charLength), NumberStyles.Any, CultureInfo.InvariantCulture, out number);
+
+ 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 JSON.TOKEN_NONE;
+ }
+
+ char c = json[index];
+ index++;
+ switch (c)
+ {
+ case '{':
+ return JSON.TOKEN_CURLY_OPEN;
+ case '}':
+ return JSON.TOKEN_CURLY_CLOSE;
+ case '[':
+ return JSON.TOKEN_SQUARED_OPEN;
+ case ']':
+ return JSON.TOKEN_SQUARED_CLOSE;
+ case ',':
+ return JSON.TOKEN_COMMA;
+ case '"':
+ return JSON.TOKEN_STRING;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '-':
+ return JSON.TOKEN_NUMBER;
+ case ':':
+ return JSON.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 JSON.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 JSON.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 JSON.TOKEN_NULL;
+ }
+ }
+
+ return JSON.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 ((value is Boolean) && ((Boolean)value == true))
+ {
+ builder.Append("true");
+ }
+ else if ((value is Boolean) && ((Boolean)value == false))
+ {
+ builder.Append("false");
+ }
+ else if (value is ValueType)
+ {
+ // thanks to ritchie for pointing out ValueType to me
+ success = SerializeNumber(Convert.ToDouble(value), builder);
+ }
+ 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;
+ }
+ }
+}