PageRenderTime 43ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/Framework/Ajax/Serialization.cs

https://github.com/mkol/il2js
C# | 474 lines | 446 code | 5 blank | 23 comment | 15 complexity | 0746c2ab2a0475da408c18fc777aa16e MD5 | raw file
  1. /*
  2. il2js Framework.dll - JavaScript VM for .NET
  3. Copyright (C) 2011 Michael Kolarz
  4. This library is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as
  6. published by the Free Software Foundation, either version 3 of
  7. the License, or (at your option) any later version.
  8. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with this library.
  14. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. using System;
  17. using System.Collections.Generic;
  18. using System.Linq;
  19. using System.Text;
  20. namespace MK.JavaScript.Ajax.Serialization {
  21. using System;
  22. using System.Collections.Generic;
  23. using System.Text;
  24. using System.Text.RegularExpressions;
  25. using System.IO;
  26. using System.Diagnostics;
  27. using System.Reflection;
  28. using System.Runtime.Serialization;
  29. using System.Web;
  30. using System.Collections;
  31. using MK.JavaScript.Framework;
  32. internal class Parser {
  33. ////bo prototype nie ma innych whitespacesow niz ' '
  34. //private void skipWhitespaces() {
  35. // while (char.IsWhiteSpace(this.source[this.position]))
  36. // ++this.position;
  37. //}
  38. private object ParseObject() {
  39. switch (this.source[this.position]) {
  40. case '{':
  41. #region object
  42. {
  43. Dictionary<string, object> ret = new Dictionary<string, object>();
  44. ++this.position;// /{/
  45. if (this.source[this.position] == '}') {
  46. ++this.position;
  47. return ret;
  48. } else do {
  49. var index = this.ParseString();
  50. this.position += 2;// /: /
  51. ret[index] = this.ParseObject();
  52. switch (this.source[this.position]) {
  53. case ',':
  54. this.position += 2;
  55. break;
  56. case '}':
  57. ++this.position;
  58. return ret;
  59. }
  60. } while (true);
  61. }
  62. #endregion
  63. case '[':
  64. #region array
  65. {
  66. List<object> ret = new List<object>();
  67. ++this.position;// /\[/
  68. if (this.source[this.position] == ']') {
  69. ++this.position;
  70. return ret;
  71. } else do {
  72. ret.Add(this.ParseObject());
  73. switch (this.source[this.position]) {
  74. case ',':
  75. this.position += 2;
  76. break;
  77. case ']':
  78. ++this.position;
  79. return ret;
  80. }
  81. } while (true);
  82. }
  83. #endregion
  84. case '"': return ParseString();
  85. case '-':
  86. case '.':
  87. case '0':
  88. case '1':
  89. case '2':
  90. case '3':
  91. case '4':
  92. case '5':
  93. case '6':
  94. case '7':
  95. case '8':
  96. case '9':
  97. #region number
  98. {
  99. int length = 1;
  100. while (new[] { '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }.Contains(this.source[this.position + length])) {
  101. ++length;
  102. }
  103. var ret = this.source.Substring(this.position, length);
  104. this.position += length;
  105. return ret;
  106. }
  107. #endregion
  108. case 'n':
  109. #region null
  110. if (
  111. this.source[this.position + 1] == 'u' &&
  112. this.source[this.position + 2] == 'l' &&
  113. this.source[this.position + 3] == 'l') {
  114. this.position += 4;
  115. return null;
  116. } else {
  117. throw new Exception(this.source.Substring(this.position));
  118. }
  119. #endregion
  120. case 't':
  121. #region true
  122. if (
  123. this.source[this.position + 1] == 'r' &&
  124. this.source[this.position + 2] == 'u' &&
  125. this.source[this.position + 3] == 'e') {
  126. this.position += 4;
  127. return true;
  128. } else {
  129. throw new Exception(this.source.Substring(this.position));
  130. }
  131. #endregion
  132. case 'f':
  133. #region false
  134. if (
  135. this.source[this.position + 1] == 'a' &&
  136. this.source[this.position + 2] == 'l' &&
  137. this.source[this.position + 3] == 's' &&
  138. this.source[this.position + 4] == 'e') {
  139. this.position += 5;
  140. return false;
  141. } else {
  142. throw new Exception(this.source.Substring(this.position));
  143. }
  144. #endregion
  145. }
  146. throw new Exception("Unknown character: " + this.source[this.position] + "@" + this.position);
  147. }
  148. private string ParseString() {
  149. ++this.position;
  150. StringBuilder sb = new StringBuilder("");
  151. do {
  152. switch (this.source[this.position]) {
  153. case '\"':
  154. ++this.position;
  155. return sb.ToString();
  156. case '\\':
  157. ++this.position;
  158. switch (this.source[this.position]) {
  159. case 'n': sb.Append('\n'); break;
  160. case 't': sb.Append('\t'); break;
  161. case '"': sb.Append('"'); break;
  162. default:
  163. throw new Exception(@"\" + this.source[this.position]);
  164. }
  165. ++this.position;
  166. break;
  167. default:
  168. sb.Append(this.source[this.position++]);
  169. break;
  170. }
  171. } while (true);
  172. }
  173. private string source;
  174. private int position;
  175. public object Parse(string s) {
  176. this.source = s;
  177. this.position = 0;
  178. return this.ParseObject();
  179. }
  180. }
  181. internal interface ISerializer {
  182. string Serialize(object obj);
  183. object Deserialize(object source);
  184. }
  185. internal class NumberSerializer : ISerializer {
  186. private readonly MethodInfo parse;
  187. public NumberSerializer(Type type) {
  188. this.parse = type.GetMethod("Parse", new[] { typeof(string) });
  189. }
  190. string ISerializer.Serialize(object obj) { return obj.ToString().Replace(',', '.'); }
  191. object ISerializer.Deserialize(object source) { return this.parse.Invoke(null, new[] { source }); }
  192. }
  193. internal class BooleanSerializer : ISerializer {
  194. string ISerializer.Serialize(object obj) { return true.Equals(obj) ? "true" : "false"; }
  195. object ISerializer.Deserialize(object source) { return source; }
  196. }
  197. internal class StringSerializer : ISerializer {
  198. string ISerializer.Serialize(object obj) {
  199. if (obj == null) return "null";
  200. StringBuilder sb = new StringBuilder();
  201. sb.Append('"');
  202. foreach (var c in (string)obj) {
  203. switch (c) {
  204. case '\\': sb.Append(@"\\"); break;
  205. case '\"': sb.Append("\\\""); break;
  206. case '\n': sb.Append(@"\n"); break;
  207. case '\r': break;
  208. default: sb.Append(c); break;
  209. }
  210. }
  211. sb.Append('"');
  212. return sb.ToString();
  213. }
  214. object ISerializer.Deserialize(object source) { return source; }
  215. }
  216. internal class IEnumerable1Serializer : ISerializer {
  217. string ISerializer.Serialize(object obj) {
  218. if (obj == null) return "null";
  219. StringBuilder sb = new StringBuilder();
  220. sb.Append('[');
  221. foreach (var item in (IEnumerable)obj) {
  222. sb.Append(Serializer.Serialize(item)).Append(',');
  223. }
  224. if (sb.Length > 1)
  225. --sb.Length;
  226. sb.Append(']');
  227. return sb.ToString();
  228. }
  229. object ISerializer.Deserialize(object source) {
  230. var values = (List<object>)source;
  231. var ret = (IList)typeof(List<>).MakeGenericType(this.type).GetConstructor(Type.EmptyTypes).Invoke(null);
  232. foreach (var item in values) {
  233. ret.Add(Serializer.Deserialize(this.type, item));
  234. }
  235. return ret;
  236. }
  237. private Type type;
  238. public IEnumerable1Serializer(Type type) { this.type = type; }
  239. }
  240. internal class ArraySerializer : ISerializer {
  241. string ISerializer.Serialize(object obj) {
  242. if (obj == null) return "null";
  243. StringBuilder sb = new StringBuilder();
  244. sb.Append('[');
  245. foreach (var item in (Array)obj) {
  246. sb.Append(Serializer.Serialize(item)).Append(',');
  247. }
  248. if (sb.Length > 1)
  249. --sb.Length;
  250. sb.Append(']');
  251. return sb.ToString();
  252. }
  253. object ISerializer.Deserialize(object source) {
  254. var values = (List<object>)source;
  255. var ret = Array.CreateInstance(this.type, values.Count);
  256. for (int i = 0; i < values.Count; ++i) {
  257. ret.SetValue(Serializer.Deserialize(this.type, values[i]), i);
  258. }
  259. return ret;
  260. }
  261. private Type type;
  262. public ArraySerializer(Type type) { this.type = type; }
  263. }
  264. internal class IDictionary2Serializer : ISerializer {
  265. string ISerializer.Serialize(object obj) {
  266. if (obj == null) return "null";
  267. StringBuilder sb = new StringBuilder();
  268. sb.Append('{');
  269. foreach (DictionaryEntry item in (IDictionary)obj) {
  270. sb.Append(Serializer.Serialize(item.Key)).Append(':').Append(Serializer.Serialize(item.Value)).Append(',');
  271. }
  272. if (sb.Length > 1)
  273. --sb.Length;
  274. sb.Append('}');
  275. return sb.ToString();
  276. }
  277. object ISerializer.Deserialize(object source) {
  278. var values = (Dictionary<string, object>)source;
  279. var ret = (IDictionary)typeof(Dictionary<,>).MakeGenericType(this.keyType, this.valueType).GetConstructor(Type.EmptyTypes).Invoke(null);
  280. foreach (var item in values) {
  281. ret[Serializer.Deserialize(this.keyType, item.Key)] = Serializer.Deserialize(this.valueType, item.Value);
  282. }
  283. return ret;
  284. }
  285. private Type keyType;
  286. private Type valueType;
  287. public IDictionary2Serializer(Type keyType, Type valueType) { this.keyType = keyType; this.valueType = valueType; }
  288. }
  289. internal class ClassSerializer : ISerializer {
  290. private class FieldSerializer {
  291. public void Set(object obj, object value) {
  292. this.Field.SetValue(obj, value);
  293. }
  294. public object Get(object obj) {
  295. return this.Field.GetValue(obj);
  296. }
  297. public readonly FieldInfo Field;
  298. public FieldSerializer(FieldInfo field) {
  299. this.Field = field;
  300. }
  301. }
  302. private Dictionary<char, FieldSerializer> fieldSerializers = new Dictionary<char, FieldSerializer>();
  303. internal char GetToken(FieldInfo fieldInfo) {
  304. foreach (var item in this.fieldSerializers) {
  305. if (item.Value.Field == fieldInfo) {
  306. return item.Key;
  307. }
  308. }
  309. return ((ClassSerializer)Serializer.GetSerializer(this.type.BaseType)).GetToken(fieldInfo);
  310. }
  311. private readonly Type type;
  312. private int tokenIndex;
  313. public ClassSerializer(Type type) {
  314. this.type = type;
  315. //throw new Exception(type+"|"+type.BaseType);
  316. this.tokenIndex = type.BaseType == typeof(object) ? 0 : ((ClassSerializer)Serializer.GetSerializer(type.BaseType)).tokenIndex;
  317. foreach (var field in from f in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
  318. where f.DeclaringType == type
  319. orderby f.Name
  320. select f) {
  321. var attributes = field.GetCustomAttributes(typeof(DataMemberAttribute), false);
  322. if (attributes.Length == 1) {
  323. this.fieldSerializers[Utils.Tokens[this.tokenIndex]] = new FieldSerializer(field);
  324. }
  325. ++this.tokenIndex;
  326. }
  327. //do {
  328. // foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) {
  329. // var attrs = field.GetCustomAttributes(typeof(DataMemberAttribute), false);
  330. // if (attrs.Length == 1) {
  331. // var data = (DataMemberAttribute)attrs[0];
  332. // this.fieldSerializers[data.Order] = new FieldSerializer(field);
  333. // }
  334. // }
  335. // type = type.BaseType;
  336. //} while (type.GetCustomAttributes(typeof(DataContractAttribute), false).Length == 1);
  337. }
  338. string ISerializer.Serialize(object obj) {
  339. if (obj == null) return "null";
  340. StringBuilder sb = new StringBuilder();
  341. sb.Append('{');
  342. var serializer = this;
  343. while (true) {
  344. foreach (var item in serializer.fieldSerializers) {
  345. sb.Append(item.Key).Append(':');
  346. sb.Append(Serializer.Serialize(item.Value.Get(obj)));
  347. sb.Append(',');
  348. }
  349. if (serializer.type.BaseType != typeof(object)) {
  350. serializer = (ClassSerializer)Serializer.GetSerializer(serializer.type.BaseType);
  351. } else {
  352. break;
  353. }
  354. }
  355. if (sb.Length > 1)
  356. --sb.Length;
  357. sb.Append('}');
  358. return sb.ToString();
  359. }
  360. object ISerializer.Deserialize(object source) {
  361. var values = (Dictionary<string, object>)source;
  362. var ret = this.type.GetConstructor(Type.EmptyTypes).Invoke(null);
  363. foreach (var item in values) {
  364. FieldSerializer serializer;
  365. if (this.fieldSerializers.TryGetValue(item.Key[0], out serializer))
  366. try {
  367. serializer.Set(ret, Serializer.Deserialize(serializer.Field.FieldType, item.Value));
  368. } catch (Exception e) {
  369. throw new Exception("Error while setting " + serializer.Field.Name + ":\n" + e);
  370. }
  371. }
  372. return ret;
  373. }
  374. }
  375. public static class Serializer {
  376. private static Dictionary<Type, ISerializer> serializers = new Dictionary<Type, ISerializer>() {
  377. {typeof(byte),new NumberSerializer(typeof(byte))},
  378. {typeof(sbyte),new NumberSerializer(typeof(sbyte))},
  379. {typeof(ushort),new NumberSerializer(typeof(ushort))},
  380. {typeof(short),new NumberSerializer(typeof(short))},
  381. {typeof(uint),new NumberSerializer(typeof(uint))},
  382. {typeof(int),new NumberSerializer(typeof(int))},
  383. {typeof(ulong),new NumberSerializer(typeof(ulong))},
  384. {typeof(long),new NumberSerializer(typeof(long))},
  385. {typeof(decimal),new NumberSerializer(typeof(decimal))},
  386. {typeof(float),new NumberSerializer(typeof(float))},
  387. {typeof(double),new NumberSerializer(typeof(double))},
  388. {typeof(string),new StringSerializer()},
  389. {typeof(bool),new BooleanSerializer()},
  390. };
  391. internal static ISerializer GetSerializer(Type type) {
  392. ISerializer ret;
  393. if (!serializers.TryGetValue(type, out ret)) {
  394. if (type.IsArray) {
  395. ret = new ArraySerializer(type.GetElementType());
  396. } else {
  397. if (type.Namespace == "System.Collections.Generic") {
  398. switch (type.Name) {
  399. case "IDictionary`2": {
  400. Type[] types = type.GetGenericArguments();
  401. ret = new IDictionary2Serializer(types[0], types[1]);
  402. goto end;
  403. }
  404. case "IEnumerable`1":
  405. ret = new IEnumerable1Serializer(type.GetGenericArguments()[0]);
  406. goto end;
  407. }
  408. }
  409. foreach (var i in type.GetInterfaces().OrderBy(t => t.Name)) {//orderby zeby slownik jako slownik a nie jako enumeracje key/value
  410. switch (i.Name) {
  411. case "IDictionary`2": {
  412. Type[] types = i.GetGenericArguments();
  413. ret = new IDictionary2Serializer(types[0], types[1]);
  414. goto end;
  415. }
  416. case "IEnumerable`1":
  417. ret = new IEnumerable1Serializer(i.GetGenericArguments()[0]);
  418. goto end;
  419. }
  420. }
  421. ret = new ClassSerializer(type);
  422. }
  423. end:
  424. serializers[type] = ret;
  425. }
  426. return ret;
  427. }
  428. public static List<object> Deserialize(HttpContext context, params Type[] types) {
  429. // var bytes = new byte[context.Request.TotalBytes];
  430. // context.Request.InputStream.Read(bytes, 0, context.Request.TotalBytes);
  431. //#warning to nie bedzie dzialac dla unicode character
  432. // var s = new string(bytes.Select(b => (char)b).ToArray());
  433. byte[] bytes = new byte[context.Request.TotalBytes];
  434. context.Request.InputStream.Read(bytes, 0, bytes.Length);
  435. var s = context.Request.ContentEncoding.GetString(bytes);
  436. var ret = (List<object>)new Parser().Parse(s);
  437. for (int i = 0; i < types.Length; ++i) {
  438. ret[i] = Deserialize(types[i], ret[i]);
  439. }
  440. //throw new Exception(string.Join(",", ret.Select(r => r.GetType().Name).ToArray()));
  441. return ret;
  442. }
  443. public static string Serialize(object obj) {
  444. if (obj == null) return "null";
  445. return GetSerializer(obj.GetType()).Serialize(obj);
  446. }
  447. internal static object Deserialize(Type type, object source) {
  448. return source == null ? null : GetSerializer(type).Deserialize(source);
  449. }
  450. }
  451. }