PageRenderTime 75ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/SDK/api/CSharp/fastJSON/JsonParser.cs

https://bitbucket.org/ehvattum/draugr_contrib
C# | 438 lines | 391 code | 40 blank | 7 comment | 24 complexity | 691d86369c37c7c72ee19a86d966933a MD5 | raw file
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Globalization;
  5. using System.Text;
  6. namespace fastJSON
  7. {
  8. /// <summary>
  9. /// This class encodes and decodes JSON strings.
  10. /// Spec. details, see http://www.json.org/
  11. /// </summary>
  12. internal sealed class JsonParser
  13. {
  14. enum Token
  15. {
  16. None = -1, // Used to denote no Lookahead available
  17. Curly_Open,
  18. Curly_Close,
  19. Squared_Open,
  20. Squared_Close,
  21. Colon,
  22. Comma,
  23. String,
  24. Number,
  25. True,
  26. False,
  27. Null
  28. }
  29. readonly char[] json;
  30. readonly StringBuilder s = new StringBuilder();
  31. Token lookAheadToken = Token.None;
  32. int index;
  33. bool _ignorecase = false;
  34. internal JsonParser(string json, bool ignorecase)
  35. {
  36. this.json = json.ToCharArray();
  37. _ignorecase = ignorecase;
  38. }
  39. public object Decode()
  40. {
  41. return ParseValue();
  42. }
  43. private Dictionary<string, object> ParseObject()
  44. {
  45. Dictionary<string, object> table = new Dictionary<string, object>();
  46. ConsumeToken(); // {
  47. while (true)
  48. {
  49. switch (LookAhead())
  50. {
  51. case Token.Comma:
  52. ConsumeToken();
  53. break;
  54. case Token.Curly_Close:
  55. ConsumeToken();
  56. return table;
  57. default:
  58. {
  59. // name
  60. string name = ParseString();
  61. if (_ignorecase)
  62. name = name.ToLower();
  63. // :
  64. if (NextToken() != Token.Colon)
  65. {
  66. throw new Exception("Expected colon at index " + index);
  67. }
  68. // value
  69. object value = ParseValue();
  70. table[name] = value;
  71. }
  72. break;
  73. }
  74. }
  75. }
  76. private List<object> ParseArray()
  77. {
  78. List<object> array = new List<object>();
  79. ConsumeToken(); // [
  80. while (true)
  81. {
  82. switch (LookAhead())
  83. {
  84. case Token.Comma:
  85. ConsumeToken();
  86. break;
  87. case Token.Squared_Close:
  88. ConsumeToken();
  89. return array;
  90. default:
  91. array.Add(ParseValue());
  92. break;
  93. }
  94. }
  95. }
  96. private object ParseValue()
  97. {
  98. switch (LookAhead())
  99. {
  100. case Token.Number:
  101. return ParseNumber();
  102. case Token.String:
  103. return ParseString();
  104. case Token.Curly_Open:
  105. return ParseObject();
  106. case Token.Squared_Open:
  107. return ParseArray();
  108. case Token.True:
  109. ConsumeToken();
  110. return true;
  111. case Token.False:
  112. ConsumeToken();
  113. return false;
  114. case Token.Null:
  115. ConsumeToken();
  116. return null;
  117. }
  118. throw new Exception("Unrecognized token at index" + index);
  119. }
  120. private string ParseString()
  121. {
  122. ConsumeToken(); // "
  123. s.Length = 0;
  124. int runIndex = -1;
  125. while (index < json.Length)
  126. {
  127. var c = json[index++];
  128. if (c == '"')
  129. {
  130. if (runIndex != -1)
  131. {
  132. if (s.Length == 0)
  133. return new string(json, runIndex, index - runIndex - 1);
  134. s.Append(json, runIndex, index - runIndex - 1);
  135. }
  136. return s.ToString();
  137. }
  138. if (c != '\\')
  139. {
  140. if (runIndex == -1)
  141. runIndex = index - 1;
  142. continue;
  143. }
  144. if (index == json.Length) break;
  145. if (runIndex != -1)
  146. {
  147. s.Append(json, runIndex, index - runIndex - 1);
  148. runIndex = -1;
  149. }
  150. switch (json[index++])
  151. {
  152. case '"':
  153. s.Append('"');
  154. break;
  155. case '\\':
  156. s.Append('\\');
  157. break;
  158. case '/':
  159. s.Append('/');
  160. break;
  161. case 'b':
  162. s.Append('\b');
  163. break;
  164. case 'f':
  165. s.Append('\f');
  166. break;
  167. case 'n':
  168. s.Append('\n');
  169. break;
  170. case 'r':
  171. s.Append('\r');
  172. break;
  173. case 't':
  174. s.Append('\t');
  175. break;
  176. case 'u':
  177. {
  178. int remainingLength = json.Length - index;
  179. if (remainingLength < 4) break;
  180. // parse the 32 bit hex into an integer codepoint
  181. uint codePoint = ParseUnicode(json[index], json[index + 1], json[index + 2], json[index + 3]);
  182. s.Append((char)codePoint);
  183. // skip 4 chars
  184. index += 4;
  185. }
  186. break;
  187. }
  188. }
  189. throw new Exception("Unexpectedly reached end of string");
  190. }
  191. private uint ParseSingleChar(char c1, uint multipliyer)
  192. {
  193. uint p1 = 0;
  194. if (c1 >= '0' && c1 <= '9')
  195. p1 = (uint)(c1 - '0') * multipliyer;
  196. else if (c1 >= 'A' && c1 <= 'F')
  197. p1 = (uint)((c1 - 'A') + 10) * multipliyer;
  198. else if (c1 >= 'a' && c1 <= 'f')
  199. p1 = (uint)((c1 - 'a') + 10) * multipliyer;
  200. return p1;
  201. }
  202. private uint ParseUnicode(char c1, char c2, char c3, char c4)
  203. {
  204. uint p1 = ParseSingleChar(c1, 0x1000);
  205. uint p2 = ParseSingleChar(c2, 0x100);
  206. uint p3 = ParseSingleChar(c3, 0x10);
  207. uint p4 = ParseSingleChar(c4, 1);
  208. return p1 + p2 + p3 + p4;
  209. }
  210. private long CreateLong(string s)
  211. {
  212. long num = 0;
  213. bool neg = false;
  214. foreach (char cc in s)
  215. {
  216. if (cc == '-')
  217. neg = true;
  218. else if (cc == '+')
  219. neg = false;
  220. else
  221. {
  222. num *= 10;
  223. num += (int)(cc - '0');
  224. }
  225. }
  226. return neg ? -num : num;
  227. }
  228. private object ParseNumber()
  229. {
  230. ConsumeToken();
  231. // Need to start back one place because the first digit is also a token and would have been consumed
  232. var startIndex = index - 1;
  233. bool dec = false;
  234. do
  235. {
  236. if (index == json.Length)
  237. break;
  238. var c = json[index];
  239. if ((c >= '0' && c <= '9') || c == '.' || c == '-' || c == '+' || c == 'e' || c == 'E')
  240. {
  241. if (c == '.' || c == 'e' || c == 'E')
  242. dec = true;
  243. if (++index == json.Length)
  244. break; //throw new Exception("Unexpected end of string whilst parsing number");
  245. continue;
  246. }
  247. break;
  248. } while (true);
  249. string s = new string(json, startIndex, index - startIndex);
  250. if (dec)
  251. return double.Parse(s,NumberFormatInfo.InvariantInfo);
  252. return CreateLong(s);
  253. }
  254. private Token LookAhead()
  255. {
  256. if (lookAheadToken != Token.None) return lookAheadToken;
  257. return lookAheadToken = NextTokenCore();
  258. }
  259. private void ConsumeToken()
  260. {
  261. lookAheadToken = Token.None;
  262. }
  263. private Token NextToken()
  264. {
  265. var result = lookAheadToken != Token.None ? lookAheadToken : NextTokenCore();
  266. lookAheadToken = Token.None;
  267. return result;
  268. }
  269. private Token NextTokenCore()
  270. {
  271. char c;
  272. // Skip past whitespace
  273. do
  274. {
  275. c = json[index];
  276. if (c > ' ') break;
  277. if (c != ' ' && c != '\t' && c != '\n' && c != '\r') break;
  278. } while (++index < json.Length);
  279. if (index == json.Length)
  280. {
  281. throw new Exception("Reached end of string unexpectedly");
  282. }
  283. c = json[index];
  284. index++;
  285. //if (c >= '0' && c <= '9')
  286. // return Token.Number;
  287. switch (c)
  288. {
  289. case '{':
  290. return Token.Curly_Open;
  291. case '}':
  292. return Token.Curly_Close;
  293. case '[':
  294. return Token.Squared_Open;
  295. case ']':
  296. return Token.Squared_Close;
  297. case ',':
  298. return Token.Comma;
  299. case '"':
  300. return Token.String;
  301. case '0':
  302. case '1':
  303. case '2':
  304. case '3':
  305. case '4':
  306. case '5':
  307. case '6':
  308. case '7':
  309. case '8':
  310. case '9':
  311. case '-':
  312. case '+':
  313. case '.':
  314. return Token.Number;
  315. case ':':
  316. return Token.Colon;
  317. case 'f':
  318. if (json.Length - index >= 4 &&
  319. json[index + 0] == 'a' &&
  320. json[index + 1] == 'l' &&
  321. json[index + 2] == 's' &&
  322. json[index + 3] == 'e')
  323. {
  324. index += 4;
  325. return Token.False;
  326. }
  327. break;
  328. case 't':
  329. if (json.Length - index >= 3 &&
  330. json[index + 0] == 'r' &&
  331. json[index + 1] == 'u' &&
  332. json[index + 2] == 'e')
  333. {
  334. index += 3;
  335. return Token.True;
  336. }
  337. break;
  338. case 'n':
  339. if (json.Length - index >= 3 &&
  340. json[index + 0] == 'u' &&
  341. json[index + 1] == 'l' &&
  342. json[index + 2] == 'l')
  343. {
  344. index += 3;
  345. return Token.Null;
  346. }
  347. break;
  348. }
  349. throw new Exception("Could not find token at index " + --index);
  350. }
  351. }
  352. }