IronSourceJSON.cs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. /*
  2. * Based on the miniJSON by Calvin Rien
  3. */
  4. using System;
  5. using System.Collections;
  6. using System.Collections.Generic;
  7. using System.IO;
  8. using System.Text;
  9. namespace IronSourceJSON
  10. {
  11. public static class Json
  12. {
  13. public static object Deserialize (string json)
  14. {
  15. if (json == null) {
  16. return null;
  17. }
  18. return Parser.Parse (json);
  19. }
  20. sealed class Parser : IDisposable
  21. {
  22. const string WHITE_SPACE = " \t\n\r";
  23. const string WORD_BREAK = " \t\n\r{}[],:\"";
  24. enum TOKEN
  25. {
  26. NONE,
  27. CURLY_OPEN,
  28. CURLY_CLOSE,
  29. SQUARED_OPEN,
  30. SQUARED_CLOSE,
  31. COLON,
  32. COMMA,
  33. STRING,
  34. NUMBER,
  35. TRUE,
  36. FALSE,
  37. NULL
  38. }
  39. ;
  40. StringReader json;
  41. Parser (string jsonString)
  42. {
  43. json = new StringReader (jsonString);
  44. }
  45. public static object Parse (string jsonString)
  46. {
  47. using (var instance = new Parser(jsonString)) {
  48. return instance.ParseValue ();
  49. }
  50. }
  51. public void Dispose ()
  52. {
  53. json.Dispose ();
  54. json = null;
  55. }
  56. Dictionary<string, object> ParseObject ()
  57. {
  58. Dictionary<string, object> table = new Dictionary<string, object> ();
  59. // ditch opening brace
  60. json.Read ();
  61. // {
  62. while (true) {
  63. switch (NextToken) {
  64. case TOKEN.NONE:
  65. return null;
  66. case TOKEN.COMMA:
  67. continue;
  68. case TOKEN.CURLY_CLOSE:
  69. return table;
  70. default:
  71. // name
  72. string name = ParseString ();
  73. if (name == null) {
  74. return null;
  75. }
  76. // :
  77. if (NextToken != TOKEN.COLON) {
  78. return null;
  79. }
  80. // ditch the colon
  81. json.Read ();
  82. // value
  83. table [name] = ParseValue ();
  84. break;
  85. }
  86. }
  87. }
  88. List<object> ParseArray ()
  89. {
  90. List<object> array = new List<object> ();
  91. // ditch opening bracket
  92. json.Read ();
  93. // [
  94. var parsing = true;
  95. while (parsing) {
  96. TOKEN nextToken = NextToken;
  97. switch (nextToken) {
  98. case TOKEN.NONE:
  99. return null;
  100. case TOKEN.COMMA:
  101. continue;
  102. case TOKEN.SQUARED_CLOSE:
  103. parsing = false;
  104. break;
  105. default:
  106. object value = ParseByToken (nextToken);
  107. array.Add (value);
  108. break;
  109. }
  110. }
  111. return array;
  112. }
  113. object ParseValue ()
  114. {
  115. TOKEN nextToken = NextToken;
  116. return ParseByToken (nextToken);
  117. }
  118. object ParseByToken (TOKEN token)
  119. {
  120. switch (token) {
  121. case TOKEN.STRING:
  122. return ParseString ();
  123. case TOKEN.NUMBER:
  124. return ParseNumber ();
  125. case TOKEN.CURLY_OPEN:
  126. return ParseObject ();
  127. case TOKEN.SQUARED_OPEN:
  128. return ParseArray ();
  129. case TOKEN.TRUE:
  130. return true;
  131. case TOKEN.FALSE:
  132. return false;
  133. case TOKEN.NULL:
  134. return null;
  135. default:
  136. return null;
  137. }
  138. }
  139. string ParseString ()
  140. {
  141. StringBuilder s = new StringBuilder ();
  142. char c;
  143. // ditch opening quote
  144. json.Read ();
  145. bool parsing = true;
  146. while (parsing) {
  147. if (json.Peek () == -1) {
  148. parsing = false;
  149. break;
  150. }
  151. c = NextChar;
  152. switch (c) {
  153. case '"':
  154. parsing = false;
  155. break;
  156. case '\\':
  157. if (json.Peek () == -1) {
  158. parsing = false;
  159. break;
  160. }
  161. c = NextChar;
  162. switch (c) {
  163. case '"':
  164. case '\\':
  165. case '/':
  166. s.Append (c);
  167. break;
  168. case 'b':
  169. s.Append ('\b');
  170. break;
  171. case 'f':
  172. s.Append ('\f');
  173. break;
  174. case 'n':
  175. s.Append ('\n');
  176. break;
  177. case 'r':
  178. s.Append ('\r');
  179. break;
  180. case 't':
  181. s.Append ('\t');
  182. break;
  183. case 'u':
  184. var hex = new StringBuilder ();
  185. for (int i=0; i< 4; i++) {
  186. hex.Append (NextChar);
  187. }
  188. s.Append ((char)Convert.ToInt32 (hex.ToString (), 16));
  189. break;
  190. }
  191. break;
  192. default:
  193. s.Append (c);
  194. break;
  195. }
  196. }
  197. return s.ToString ();
  198. }
  199. object ParseNumber ()
  200. {
  201. string number = NextWord;
  202. if (number.IndexOf ('.') == -1) {
  203. long parsedInt;
  204. Int64.TryParse (number, out parsedInt);
  205. return parsedInt;
  206. }
  207. double parsedDouble;
  208. Double.TryParse (number, out parsedDouble);
  209. return parsedDouble;
  210. }
  211. void EatWhitespace ()
  212. {
  213. while (WHITE_SPACE.IndexOf(PeekChar) != -1) {
  214. json.Read ();
  215. if (json.Peek () == -1) {
  216. break;
  217. }
  218. }
  219. }
  220. char PeekChar {
  221. get {
  222. return Convert.ToChar (json.Peek ());
  223. }
  224. }
  225. char NextChar {
  226. get {
  227. return Convert.ToChar (json.Read ());
  228. }
  229. }
  230. string NextWord {
  231. get {
  232. StringBuilder word = new StringBuilder ();
  233. while (WORD_BREAK.IndexOf(PeekChar) == -1) {
  234. word.Append (NextChar);
  235. if (json.Peek () == -1) {
  236. break;
  237. }
  238. }
  239. return word.ToString ();
  240. }
  241. }
  242. TOKEN NextToken {
  243. get {
  244. EatWhitespace ();
  245. if (json.Peek () == -1) {
  246. return TOKEN.NONE;
  247. }
  248. char c = PeekChar;
  249. switch (c) {
  250. case '{':
  251. return TOKEN.CURLY_OPEN;
  252. case '}':
  253. json.Read ();
  254. return TOKEN.CURLY_CLOSE;
  255. case '[':
  256. return TOKEN.SQUARED_OPEN;
  257. case ']':
  258. json.Read ();
  259. return TOKEN.SQUARED_CLOSE;
  260. case ',':
  261. json.Read ();
  262. return TOKEN.COMMA;
  263. case '"':
  264. return TOKEN.STRING;
  265. case ':':
  266. return TOKEN.COLON;
  267. case '0':
  268. case '1':
  269. case '2':
  270. case '3':
  271. case '4':
  272. case '5':
  273. case '6':
  274. case '7':
  275. case '8':
  276. case '9':
  277. case '-':
  278. return TOKEN.NUMBER;
  279. }
  280. string word = NextWord;
  281. switch (word) {
  282. case "false":
  283. return TOKEN.FALSE;
  284. case "true":
  285. return TOKEN.TRUE;
  286. case "null":
  287. return TOKEN.NULL;
  288. }
  289. return TOKEN.NONE;
  290. }
  291. }
  292. }
  293. /// <summary>
  294. /// Converts a IDictionary / IList object or a simple type (string, int, etc.) into a JSON string
  295. /// </summary>
  296. /// <param name="json">A Dictionary&lt;string, object&gt; / List&lt;object&gt;</param>
  297. /// <returns>A JSON encoded string, or null if object 'json' is not serializable</returns>
  298. public static string Serialize (object obj)
  299. {
  300. return Serializer.Serialize (obj);
  301. }
  302. sealed class Serializer
  303. {
  304. StringBuilder builder;
  305. Serializer ()
  306. {
  307. builder = new StringBuilder ();
  308. }
  309. public static string Serialize (object obj)
  310. {
  311. var instance = new Serializer ();
  312. instance.SerializeValue (obj);
  313. return instance.builder.ToString ();
  314. }
  315. void SerializeValue (object value)
  316. {
  317. IList asList;
  318. IDictionary asDict;
  319. string asStr;
  320. if (value == null) {
  321. builder.Append ("null");
  322. } else if ((asStr = value as string) != null) {
  323. SerializeString (asStr);
  324. } else if (value is bool) {
  325. builder.Append (value.ToString ().ToLower ());
  326. } else if ((asList = value as IList) != null) {
  327. SerializeArray (asList);
  328. } else if ((asDict = value as IDictionary) != null) {
  329. SerializeObject (asDict);
  330. } else if (value is char) {
  331. SerializeString (value.ToString ());
  332. } else {
  333. SerializeOther (value);
  334. }
  335. }
  336. void SerializeObject (IDictionary obj)
  337. {
  338. bool first = true;
  339. builder.Append ('{');
  340. foreach (object e in obj.Keys) {
  341. if (!first) {
  342. builder.Append (',');
  343. }
  344. SerializeString (e.ToString ());
  345. builder.Append (':');
  346. SerializeValue (obj [e]);
  347. first = false;
  348. }
  349. builder.Append ('}');
  350. }
  351. void SerializeArray (IList anArray)
  352. {
  353. builder.Append ('[');
  354. bool first = true;
  355. foreach (object obj in anArray) {
  356. if (!first) {
  357. builder.Append (',');
  358. }
  359. SerializeValue (obj);
  360. first = false;
  361. }
  362. builder.Append (']');
  363. }
  364. void SerializeString (string str)
  365. {
  366. builder.Append ('\"');
  367. char[] charArray = str.ToCharArray ();
  368. foreach (var c in charArray) {
  369. switch (c) {
  370. case '"':
  371. builder.Append ("\\\"");
  372. break;
  373. case '\\':
  374. builder.Append ("\\\\");
  375. break;
  376. case '\b':
  377. builder.Append ("\\b");
  378. break;
  379. case '\f':
  380. builder.Append ("\\f");
  381. break;
  382. case '\n':
  383. builder.Append ("\\n");
  384. break;
  385. case '\r':
  386. builder.Append ("\\r");
  387. break;
  388. case '\t':
  389. builder.Append ("\\t");
  390. break;
  391. default:
  392. int codepoint = Convert.ToInt32 (c);
  393. if ((codepoint >= 32) && (codepoint <= 126)) {
  394. builder.Append (c);
  395. } else {
  396. builder.Append ("\\u" + Convert.ToString (codepoint, 16).PadLeft (4, '0'));
  397. }
  398. break;
  399. }
  400. }
  401. builder.Append ('\"');
  402. }
  403. void SerializeOther (object value)
  404. {
  405. if (value is float
  406. || value is int
  407. || value is uint
  408. || value is long
  409. || value is double
  410. || value is sbyte
  411. || value is byte
  412. || value is short
  413. || value is ushort
  414. || value is ulong
  415. || value is decimal) {
  416. builder.Append (value.ToString ());
  417. } else {
  418. SerializeString (value.ToString ());
  419. }
  420. }
  421. }
  422. }
  423. }