您不能選擇超過 %s 個話題 話題必須以字母或數字為開頭,可包含連接號 ('-') 且最長為 35 個字
 
 
 

590 行
15 KiB

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Globalization;
  5. using System.Text;
  6. using System.Text.RegularExpressions;
  7. namespace Boomlagoon.JSON
  8. {
  9. public class JSONObject : IEnumerable<KeyValuePair<string, JSONValue>>, IEnumerable
  10. {
  11. public JSONObject()
  12. {
  13. }
  14. public JSONObject(JSONObject other)
  15. {
  16. this.values = new Dictionary<string, JSONValue>();
  17. if (other != null)
  18. {
  19. foreach (KeyValuePair<string, JSONValue> keyValuePair in other.values)
  20. {
  21. this.values[keyValuePair.Key] = new JSONValue(keyValuePair.Value);
  22. }
  23. }
  24. }
  25. public bool ContainsKey(string key)
  26. {
  27. return this.values.ContainsKey(key);
  28. }
  29. public JSONValue GetValue(string key)
  30. {
  31. JSONValue result;
  32. this.values.TryGetValue(key, out result);
  33. return result;
  34. }
  35. public string GetString(string key)
  36. {
  37. JSONValue value = this.GetValue(key);
  38. if (value == null)
  39. {
  40. JSONLogger.Error(key + "(string) == null");
  41. return string.Empty;
  42. }
  43. return value.Str;
  44. }
  45. public double GetNumber(string key)
  46. {
  47. JSONValue value = this.GetValue(key);
  48. if (value == null)
  49. {
  50. JSONLogger.Error(key + " == null");
  51. return double.NaN;
  52. }
  53. return value.Number;
  54. }
  55. public JSONObject GetObject(string key)
  56. {
  57. JSONValue value = this.GetValue(key);
  58. if (value == null)
  59. {
  60. JSONLogger.Error(key + " == null");
  61. return null;
  62. }
  63. return value.Obj;
  64. }
  65. public bool GetBoolean(string key)
  66. {
  67. JSONValue value = this.GetValue(key);
  68. if (value == null)
  69. {
  70. JSONLogger.Error(key + " == null");
  71. return false;
  72. }
  73. return value.Boolean;
  74. }
  75. public JSONArray GetArray(string key)
  76. {
  77. JSONValue value = this.GetValue(key);
  78. if (value == null)
  79. {
  80. JSONLogger.Error(key + " == null");
  81. return null;
  82. }
  83. return value.Array;
  84. }
  85. public JSONValue this[string key]
  86. {
  87. get
  88. {
  89. return this.GetValue(key);
  90. }
  91. set
  92. {
  93. this.values[key] = value;
  94. }
  95. }
  96. public void Add(string key, JSONValue value)
  97. {
  98. this.values[key] = value;
  99. }
  100. public void Add(KeyValuePair<string, JSONValue> pair)
  101. {
  102. this.values[pair.Key] = pair.Value;
  103. }
  104. public static JSONObject Parse(string jsonString)
  105. {
  106. if (string.IsNullOrEmpty(jsonString))
  107. {
  108. return null;
  109. }
  110. JSONValue jsonvalue = null;
  111. List<string> list = new List<string>();
  112. JSONObject.JSONParsingState jsonparsingState = JSONObject.JSONParsingState.Object;
  113. for (int i = 0; i < jsonString.Length; i++)
  114. {
  115. i = JSONObject.SkipWhitespace(jsonString, i);
  116. switch (jsonparsingState)
  117. {
  118. case JSONObject.JSONParsingState.Object:
  119. {
  120. if (jsonString[i] != '{')
  121. {
  122. return JSONObject.Fail('{', i);
  123. }
  124. JSONValue jsonvalue2 = new JSONObject();
  125. if (jsonvalue != null)
  126. {
  127. jsonvalue2.Parent = jsonvalue;
  128. }
  129. jsonvalue = jsonvalue2;
  130. jsonparsingState = JSONObject.JSONParsingState.Key;
  131. break;
  132. }
  133. case JSONObject.JSONParsingState.Array:
  134. {
  135. if (jsonString[i] != '[')
  136. {
  137. return JSONObject.Fail('[', i);
  138. }
  139. JSONValue jsonvalue3 = new JSONArray();
  140. if (jsonvalue != null)
  141. {
  142. jsonvalue3.Parent = jsonvalue;
  143. }
  144. jsonvalue = jsonvalue3;
  145. jsonparsingState = JSONObject.JSONParsingState.Value;
  146. break;
  147. }
  148. case JSONObject.JSONParsingState.EndObject:
  149. {
  150. if (jsonString[i] != '}')
  151. {
  152. return JSONObject.Fail('}', i);
  153. }
  154. if (jsonvalue.Parent == null)
  155. {
  156. return jsonvalue.Obj;
  157. }
  158. JSONValueType type = jsonvalue.Parent.Type;
  159. if (type != JSONValueType.Object)
  160. {
  161. if (type != JSONValueType.Array)
  162. {
  163. return JSONObject.Fail("valid object", i);
  164. }
  165. jsonvalue.Parent.Array.Add(new JSONValue(jsonvalue.Obj));
  166. }
  167. else
  168. {
  169. jsonvalue.Parent.Obj.values[list.Pop<string>()] = new JSONValue(jsonvalue.Obj);
  170. }
  171. jsonvalue = jsonvalue.Parent;
  172. jsonparsingState = JSONObject.JSONParsingState.ValueSeparator;
  173. break;
  174. }
  175. case JSONObject.JSONParsingState.EndArray:
  176. {
  177. if (jsonString[i] != ']')
  178. {
  179. return JSONObject.Fail(']', i);
  180. }
  181. if (jsonvalue.Parent == null)
  182. {
  183. return jsonvalue.Obj;
  184. }
  185. JSONValueType type2 = jsonvalue.Parent.Type;
  186. if (type2 != JSONValueType.Object)
  187. {
  188. if (type2 != JSONValueType.Array)
  189. {
  190. return JSONObject.Fail("valid object", i);
  191. }
  192. jsonvalue.Parent.Array.Add(new JSONValue(jsonvalue.Array));
  193. }
  194. else
  195. {
  196. jsonvalue.Parent.Obj.values[list.Pop<string>()] = new JSONValue(jsonvalue.Array);
  197. }
  198. jsonvalue = jsonvalue.Parent;
  199. jsonparsingState = JSONObject.JSONParsingState.ValueSeparator;
  200. break;
  201. }
  202. case JSONObject.JSONParsingState.Key:
  203. if (jsonString[i] == '}')
  204. {
  205. i--;
  206. jsonparsingState = JSONObject.JSONParsingState.EndObject;
  207. }
  208. else
  209. {
  210. string text = JSONObject.ParseString(jsonString, ref i);
  211. if (text == null)
  212. {
  213. return JSONObject.Fail("key string", i);
  214. }
  215. list.Add(text);
  216. jsonparsingState = JSONObject.JSONParsingState.KeyValueSeparator;
  217. }
  218. break;
  219. case JSONObject.JSONParsingState.Value:
  220. {
  221. char c = jsonString[i];
  222. if (c == '"')
  223. {
  224. jsonparsingState = JSONObject.JSONParsingState.String;
  225. }
  226. else if (char.IsDigit(c) || c == '-')
  227. {
  228. jsonparsingState = JSONObject.JSONParsingState.Number;
  229. }
  230. else
  231. {
  232. switch (c)
  233. {
  234. case '[':
  235. jsonparsingState = JSONObject.JSONParsingState.Array;
  236. break;
  237. default:
  238. if (c != 'f')
  239. {
  240. if (c == 'n')
  241. {
  242. jsonparsingState = JSONObject.JSONParsingState.Null;
  243. break;
  244. }
  245. if (c != 't')
  246. {
  247. if (c != '{')
  248. {
  249. return JSONObject.Fail("beginning of value", i);
  250. }
  251. jsonparsingState = JSONObject.JSONParsingState.Object;
  252. break;
  253. }
  254. }
  255. jsonparsingState = JSONObject.JSONParsingState.Boolean;
  256. break;
  257. case ']':
  258. if (jsonvalue.Type != JSONValueType.Array)
  259. {
  260. return JSONObject.Fail("valid array", i);
  261. }
  262. jsonparsingState = JSONObject.JSONParsingState.EndArray;
  263. break;
  264. }
  265. }
  266. i--;
  267. break;
  268. }
  269. case JSONObject.JSONParsingState.KeyValueSeparator:
  270. if (jsonString[i] != ':')
  271. {
  272. return JSONObject.Fail(':', i);
  273. }
  274. jsonparsingState = JSONObject.JSONParsingState.Value;
  275. break;
  276. case JSONObject.JSONParsingState.ValueSeparator:
  277. {
  278. char c2 = jsonString[i];
  279. if (c2 != ',')
  280. {
  281. if (c2 != ']')
  282. {
  283. if (c2 != '}')
  284. {
  285. return JSONObject.Fail(", } ]", i);
  286. }
  287. jsonparsingState = JSONObject.JSONParsingState.EndObject;
  288. i--;
  289. }
  290. else
  291. {
  292. jsonparsingState = JSONObject.JSONParsingState.EndArray;
  293. i--;
  294. }
  295. }
  296. else
  297. {
  298. jsonparsingState = ((jsonvalue.Type != JSONValueType.Object) ? JSONObject.JSONParsingState.Value : JSONObject.JSONParsingState.Key);
  299. }
  300. break;
  301. }
  302. case JSONObject.JSONParsingState.String:
  303. {
  304. string text2 = JSONObject.ParseString(jsonString, ref i);
  305. if (text2 == null)
  306. {
  307. return JSONObject.Fail("string value", i);
  308. }
  309. JSONValueType type3 = jsonvalue.Type;
  310. if (type3 != JSONValueType.Object)
  311. {
  312. if (type3 != JSONValueType.Array)
  313. {
  314. JSONLogger.Error("Fatal error, current JSON value not valid");
  315. return null;
  316. }
  317. jsonvalue.Array.Add(text2);
  318. }
  319. else
  320. {
  321. jsonvalue.Obj.values[list.Pop<string>()] = new JSONValue(text2);
  322. }
  323. jsonparsingState = JSONObject.JSONParsingState.ValueSeparator;
  324. break;
  325. }
  326. case JSONObject.JSONParsingState.Number:
  327. {
  328. double num = JSONObject.ParseNumber(jsonString, ref i);
  329. if (double.IsNaN(num))
  330. {
  331. return JSONObject.Fail("valid number", i);
  332. }
  333. JSONValueType type4 = jsonvalue.Type;
  334. if (type4 != JSONValueType.Object)
  335. {
  336. if (type4 != JSONValueType.Array)
  337. {
  338. JSONLogger.Error("Fatal error, current JSON value not valid");
  339. return null;
  340. }
  341. jsonvalue.Array.Add(num);
  342. }
  343. else
  344. {
  345. jsonvalue.Obj.values[list.Pop<string>()] = new JSONValue(num);
  346. }
  347. jsonparsingState = JSONObject.JSONParsingState.ValueSeparator;
  348. break;
  349. }
  350. case JSONObject.JSONParsingState.Boolean:
  351. if (jsonString[i] == 't')
  352. {
  353. if (jsonString.Length < i + 4 || jsonString[i + 1] != 'r' || jsonString[i + 2] != 'u' || jsonString[i + 3] != 'e')
  354. {
  355. return JSONObject.Fail("true", i);
  356. }
  357. JSONValueType type5 = jsonvalue.Type;
  358. if (type5 != JSONValueType.Object)
  359. {
  360. if (type5 != JSONValueType.Array)
  361. {
  362. JSONLogger.Error("Fatal error, current JSON value not valid");
  363. return null;
  364. }
  365. jsonvalue.Array.Add(new JSONValue(true));
  366. }
  367. else
  368. {
  369. jsonvalue.Obj.values[list.Pop<string>()] = new JSONValue(true);
  370. }
  371. i += 3;
  372. }
  373. else
  374. {
  375. if (jsonString.Length < i + 5 || jsonString[i + 1] != 'a' || jsonString[i + 2] != 'l' || jsonString[i + 3] != 's' || jsonString[i + 4] != 'e')
  376. {
  377. return JSONObject.Fail("false", i);
  378. }
  379. JSONValueType type6 = jsonvalue.Type;
  380. if (type6 != JSONValueType.Object)
  381. {
  382. if (type6 != JSONValueType.Array)
  383. {
  384. JSONLogger.Error("Fatal error, current JSON value not valid");
  385. return null;
  386. }
  387. jsonvalue.Array.Add(new JSONValue(false));
  388. }
  389. else
  390. {
  391. jsonvalue.Obj.values[list.Pop<string>()] = new JSONValue(false);
  392. }
  393. i += 4;
  394. }
  395. jsonparsingState = JSONObject.JSONParsingState.ValueSeparator;
  396. break;
  397. case JSONObject.JSONParsingState.Null:
  398. if (jsonString[i] == 'n')
  399. {
  400. if (jsonString.Length < i + 4 || jsonString[i + 1] != 'u' || jsonString[i + 2] != 'l' || jsonString[i + 3] != 'l')
  401. {
  402. return JSONObject.Fail("null", i);
  403. }
  404. JSONValueType type7 = jsonvalue.Type;
  405. if (type7 != JSONValueType.Object)
  406. {
  407. if (type7 != JSONValueType.Array)
  408. {
  409. JSONLogger.Error("Fatal error, current JSON value not valid");
  410. return null;
  411. }
  412. jsonvalue.Array.Add(new JSONValue(JSONValueType.Null));
  413. }
  414. else
  415. {
  416. jsonvalue.Obj.values[list.Pop<string>()] = new JSONValue(JSONValueType.Null);
  417. }
  418. i += 3;
  419. }
  420. jsonparsingState = JSONObject.JSONParsingState.ValueSeparator;
  421. break;
  422. }
  423. }
  424. JSONLogger.Error("Unexpected end of string");
  425. return null;
  426. }
  427. private static int SkipWhitespace(string str, int pos)
  428. {
  429. while (pos < str.Length && char.IsWhiteSpace(str[pos]))
  430. {
  431. pos++;
  432. }
  433. return pos;
  434. }
  435. private static string ParseString(string str, ref int startPosition)
  436. {
  437. if (str[startPosition] != '"' || startPosition + 1 >= str.Length)
  438. {
  439. JSONObject.Fail('"', startPosition);
  440. return null;
  441. }
  442. int num = str.IndexOf('"', startPosition + 1);
  443. if (num <= startPosition)
  444. {
  445. JSONObject.Fail('"', startPosition + 1);
  446. return null;
  447. }
  448. while (str[num - 1] == '\\')
  449. {
  450. num = str.IndexOf('"', num + 1);
  451. if (num <= startPosition)
  452. {
  453. JSONObject.Fail('"', startPosition + 1);
  454. return null;
  455. }
  456. }
  457. string text = string.Empty;
  458. if (num > startPosition + 1)
  459. {
  460. text = str.Substring(startPosition + 1, num - startPosition - 1);
  461. }
  462. startPosition = num;
  463. for (;;)
  464. {
  465. Match match = JSONObject.unicodeRegex.Match(text);
  466. if (!match.Success)
  467. {
  468. break;
  469. }
  470. string text2 = match.Groups[1].Captures[0].Value;
  471. JSONObject.unicodeBytes[1] = byte.Parse(text2.Substring(0, 2), NumberStyles.HexNumber);
  472. JSONObject.unicodeBytes[0] = byte.Parse(text2.Substring(2, 2), NumberStyles.HexNumber);
  473. text2 = Encoding.Unicode.GetString(JSONObject.unicodeBytes, 0, JSONObject.unicodeBytes.Length);
  474. text = text.Replace(match.Value, text2);
  475. }
  476. return text;
  477. }
  478. private static double ParseNumber(string str, ref int startPosition)
  479. {
  480. if (startPosition >= str.Length || (!char.IsDigit(str[startPosition]) && str[startPosition] != '-'))
  481. {
  482. return double.NaN;
  483. }
  484. int num = startPosition + 1;
  485. while (num < str.Length && str[num] != ',' && str[num] != ']' && str[num] != '}')
  486. {
  487. num++;
  488. }
  489. double result;
  490. if (!double.TryParse(str.Substring(startPosition, num - startPosition), NumberStyles.Float, CultureInfo.InvariantCulture, out result))
  491. {
  492. return double.NaN;
  493. }
  494. startPosition = num - 1;
  495. return result;
  496. }
  497. private static JSONObject Fail(char expected, int position)
  498. {
  499. return JSONObject.Fail(new string(expected, 1), position);
  500. }
  501. private static JSONObject Fail(string expected, int position)
  502. {
  503. JSONLogger.Error(string.Format("Invalid json string, expecting {0} at {1}", expected, position));
  504. return null;
  505. }
  506. public override string ToString()
  507. {
  508. StringBuilder stringBuilder = new StringBuilder();
  509. stringBuilder.Append('{');
  510. foreach (KeyValuePair<string, JSONValue> keyValuePair in this.values)
  511. {
  512. stringBuilder.Append("\"" + keyValuePair.Key + "\"");
  513. stringBuilder.Append(':');
  514. stringBuilder.Append(keyValuePair.Value.ToString());
  515. stringBuilder.Append(',');
  516. }
  517. if (this.values.Count > 0)
  518. {
  519. stringBuilder.Remove(stringBuilder.Length - 1, 1);
  520. }
  521. stringBuilder.Append('}');
  522. return stringBuilder.ToString();
  523. }
  524. public IEnumerator<KeyValuePair<string, JSONValue>> GetEnumerator()
  525. {
  526. return this.values.GetEnumerator();
  527. }
  528. IEnumerator IEnumerable.GetEnumerator()
  529. {
  530. return this.values.GetEnumerator();
  531. }
  532. public void Clear()
  533. {
  534. this.values.Clear();
  535. }
  536. public void Remove(string key)
  537. {
  538. if (this.values.ContainsKey(key))
  539. {
  540. this.values.Remove(key);
  541. }
  542. }
  543. private readonly IDictionary<string, JSONValue> values = new Dictionary<string, JSONValue>();
  544. private static readonly Regex unicodeRegex = new Regex("\\\\u([0-9a-fA-F]{4})");
  545. private static readonly byte[] unicodeBytes = new byte[2];
  546. private enum JSONParsingState
  547. {
  548. Object,
  549. Array,
  550. EndObject,
  551. EndArray,
  552. Key,
  553. Value,
  554. KeyValueSeparator,
  555. ValueSeparator,
  556. String,
  557. Number,
  558. Boolean,
  559. Null
  560. }
  561. }
  562. }