Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 

746 rindas
16 KiB

  1. using System;
  2. using System.Collections;
  3. using System.Text;
  4. using System.Collections.Generic;
  5. namespace ETModel
  6. {
  7. /* Based on the JSON parser from
  8. * http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html
  9. *
  10. * I simplified it so that it doesn't throw exceptions
  11. * and can be used in Unity iPhone with maximum code stripping.
  12. */
  13. /// <summary>
  14. /// This class encodes and decodes JSON strings.
  15. /// Spec. details, see http://www.json.org/
  16. ///
  17. /// JSON uses Arrays and Objects. These correspond here to the datatypes ArrayList and Hashtable.
  18. /// All numbers are parsed to doubles.
  19. /// </summary>
  20. public class MiniJSON
  21. {
  22. private const int TOKEN_NONE = 0;
  23. private const int TOKEN_CURLY_OPEN = 1;
  24. private const int TOKEN_CURLY_CLOSE = 2;
  25. private const int TOKEN_SQUARED_OPEN = 3;
  26. private const int TOKEN_SQUARED_CLOSE = 4;
  27. private const int TOKEN_COLON = 5;
  28. private const int TOKEN_COMMA = 6;
  29. private const int TOKEN_STRING = 7;
  30. private const int TOKEN_NUMBER = 8;
  31. private const int TOKEN_TRUE = 9;
  32. private const int TOKEN_FALSE = 10;
  33. private const int TOKEN_NULL = 11;
  34. private const int BUILDER_CAPACITY = 2000;
  35. /// <summary>
  36. /// On decoding, this value holds the position at which the parse failed (-1 = no error).
  37. /// </summary>
  38. protected static int lastErrorIndex = -1;
  39. protected static string lastDecode = "";
  40. /// <summary>
  41. /// Parses the string json into a value
  42. /// </summary>
  43. /// <param name="json">A JSON string.</param>
  44. /// <returns>An ArrayList, a Hashtable, a double, a string, null, true, or false</returns>
  45. public static object jsonDecode(string json)
  46. {
  47. // save the string for debug information
  48. MiniJSON.lastDecode = json;
  49. if (json != null)
  50. {
  51. char[] charArray = json.ToCharArray();
  52. int index = 0;
  53. bool success = true;
  54. object value = MiniJSON.parseValue(charArray, ref index, ref success);
  55. if (success)
  56. MiniJSON.lastErrorIndex = -1;
  57. else
  58. MiniJSON.lastErrorIndex = index;
  59. return value;
  60. }
  61. else
  62. {
  63. return null;
  64. }
  65. }
  66. /// <summary>
  67. /// Converts a Hashtable / ArrayList / Dictionary(string,string) object into a JSON string
  68. /// </summary>
  69. /// <param name="json">A Hashtable / ArrayList</param>
  70. /// <returns>A JSON encoded string, or null if object 'json' is not serializable</returns>
  71. public static string jsonEncode(object json)
  72. {
  73. var builder = new StringBuilder(BUILDER_CAPACITY);
  74. var success = MiniJSON.serializeValue(json, builder);
  75. return (success ? builder.ToString() : null);
  76. }
  77. /// <summary>
  78. /// On decoding, this function returns the position at which the parse failed (-1 = no error).
  79. /// </summary>
  80. /// <returns></returns>
  81. public static bool lastDecodeSuccessful()
  82. {
  83. return (MiniJSON.lastErrorIndex == -1);
  84. }
  85. /// <summary>
  86. /// On decoding, this function returns the position at which the parse failed (-1 = no error).
  87. /// </summary>
  88. /// <returns></returns>
  89. public static int getLastErrorIndex()
  90. {
  91. return MiniJSON.lastErrorIndex;
  92. }
  93. /// <summary>
  94. /// If a decoding error occurred, this function returns a piece of the JSON string
  95. /// at which the error took place. To ease debugging.
  96. /// </summary>
  97. /// <returns></returns>
  98. public static string getLastErrorSnippet()
  99. {
  100. if (MiniJSON.lastErrorIndex == -1)
  101. {
  102. return "";
  103. }
  104. else
  105. {
  106. int startIndex = MiniJSON.lastErrorIndex - 5;
  107. int endIndex = MiniJSON.lastErrorIndex + 15;
  108. if (startIndex < 0)
  109. startIndex = 0;
  110. if (endIndex >= MiniJSON.lastDecode.Length)
  111. endIndex = MiniJSON.lastDecode.Length - 1;
  112. return MiniJSON.lastDecode.Substring(startIndex, endIndex - startIndex + 1);
  113. }
  114. }
  115. #region Parsing
  116. protected static Hashtable parseObject(char[] json, ref int index)
  117. {
  118. Hashtable table = new Hashtable();
  119. int token;
  120. // {
  121. nextToken(json, ref index);
  122. bool done = false;
  123. while (!done)
  124. {
  125. token = lookAhead(json, index);
  126. if (token == MiniJSON.TOKEN_NONE)
  127. {
  128. return null;
  129. }
  130. else if (token == MiniJSON.TOKEN_COMMA)
  131. {
  132. nextToken(json, ref index);
  133. }
  134. else if (token == MiniJSON.TOKEN_CURLY_CLOSE)
  135. {
  136. nextToken(json, ref index);
  137. return table;
  138. }
  139. else
  140. {
  141. // name
  142. string name = parseString(json, ref index);
  143. if (name == null)
  144. {
  145. return null;
  146. }
  147. // :
  148. token = nextToken(json, ref index);
  149. if (token != MiniJSON.TOKEN_COLON)
  150. return null;
  151. // value
  152. bool success = true;
  153. object value = parseValue(json, ref index, ref success);
  154. if (!success)
  155. return null;
  156. table[name] = value;
  157. }
  158. }
  159. return table;
  160. }
  161. protected static ArrayList parseArray(char[] json, ref int index)
  162. {
  163. ArrayList array = new ArrayList();
  164. // [
  165. nextToken(json, ref index);
  166. bool done = false;
  167. while (!done)
  168. {
  169. int token = lookAhead(json, index);
  170. if (token == MiniJSON.TOKEN_NONE)
  171. {
  172. return null;
  173. }
  174. else if (token == MiniJSON.TOKEN_COMMA)
  175. {
  176. nextToken(json, ref index);
  177. }
  178. else if (token == MiniJSON.TOKEN_SQUARED_CLOSE)
  179. {
  180. nextToken(json, ref index);
  181. break;
  182. }
  183. else
  184. {
  185. bool success = true;
  186. object value = parseValue(json, ref index, ref success);
  187. if (!success)
  188. return null;
  189. array.Add(value);
  190. }
  191. }
  192. return array;
  193. }
  194. protected static object parseValue(char[] json, ref int index, ref bool success)
  195. {
  196. switch (lookAhead(json, index))
  197. {
  198. case MiniJSON.TOKEN_STRING:
  199. return parseString(json, ref index);
  200. case MiniJSON.TOKEN_NUMBER:
  201. return parseNumber(json, ref index);
  202. case MiniJSON.TOKEN_CURLY_OPEN:
  203. return parseObject(json, ref index);
  204. case MiniJSON.TOKEN_SQUARED_OPEN:
  205. return parseArray(json, ref index);
  206. case MiniJSON.TOKEN_TRUE:
  207. nextToken(json, ref index);
  208. return Boolean.Parse("TRUE");
  209. case MiniJSON.TOKEN_FALSE:
  210. nextToken(json, ref index);
  211. return Boolean.Parse("FALSE");
  212. case MiniJSON.TOKEN_NULL:
  213. nextToken(json, ref index);
  214. return null;
  215. case MiniJSON.TOKEN_NONE:
  216. break;
  217. }
  218. success = false;
  219. return null;
  220. }
  221. protected static string parseString(char[] json, ref int index)
  222. {
  223. string s = "";
  224. char c;
  225. eatWhitespace(json, ref index);
  226. // "
  227. c = json[index++];
  228. bool complete = false;
  229. while (!complete)
  230. {
  231. if (index == json.Length)
  232. break;
  233. c = json[index++];
  234. if (c == '"')
  235. {
  236. complete = true;
  237. break;
  238. }
  239. else if (c == '\\')
  240. {
  241. if (index == json.Length)
  242. break;
  243. c = json[index++];
  244. if (c == '"')
  245. {
  246. s += '"';
  247. }
  248. else if (c == '\\')
  249. {
  250. s += '\\';
  251. }
  252. else if (c == '/')
  253. {
  254. s += '/';
  255. }
  256. else if (c == 'b')
  257. {
  258. s += '\b';
  259. }
  260. else if (c == 'f')
  261. {
  262. s += '\f';
  263. }
  264. else if (c == 'n')
  265. {
  266. s += '\n';
  267. }
  268. else if (c == 'r')
  269. {
  270. s += '\r';
  271. }
  272. else if (c == 't')
  273. {
  274. s += '\t';
  275. }
  276. else if (c == 'u')
  277. {
  278. int remainingLength = json.Length - index;
  279. if (remainingLength >= 4)
  280. {
  281. char[] unicodeCharArray = new char[4];
  282. Array.Copy(json, index, unicodeCharArray, 0, 4);
  283. uint codePoint = UInt32.Parse(new string(unicodeCharArray), System.Globalization.NumberStyles.HexNumber);
  284. // convert the integer codepoint to a unicode char and add to string
  285. s += Char.ConvertFromUtf32((int)codePoint);
  286. // skip 4 chars
  287. index += 4;
  288. }
  289. else
  290. {
  291. break;
  292. }
  293. }
  294. }
  295. else
  296. {
  297. s += c;
  298. }
  299. }
  300. if (!complete)
  301. return null;
  302. return s;
  303. }
  304. protected static double parseNumber(char[] json, ref int index)
  305. {
  306. eatWhitespace(json, ref index);
  307. int lastIndex = getLastIndexOfNumber(json, index);
  308. int charLength = (lastIndex - index) + 1;
  309. char[] numberCharArray = new char[charLength];
  310. Array.Copy(json, index, numberCharArray, 0, charLength);
  311. index = lastIndex + 1;
  312. return Double.Parse(new string(numberCharArray)); // , CultureInfo.InvariantCulture);
  313. }
  314. protected static int getLastIndexOfNumber(char[] json, int index)
  315. {
  316. int lastIndex;
  317. for (lastIndex = index; lastIndex < json.Length; lastIndex++)
  318. if ("0123456789+-.eE".IndexOf(json[lastIndex]) == -1)
  319. {
  320. break;
  321. }
  322. return lastIndex - 1;
  323. }
  324. protected static void eatWhitespace(char[] json, ref int index)
  325. {
  326. for (; index < json.Length; index++)
  327. if (" \t\n\r".IndexOf(json[index]) == -1)
  328. {
  329. break;
  330. }
  331. }
  332. protected static int lookAhead(char[] json, int index)
  333. {
  334. int saveIndex = index;
  335. return nextToken(json, ref saveIndex);
  336. }
  337. protected static int nextToken(char[] json, ref int index)
  338. {
  339. eatWhitespace(json, ref index);
  340. if (index == json.Length)
  341. {
  342. return MiniJSON.TOKEN_NONE;
  343. }
  344. char c = json[index];
  345. index++;
  346. switch (c)
  347. {
  348. case '{':
  349. return MiniJSON.TOKEN_CURLY_OPEN;
  350. case '}':
  351. return MiniJSON.TOKEN_CURLY_CLOSE;
  352. case '[':
  353. return MiniJSON.TOKEN_SQUARED_OPEN;
  354. case ']':
  355. return MiniJSON.TOKEN_SQUARED_CLOSE;
  356. case ',':
  357. return MiniJSON.TOKEN_COMMA;
  358. case '"':
  359. return MiniJSON.TOKEN_STRING;
  360. case '0':
  361. case '1':
  362. case '2':
  363. case '3':
  364. case '4':
  365. case '5':
  366. case '6':
  367. case '7':
  368. case '8':
  369. case '9':
  370. case '-':
  371. return MiniJSON.TOKEN_NUMBER;
  372. case ':':
  373. return MiniJSON.TOKEN_COLON;
  374. }
  375. index--;
  376. int remainingLength = json.Length - index;
  377. // false
  378. if (remainingLength >= 5)
  379. {
  380. if (json[index] == 'f' &&
  381. json[index + 1] == 'a' &&
  382. json[index + 2] == 'l' &&
  383. json[index + 3] == 's' &&
  384. json[index + 4] == 'e')
  385. {
  386. index += 5;
  387. return MiniJSON.TOKEN_FALSE;
  388. }
  389. }
  390. // true
  391. if (remainingLength >= 4)
  392. {
  393. if (json[index] == 't' &&
  394. json[index + 1] == 'r' &&
  395. json[index + 2] == 'u' &&
  396. json[index + 3] == 'e')
  397. {
  398. index += 4;
  399. return MiniJSON.TOKEN_TRUE;
  400. }
  401. }
  402. // null
  403. if (remainingLength >= 4)
  404. {
  405. if (json[index] == 'n' &&
  406. json[index + 1] == 'u' &&
  407. json[index + 2] == 'l' &&
  408. json[index + 3] == 'l')
  409. {
  410. index += 4;
  411. return MiniJSON.TOKEN_NULL;
  412. }
  413. }
  414. return MiniJSON.TOKEN_NONE;
  415. }
  416. #endregion
  417. #region Serialization
  418. protected static bool serializeObjectOrArray(object objectOrArray, StringBuilder builder)
  419. {
  420. if (objectOrArray is Hashtable)
  421. {
  422. return serializeObject((Hashtable)objectOrArray, builder);
  423. }
  424. else if (objectOrArray is ArrayList)
  425. {
  426. return serializeArray((ArrayList)objectOrArray, builder);
  427. }
  428. else
  429. {
  430. return false;
  431. }
  432. }
  433. protected static bool serializeObject(Hashtable anObject, StringBuilder builder)
  434. {
  435. builder.Append("{");
  436. IDictionaryEnumerator e = anObject.GetEnumerator();
  437. bool first = true;
  438. while (e.MoveNext())
  439. {
  440. string key = e.Key.ToString();
  441. object value = e.Value;
  442. if (!first)
  443. {
  444. builder.Append(", ");
  445. }
  446. serializeString(key, builder);
  447. builder.Append(":");
  448. if (!serializeValue(value, builder))
  449. {
  450. return false;
  451. }
  452. first = false;
  453. }
  454. builder.Append("}");
  455. return true;
  456. }
  457. protected static bool serializeDictionary(Dictionary<string, string> dict, StringBuilder builder)
  458. {
  459. builder.Append("{");
  460. bool first = true;
  461. foreach (var kv in dict)
  462. {
  463. if (!first)
  464. builder.Append(", ");
  465. serializeString(kv.Key, builder);
  466. builder.Append(":");
  467. serializeString(kv.Value, builder);
  468. first = false;
  469. }
  470. builder.Append("}");
  471. return true;
  472. }
  473. protected static bool serializeArray(ArrayList anArray, StringBuilder builder)
  474. {
  475. builder.Append("[");
  476. bool first = true;
  477. for (int i = 0; i < anArray.Count; i++)
  478. {
  479. object value = anArray[i];
  480. if (!first)
  481. {
  482. builder.Append(", ");
  483. }
  484. if (!serializeValue(value, builder))
  485. {
  486. return false;
  487. }
  488. first = false;
  489. }
  490. builder.Append("]");
  491. return true;
  492. }
  493. protected static bool serializeValue(object value, StringBuilder builder)
  494. {
  495. //Type t = value.GetType();
  496. //UnityEngine.Debug.Log("type: " + t.ToString() + " isArray: " + t.IsArray);
  497. if (value == null)
  498. {
  499. builder.Append("null");
  500. }
  501. else if (value.GetType().IsArray)
  502. {
  503. serializeArray(new ArrayList((ICollection)value), builder);
  504. }
  505. else if (value is string)
  506. {
  507. serializeString((string)value, builder);
  508. }
  509. else if (value is Char)
  510. {
  511. serializeString(Convert.ToString((char)value), builder);
  512. }
  513. else if (value is decimal)
  514. {
  515. serializeString(Convert.ToString((decimal)value), builder);
  516. }
  517. else if (value is Hashtable)
  518. {
  519. serializeObject((Hashtable)value, builder);
  520. }
  521. else if (value is Dictionary<string, string>)
  522. {
  523. serializeDictionary((Dictionary<string, string>)value, builder);
  524. }
  525. else if (value is ArrayList)
  526. {
  527. serializeArray((ArrayList)value, builder);
  528. }
  529. else if ((value is Boolean) && ((Boolean)value == true))
  530. {
  531. builder.Append("true");
  532. }
  533. else if ((value is Boolean) && ((Boolean)value == false))
  534. {
  535. builder.Append("false");
  536. }
  537. else if (value.GetType().IsPrimitive)
  538. {
  539. serializeNumber(Convert.ToDouble(value), builder);
  540. }
  541. else
  542. {
  543. return false;
  544. }
  545. return true;
  546. }
  547. protected static void serializeString(string aString, StringBuilder builder)
  548. {
  549. builder.Append("\"");
  550. char[] charArray = aString.ToCharArray();
  551. for (int i = 0; i < charArray.Length; i++)
  552. {
  553. char c = charArray[i];
  554. if (c == '"')
  555. {
  556. builder.Append("\\\"");
  557. }
  558. else if (c == '\\')
  559. {
  560. builder.Append("\\\\");
  561. }
  562. else if (c == '\b')
  563. {
  564. builder.Append("\\b");
  565. }
  566. else if (c == '\f')
  567. {
  568. builder.Append("\\f");
  569. }
  570. else if (c == '\n')
  571. {
  572. builder.Append("\\n");
  573. }
  574. else if (c == '\r')
  575. {
  576. builder.Append("\\r");
  577. }
  578. else if (c == '\t')
  579. {
  580. builder.Append("\\t");
  581. }
  582. else
  583. {
  584. int codepoint = Convert.ToInt32(c);
  585. if ((codepoint >= 32) && (codepoint <= 126))
  586. {
  587. builder.Append(c);
  588. }
  589. else
  590. {
  591. builder.Append("\\u" + Convert.ToString(codepoint, 16).PadLeft(4, '0'));
  592. }
  593. }
  594. }
  595. builder.Append("\"");
  596. }
  597. protected static void serializeNumber(double number, StringBuilder builder)
  598. {
  599. builder.Append(Convert.ToString(number)); // , CultureInfo.InvariantCulture));
  600. }
  601. #endregion
  602. }
  603. #region Extension methods
  604. public static class MiniJsonExtensions
  605. {
  606. public static string toJson(this Hashtable obj)
  607. {
  608. return MiniJSON.jsonEncode(obj);
  609. }
  610. public static string toJson(this Dictionary<string, string> obj)
  611. {
  612. return MiniJSON.jsonEncode(obj);
  613. }
  614. public static ArrayList arrayListFromJson(this string json)
  615. {
  616. return MiniJSON.jsonDecode(json) as ArrayList;
  617. }
  618. public static Hashtable hashtableFromJson(this string json)
  619. {
  620. return MiniJSON.jsonDecode(json) as Hashtable;
  621. }
  622. }
  623. #endregion
  624. }