PageRenderTime 49ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/SDK/api/CSharp/fastJSON/JsonSerializer.cs

https://bitbucket.org/ehvattum/draugr_contrib
C# | 508 lines | 425 code | 76 blank | 7 comment | 119 complexity | 2d8cefdaaee9e4e086d7e9f67d2dc021 MD5 | raw file
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. #if !SILVERLIGHT
  5. using System.Data;
  6. #endif
  7. using System.Globalization;
  8. using System.IO;
  9. using System.Text;
  10. namespace fastJSON
  11. {
  12. internal sealed class JSONSerializer
  13. {
  14. private StringBuilder _output = new StringBuilder();
  15. private StringBuilder _before = new StringBuilder();
  16. readonly int _MAX_DEPTH = 10;
  17. int _current_depth = 0;
  18. private Dictionary<string, int> _globalTypes = new Dictionary<string, int>();
  19. private JSONParameters _params;
  20. private bool _useEscapedUnicode = false;
  21. internal JSONSerializer(JSONParameters param)
  22. {
  23. _params = param;
  24. _useEscapedUnicode = _params.UseEscapedUnicode;
  25. }
  26. internal string ConvertToJSON(object obj)
  27. {
  28. WriteValue(obj);
  29. string str = "";
  30. if (_params.UsingGlobalTypes && _globalTypes != null && _globalTypes.Count > 0)
  31. {
  32. StringBuilder sb = _before;
  33. sb.Append("\"$types\":{");
  34. bool pendingSeparator = false;
  35. foreach (var kv in _globalTypes)
  36. {
  37. if (pendingSeparator) sb.Append(',');
  38. pendingSeparator = true;
  39. sb.Append("\"");
  40. sb.Append(kv.Key);
  41. sb.Append("\":\"");
  42. sb.Append(kv.Value);
  43. sb.Append("\"");
  44. }
  45. sb.Append("},");
  46. sb.Append(_output.ToString());
  47. str = sb.ToString();
  48. }
  49. else
  50. str = _output.ToString();
  51. return str;
  52. }
  53. private void WriteValue(object obj)
  54. {
  55. if (obj == null || obj is DBNull)
  56. _output.Append("null");
  57. else if (obj is string || obj is char)
  58. WriteString(obj.ToString());
  59. else if (obj is Guid)
  60. WriteGuid((Guid)obj);
  61. else if (obj is bool)
  62. _output.Append(((bool)obj) ? "true" : "false"); // conform to standard
  63. else if (
  64. obj is int || obj is long || obj is double ||
  65. obj is decimal || obj is float ||
  66. obj is byte || obj is short ||
  67. obj is sbyte || obj is ushort ||
  68. obj is uint || obj is ulong
  69. )
  70. _output.Append(((IConvertible)obj).ToString(NumberFormatInfo.InvariantInfo));
  71. else if (obj is DateTime)
  72. WriteDateTime((DateTime)obj);
  73. else if (obj is IDictionary && obj.GetType().IsGenericType && obj.GetType().GetGenericArguments()[0] == typeof(string))
  74. WriteStringDictionary((IDictionary)obj);
  75. else if (obj is IDictionary)
  76. WriteDictionary((IDictionary)obj);
  77. #if !SILVERLIGHT
  78. else if (obj is DataSet)
  79. WriteDataset((DataSet)obj);
  80. else if (obj is DataTable)
  81. this.WriteDataTable((DataTable)obj);
  82. #endif
  83. else if (obj is byte[])
  84. WriteBytes((byte[])obj);
  85. else if (obj is Array || obj is IList || obj is ICollection)
  86. WriteArray((IEnumerable)obj);
  87. else if (obj is Enum)
  88. WriteEnum((Enum)obj);
  89. #if CUSTOMTYPE
  90. else if (JSON.Instance.IsTypeRegistered(obj.GetType()))
  91. WriteCustom(obj);
  92. #endif
  93. else
  94. WriteObject(obj);
  95. }
  96. #if CUSTOMTYPE
  97. private void WriteCustom(object obj)
  98. {
  99. Serialize s;
  100. JSON.Instance._customSerializer.TryGetValue(obj.GetType(), out s);
  101. WriteStringFast(s(obj));
  102. }
  103. #endif
  104. private void WriteEnum(Enum e)
  105. {
  106. // TODO : optimize enum write
  107. WriteStringFast(e.ToString());
  108. }
  109. private void WriteGuid(Guid g)
  110. {
  111. if (_params.UseFastGuid == false)
  112. WriteStringFast(g.ToString());
  113. else
  114. WriteBytes(g.ToByteArray());
  115. }
  116. private void WriteBytes(byte[] bytes)
  117. {
  118. #if !SILVERLIGHT
  119. WriteStringFast(Convert.ToBase64String(bytes, 0, bytes.Length, Base64FormattingOptions.None));
  120. #else
  121. WriteStringFast(Convert.ToBase64String(bytes, 0, bytes.Length));
  122. #endif
  123. }
  124. private void WriteDateTime(DateTime dateTime)
  125. {
  126. // datetime format standard : yyyy-MM-dd HH:mm:ss
  127. DateTime dt = dateTime;
  128. if (_params.UseUTCDateTime)
  129. dt = dateTime.ToUniversalTime();
  130. _output.Append("\"");
  131. _output.Append(dt.Year.ToString("0000", NumberFormatInfo.InvariantInfo));
  132. _output.Append("-");
  133. _output.Append(dt.Month.ToString("00", NumberFormatInfo.InvariantInfo));
  134. _output.Append("-");
  135. _output.Append(dt.Day.ToString("00", NumberFormatInfo.InvariantInfo));
  136. _output.Append(" ");
  137. _output.Append(dt.Hour.ToString("00", NumberFormatInfo.InvariantInfo));
  138. _output.Append(":");
  139. _output.Append(dt.Minute.ToString("00", NumberFormatInfo.InvariantInfo));
  140. _output.Append(":");
  141. _output.Append(dt.Second.ToString("00", NumberFormatInfo.InvariantInfo));
  142. if (_params.UseUTCDateTime)
  143. _output.Append("Z");
  144. _output.Append("\"");
  145. }
  146. #if !SILVERLIGHT
  147. private DatasetSchema GetSchema(DataTable ds)
  148. {
  149. if (ds == null) return null;
  150. DatasetSchema m = new DatasetSchema();
  151. m.Info = new List<string>();
  152. m.Name = ds.TableName;
  153. foreach (DataColumn c in ds.Columns)
  154. {
  155. m.Info.Add(ds.TableName);
  156. m.Info.Add(c.ColumnName);
  157. m.Info.Add(c.DataType.ToString());
  158. }
  159. // FEATURE : serialize relations and constraints here
  160. return m;
  161. }
  162. private DatasetSchema GetSchema(DataSet ds)
  163. {
  164. if (ds == null) return null;
  165. DatasetSchema m = new DatasetSchema();
  166. m.Info = new List<string>();
  167. m.Name = ds.DataSetName;
  168. foreach (DataTable t in ds.Tables)
  169. {
  170. foreach (DataColumn c in t.Columns)
  171. {
  172. m.Info.Add(t.TableName);
  173. m.Info.Add(c.ColumnName);
  174. m.Info.Add(c.DataType.ToString());
  175. }
  176. }
  177. // FEATURE : serialize relations and constraints here
  178. return m;
  179. }
  180. private string GetXmlSchema(DataTable dt)
  181. {
  182. using (var writer = new StringWriter())
  183. {
  184. dt.WriteXmlSchema(writer);
  185. return dt.ToString();
  186. }
  187. }
  188. private void WriteDataset(DataSet ds)
  189. {
  190. _output.Append('{');
  191. if (_params.UseExtensions)
  192. {
  193. WritePair("$schema", _params.UseOptimizedDatasetSchema ? (object)GetSchema(ds) : ds.GetXmlSchema());
  194. _output.Append(',');
  195. }
  196. bool tablesep = false;
  197. foreach (DataTable table in ds.Tables)
  198. {
  199. if (tablesep) _output.Append(",");
  200. tablesep = true;
  201. WriteDataTableData(table);
  202. }
  203. // end dataset
  204. _output.Append('}');
  205. }
  206. private void WriteDataTableData(DataTable table)
  207. {
  208. _output.Append('\"');
  209. _output.Append(table.TableName);
  210. _output.Append("\":[");
  211. DataColumnCollection cols = table.Columns;
  212. bool rowseparator = false;
  213. foreach (DataRow row in table.Rows)
  214. {
  215. if (rowseparator) _output.Append(",");
  216. rowseparator = true;
  217. _output.Append('[');
  218. bool pendingSeperator = false;
  219. foreach (DataColumn column in cols)
  220. {
  221. if (pendingSeperator) _output.Append(',');
  222. WriteValue(row[column]);
  223. pendingSeperator = true;
  224. }
  225. _output.Append(']');
  226. }
  227. _output.Append(']');
  228. }
  229. void WriteDataTable(DataTable dt)
  230. {
  231. this._output.Append('{');
  232. if (_params.UseExtensions)
  233. {
  234. this.WritePair("$schema", _params.UseOptimizedDatasetSchema ? (object)this.GetSchema(dt) : this.GetXmlSchema(dt));
  235. this._output.Append(',');
  236. }
  237. WriteDataTableData(dt);
  238. // end datatable
  239. this._output.Append('}');
  240. }
  241. #endif
  242. bool _TypesWritten = false;
  243. private void WriteObject(object obj)
  244. {
  245. if (_params.UsingGlobalTypes == false)
  246. _output.Append('{');
  247. else
  248. {
  249. if (_TypesWritten == false)
  250. {
  251. _output.Append("{");
  252. _before = _output;
  253. _output = new StringBuilder();
  254. }
  255. else
  256. _output.Append("{");
  257. }
  258. _TypesWritten = true;
  259. _current_depth++;
  260. if (_current_depth > _MAX_DEPTH)
  261. throw new Exception("Serializer encountered maximum depth of " + _MAX_DEPTH);
  262. Dictionary<string, string> map = new Dictionary<string, string>();
  263. Type t = obj.GetType();
  264. bool append = false;
  265. if (_params.UseExtensions)
  266. {
  267. if (_params.UsingGlobalTypes == false)
  268. WritePairFast("$type", Reflection.Instance.GetTypeAssemblyName(t));
  269. else
  270. {
  271. int dt = 0;
  272. string ct = Reflection.Instance.GetTypeAssemblyName(t);
  273. if (_globalTypes.TryGetValue(ct, out dt) == false)
  274. {
  275. dt = _globalTypes.Count + 1;
  276. _globalTypes.Add(ct, dt);
  277. }
  278. WritePairFast("$type", dt.ToString());
  279. }
  280. append = true;
  281. }
  282. List<Getters> g = Reflection.Instance.GetGetters(t);
  283. foreach (var p in g)
  284. {
  285. object o = p.Getter(obj);
  286. if ((o == null || o is DBNull) && _params.SerializeNullValues == false)
  287. {
  288. //append = false;
  289. }
  290. else
  291. {
  292. if (append)
  293. _output.Append(',');
  294. WritePair(p.Name, o);
  295. if (o != null && _params.UseExtensions)
  296. {
  297. Type tt = o.GetType();
  298. if (tt == typeof(System.Object))
  299. map.Add(p.Name, tt.ToString());
  300. }
  301. append = true;
  302. }
  303. }
  304. if (map.Count > 0 && _params.UseExtensions)
  305. {
  306. _output.Append(",\"$map\":");
  307. WriteStringDictionary(map);
  308. }
  309. _current_depth--;
  310. _output.Append('}');
  311. _current_depth--;
  312. }
  313. private void WritePairFast(string name, string value)
  314. {
  315. if ((value == null) && _params.SerializeNullValues == false)
  316. return;
  317. WriteStringFast(name);
  318. _output.Append(':');
  319. WriteStringFast(value);
  320. }
  321. private void WritePair(string name, object value)
  322. {
  323. if ((value == null || value is DBNull) && _params.SerializeNullValues == false)
  324. return;
  325. WriteStringFast(name);
  326. _output.Append(':');
  327. WriteValue(value);
  328. }
  329. private void WriteArray(IEnumerable array)
  330. {
  331. _output.Append('[');
  332. bool pendingSeperator = false;
  333. foreach (object obj in array)
  334. {
  335. if (pendingSeperator) _output.Append(',');
  336. WriteValue(obj);
  337. pendingSeperator = true;
  338. }
  339. _output.Append(']');
  340. }
  341. private void WriteStringDictionary(IDictionary dic)
  342. {
  343. _output.Append('{');
  344. bool pendingSeparator = false;
  345. foreach (DictionaryEntry entry in dic)
  346. {
  347. if (pendingSeparator) _output.Append(',');
  348. WritePair((string)entry.Key, entry.Value);
  349. pendingSeparator = true;
  350. }
  351. _output.Append('}');
  352. }
  353. private void WriteDictionary(IDictionary dic)
  354. {
  355. _output.Append('[');
  356. bool pendingSeparator = false;
  357. foreach (DictionaryEntry entry in dic)
  358. {
  359. if (pendingSeparator) _output.Append(',');
  360. _output.Append('{');
  361. WritePair("k", entry.Key);
  362. _output.Append(",");
  363. WritePair("v", entry.Value);
  364. _output.Append('}');
  365. pendingSeparator = true;
  366. }
  367. _output.Append(']');
  368. }
  369. private void WriteStringFast(string s)
  370. {
  371. _output.Append('\"');
  372. _output.Append(s);
  373. _output.Append('\"');
  374. }
  375. private void WriteString(string s)
  376. {
  377. _output.Append('\"');
  378. int runIndex = -1;
  379. for (var index = 0; index < s.Length; ++index)
  380. {
  381. var c = s[index];
  382. if (_useEscapedUnicode)
  383. {
  384. if (c >= ' ' && c < 128 && c != '\"' && c != '\\')
  385. {
  386. if (runIndex == -1)
  387. runIndex = index;
  388. continue;
  389. }
  390. }
  391. else
  392. {
  393. if (c != '\t' && c != '\n' && c != '\r' && c != '\"' && c != '\\')// && c != ':' && c!=',')
  394. {
  395. if (runIndex == -1)
  396. runIndex = index;
  397. continue;
  398. }
  399. }
  400. if (runIndex != -1)
  401. {
  402. _output.Append(s, runIndex, index - runIndex);
  403. runIndex = -1;
  404. }
  405. switch (c)
  406. {
  407. case '\t': _output.Append("\\t"); break;
  408. case '\r': _output.Append("\\r"); break;
  409. case '\n': _output.Append("\\n"); break;
  410. case '"':
  411. case '\\': _output.Append('\\'); _output.Append(c); break;
  412. default:
  413. if (_useEscapedUnicode)
  414. {
  415. _output.Append("\\u");
  416. _output.Append(((int)c).ToString("X4", NumberFormatInfo.InvariantInfo));
  417. }
  418. else
  419. _output.Append(c);
  420. break;
  421. }
  422. }
  423. if (runIndex != -1)
  424. _output.Append(s, runIndex, s.Length - runIndex);
  425. _output.Append('\"');
  426. }
  427. }
  428. }