PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/Rusty/Common/SimpleJson/Decode.cs

http://github.com/polyethene/IronAHK
C# | 265 lines | 225 code | 35 blank | 5 comment | 94 complexity | 15b64d5816f7f8b1d94d6618e9a1acf6 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. namespace IronAHK.Rusty.Common
  5. {
  6. partial class SimpleJson
  7. {
  8. /// <summary>
  9. /// Convert a JSON string to a dictionary of string key and object value pairs.
  10. /// </summary>
  11. /// <param name="Source">The JSON string to evaluate.</param>
  12. /// <returns>A <see cref="System.Collections.Generic.Dictionary&lt;TKey, TValue&gt;"/>.</returns>
  13. public static Dictionary<string, object> Decode(string Source)
  14. {
  15. var data = new Dictionary<string, object>();
  16. int pointer = 0;
  17. DecodeObject(ref data, Scan(Source, ref pointer, ObjectClose));
  18. return data;
  19. }
  20. static string Scan(string node, ref int i, char anchor)
  21. {
  22. int start = i + 1, skip = 1;
  23. bool inStr = false;
  24. while (++i < node.Length)
  25. {
  26. char token = node[i];
  27. if ((token == StringBoundary || token == StringBoundaryAlt) && node[i - 1] != Escape)
  28. inStr = !inStr;
  29. if ((anchor == ArrayClose && token == ArrayOpen) || (anchor == ObjectClose && token == ObjectOpen))
  30. skip++;
  31. else if ((anchor == StringBoundary || anchor == StringBoundaryAlt) && token == anchor)
  32. break;
  33. else if (!inStr && token == anchor)
  34. if (--skip == 0)
  35. break;
  36. if (i == node.Length)
  37. throw new Exception(ErrorMessage(ExUntermField, i));
  38. }
  39. return node.Substring(start, i - start);
  40. }
  41. static void Value(ref Dictionary<string, object> parent, ref string key)
  42. {
  43. object value = null;
  44. Value(ref parent, ref key, ref value);
  45. }
  46. static void Value(ref Dictionary<string, object> parent, ref string key, ref object value)
  47. {
  48. if (key.Length == 0)
  49. return;
  50. if (parent.ContainsKey(key))
  51. parent[key] = value;
  52. else parent.Add(key, value);
  53. key = string.Empty;
  54. value = null;
  55. }
  56. static bool IsNumber(char c)
  57. {
  58. return c == '+' || c == '-' || c == '.' || c == 'e' || c == 'E' || (c >= '0' && c <= '9');
  59. }
  60. static bool ExtractNumber(ref string node, ref int i, out object value)
  61. {
  62. var s = new StringBuilder();
  63. while (i < node.Length)
  64. {
  65. char c = node[i];
  66. if (IsNumber(c))
  67. s.Append(c);
  68. else
  69. break;
  70. i++;
  71. }
  72. value = null;
  73. double n;
  74. if (double.TryParse(s.ToString(), out n))
  75. {
  76. value = (((int)n)) == n ? (int)n : n;
  77. return true;
  78. }
  79. return false;
  80. }
  81. static bool ExtractBoolean(ref string node, ref int i, ref object value)
  82. {
  83. int r = node.Length - i + 1;
  84. if (r > Null.Length && string.Equals(node.Substring(i, Null.Length), Null, StringComparison.OrdinalIgnoreCase))
  85. {
  86. i += Null.Length;
  87. value = null;
  88. return true;
  89. }
  90. else if (r > True.Length && string.Equals(node.Substring(i, True.Length), True, StringComparison.OrdinalIgnoreCase))
  91. {
  92. i += True.Length;
  93. value = true;
  94. return true;
  95. }
  96. else if (r > False.Length && string.Equals(node.Substring(i, False.Length), False, StringComparison.OrdinalIgnoreCase))
  97. {
  98. i += False.Length;
  99. value = false;
  100. return true;
  101. }
  102. return false;
  103. }
  104. static object[] ParseArray(string node)
  105. {
  106. var list = new List<object>();
  107. object value = null;
  108. for (int i = 0; i < node.Length; i++)
  109. {
  110. char token = node[i];
  111. if (char.IsWhiteSpace(node, i))
  112. continue;
  113. switch (token)
  114. {
  115. case StringBoundary:
  116. value = Scan(node, ref i, StringBoundary);
  117. break;
  118. case StringBoundaryAlt:
  119. value = Scan(node, ref i, StringBoundaryAlt);
  120. break;
  121. case ObjectOpen:
  122. var sub = new Dictionary<string, object>();
  123. DecodeObject(ref sub, Scan(node, ref i, ObjectClose));
  124. value = sub;
  125. break;
  126. case ArrayOpen:
  127. value = ParseArray(Scan(node, ref i, ArrayClose));
  128. break;
  129. case MemberSeperator:
  130. list.Add(value);
  131. value = null;
  132. break;
  133. default:
  134. if (IsNumber(token))
  135. ExtractNumber(ref node, ref i, out value);
  136. else if (!ExtractBoolean(ref node, ref i, ref value))
  137. throw new Exception(ErrorMessage(ExNoMemberVal, i));
  138. break;
  139. }
  140. }
  141. if (node.Length != 0)
  142. list.Add(value);
  143. return list.ToArray();
  144. }
  145. static void DecodeObject(ref Dictionary<string, object> parent, string node)
  146. {
  147. string key = string.Empty;
  148. bool expectVal = false, next = true;
  149. for (int i = 0; i < node.Length; i++)
  150. {
  151. char token = node[i];
  152. if (char.IsWhiteSpace(token))
  153. continue;
  154. else if (expectVal)
  155. {
  156. object value = null;
  157. switch (token)
  158. {
  159. case StringBoundary:
  160. value = Scan(node, ref i, StringBoundary);
  161. break;
  162. case StringBoundaryAlt:
  163. value = Scan(node, ref i, StringBoundaryAlt);
  164. break;
  165. case ObjectOpen:
  166. var sub = new Dictionary<string, object>();
  167. DecodeObject(ref sub, Scan(node, ref i, ObjectClose));
  168. value = sub;
  169. break;
  170. case ArrayOpen:
  171. string s = Scan(node, ref i, ArrayClose);
  172. value = ParseArray(s);
  173. break;
  174. case MemberSeperator:
  175. value = null;
  176. next = true;
  177. break;
  178. default:
  179. if (IsNumber(token))
  180. ExtractNumber(ref node, ref i, out value);
  181. else if (!ExtractBoolean(ref node, ref i, ref value))
  182. throw new Exception(ErrorMessage(ExNoMemberVal, i));
  183. break;
  184. }
  185. Value(ref parent, ref key, ref value);
  186. expectVal = false;
  187. }
  188. else if (next)
  189. {
  190. next = false;
  191. if (token == StringBoundary)
  192. key = Scan(node, ref i, StringBoundary);
  193. else if (token == StringBoundaryAlt)
  194. key = Scan(node, ref i, StringBoundaryAlt);
  195. else
  196. {
  197. var keyip = new StringBuilder();
  198. do
  199. {
  200. char c = node[i];
  201. if (char.IsLetterOrDigit(c) || c == '_')
  202. keyip.Append(c);
  203. else
  204. break;
  205. i++;
  206. }
  207. while (i < node.Length);
  208. if (keyip.Length == 0)
  209. throw new Exception(ErrorMessage(ExNoKeyPair, i));
  210. else
  211. {
  212. key = keyip.ToString();
  213. i--;
  214. }
  215. }
  216. }
  217. else if (token == MemberAssign || token == MemberAssignAlt)
  218. expectVal = true;
  219. else if (token == MemberSeperator)
  220. {
  221. Value(ref parent, ref key);
  222. next = true;
  223. }
  224. else
  225. throw new Exception(ErrorMessage(ExUnexpectedToken, i));
  226. }
  227. Value(ref parent, ref key);
  228. }
  229. }
  230. }