PageRenderTime 45ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/JSON/JSON.cs

https://bitbucket.org/rodlogic/arc-reaction
C# | 365 lines | 281 code | 84 blank | 0 comment | 65 complexity | 9a5441ae8de7c30d01710d0c0c4c489c MD5 | raw file
  1. using Prelude;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Globalization;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Web;
  8. namespace ArcReaction
  9. {
  10. public abstract class JSON : IHttpHandler
  11. {
  12. protected readonly JSONPropertyList properties;
  13. public JSON()
  14. {
  15. this.properties = new JSONPropertyList(this);
  16. }
  17. protected sealed class JSONPropertyList : IEnumerable<JSONProperty>
  18. {
  19. readonly List<JSONProperty> xs = new List<JSONProperty>();
  20. readonly JSON owner;
  21. public void Add(JSONProperty property)
  22. {
  23. xs.Add(property);
  24. }
  25. public void Add(string name, object value, bool show_null)
  26. {
  27. xs.Add(new DefaultJSONProperty(name, JSONProperty.GetValueString(value), show_null));
  28. }
  29. public void Add(string name, object value)
  30. {
  31. xs.Add(new DefaultJSONProperty(name, JSONProperty.GetValueString(value), true));
  32. }
  33. public void Add(string name, JSON value, bool show_null)
  34. {
  35. xs.Add(JSONProperty.Create(name, value, show_null));
  36. }
  37. public void Add(string name, JSON value)
  38. {
  39. xs.Add(JSONProperty.Create(name, value, true));
  40. }
  41. public void Add(string name, IEnumerable<JSON> values, bool show_null)
  42. {
  43. xs.Add(JSONProperty.Create(name, new JSONCollection(values), show_null));
  44. }
  45. public void Add(string name, IEnumerable<JSON> values)
  46. {
  47. xs.Add(JSONProperty.Create(name, new JSONCollection(values)));
  48. }
  49. public JSONPropertyList(JSON owner)
  50. {
  51. this.owner = owner;
  52. }
  53. public IEnumerator<JSONProperty> GetEnumerator()
  54. {
  55. return xs.GetEnumerator();
  56. }
  57. System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
  58. {
  59. return GetEnumerator();
  60. }
  61. }
  62. public abstract class JSONProperty
  63. {
  64. protected readonly string name, value;
  65. internal readonly bool show_null;
  66. public string Name { get { return name; } }
  67. public string Value { get { return value; } }
  68. public JSONProperty(string name, string value, bool show_null)
  69. {
  70. this.name = MakeSafeJavaScriptIdentifier(name);
  71. this.value = value;
  72. this.show_null = show_null;
  73. }
  74. static string MakeSafeString(string s)
  75. {
  76. return '"' + s.Replace("\"", "\\\"") + '"';
  77. }
  78. static bool ValidInitialCharacter(char c)
  79. {
  80. var unicode_category = char.GetUnicodeCategory(c);
  81. return unicode_category == UnicodeCategory.UppercaseLetter ||
  82. unicode_category == UnicodeCategory.LowercaseLetter ||
  83. unicode_category == UnicodeCategory.TitlecaseLetter ||
  84. unicode_category == UnicodeCategory.ModifierLetter ||
  85. unicode_category == UnicodeCategory.LetterNumber ||
  86. unicode_category == UnicodeCategory.OtherLetter;
  87. }
  88. static bool ValidSubsequentCharacter(char c)
  89. {
  90. var unicode_category = char.GetUnicodeCategory(c);
  91. return ValidInitialCharacter(c) ||
  92. unicode_category == UnicodeCategory.NonSpacingMark ||
  93. unicode_category == UnicodeCategory.SpacingCombiningMark ||
  94. unicode_category == UnicodeCategory.DecimalDigitNumber ||
  95. unicode_category == UnicodeCategory.ConnectorPunctuation;
  96. }
  97. static string MakeSafeJavaScriptIdentifier(string name)
  98. {
  99. if (!ValidInitialCharacter(name[0]))
  100. return MakeSafeString(name);
  101. for (var i = 1; i < name.Length; i++)
  102. if(!ValidSubsequentCharacter(name[i]))
  103. return MakeSafeString(name);
  104. return name;
  105. }
  106. internal static string GetValueString(object value)
  107. {
  108. if(value == null || (IsNull(value)))
  109. return "null";
  110. var type = value.GetType();
  111. if (type.IsArray)
  112. {
  113. var result = new List<string>();
  114. dynamic xs = value;
  115. foreach (var x in xs)
  116. result.Add(GetValueString(x));
  117. return '[' + string.Join(",", result) + ']';
  118. }
  119. var s = value.ToString();
  120. if (IsSimpleNumberType(type))
  121. return s;
  122. if (type == typeof(DateTime))
  123. return "new Date(\"" + s + "\")";
  124. if (type == typeof(Guid))
  125. return '"' + s + '"';
  126. if (type == typeof(bool))
  127. return s.ToLower();
  128. if(type.IsSubclassOf(typeof(JSON)))
  129. return value.ToString();
  130. return MakeSafeString(s);
  131. }
  132. static bool IsNull(object value)
  133. {
  134. Type type = null;
  135. return object.ReferenceEquals(value, null) || ((type = value.GetType()).IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>) && !(((dynamic)value).HasValue));
  136. }
  137. static bool IsSimpleNumberType(Type type)
  138. {
  139. if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
  140. return IsSimpleNumberType(type.GetGenericArguments()[0]);
  141. else
  142. return type == typeof(byte) || type == typeof(sbyte) || type == typeof(short) || type == typeof(ushort) || type == typeof(int) || type == typeof(uint) || type == typeof(long) || type == typeof(ulong) ||
  143. type == typeof(decimal) || type == typeof(float) || type == typeof(double);
  144. }
  145. public static JSONProperty Create(string name, object o, bool showNull)
  146. {
  147. if (o is JSON[])
  148. return new JSONObjectProperty(name, new JSONCollection(o as JSON[]), showNull);
  149. return new DefaultJSONProperty(name, GetValueString(o), showNull);
  150. }
  151. public static JSONProperty Create(string name, object o)
  152. {
  153. return Create(name, o, true);
  154. }
  155. public static JSONProperty Create(string name, JSON o, bool showNull)
  156. {
  157. return o != null ? (JSONProperty) new JSONObjectProperty(name, o, showNull) : new DefaultJSONProperty(name, GetValueString(null), showNull);
  158. }
  159. public static JSONProperty Create(string name, JSON o)
  160. {
  161. return Create(name, o, true);
  162. }
  163. public abstract string ToString(int n);
  164. public override string ToString()
  165. {
  166. return ToString(0);
  167. }
  168. }
  169. public sealed class DefaultJSONProperty : JSONProperty
  170. {
  171. public DefaultJSONProperty(string name, string value, bool show_null) : base(name, value, show_null) { }
  172. public override string ToString(int n)
  173. {
  174. return '\t'.RepeatAndAppend(n, name + " : " + value);
  175. }
  176. }
  177. public sealed class JSONObjectProperty : JSONProperty
  178. {
  179. JSON json;
  180. public JSONObjectProperty(string name, JSON obj, bool show_null)
  181. : base(name, obj.ToString(), show_null)
  182. {
  183. this.json = obj;
  184. }
  185. public override string ToString(int n)
  186. {
  187. var sb = new StringBuilder();
  188. sb.Append('\t'.RepeatAndAppend(n, Name + ":"));
  189. sb.Append(json.ToString(n));
  190. return sb.ToString();
  191. }
  192. }
  193. public virtual string ToString(int n)
  194. {
  195. var sb = new StringBuilder();
  196. sb.Append('\t'.RepeatAndAppend(n, "{\r\n"));
  197. if (properties.Any())
  198. {
  199. var filtered = (from p in properties where p.Value != "null" || p.show_null select p).GetEnumerator();
  200. filtered.MoveNext();
  201. sb.Append(filtered.Current.ToString(n + 1));
  202. while (filtered.MoveNext())
  203. {
  204. sb.Append(",");
  205. sb.Append("\r\n");
  206. sb.Append(filtered.Current.ToString(n + 1));
  207. }
  208. }
  209. sb.Append("\r\n" + '\t'.RepeatAndAppend(n, "}"));
  210. return sb.ToString();
  211. }
  212. public override string ToString()
  213. {
  214. return ToString(0);
  215. }
  216. public bool IsReusable
  217. {
  218. get { return false; }
  219. }
  220. public void ProcessRequest(HttpContext context)
  221. {
  222. context.Response.AddHeader("Content-Type", "application/json");
  223. context.Response.AddHeader("Content-Disposition", "inline");
  224. context.Response.Write(this.ToString());
  225. }
  226. public void AddScalar(string name, object value)
  227. {
  228. this.properties.Add(name, value);
  229. }
  230. public void AddArray(string name, System.Collections.IEnumerable values)
  231. {
  232. object[] array = values as object[];
  233. if (array == null)
  234. {
  235. var xs = new List<object>();
  236. foreach (var value in values)
  237. xs.Add(value);
  238. array = xs.ToArray();
  239. }
  240. this.properties.Add(name, array);
  241. }
  242. }
  243. public sealed class JSONCollection : JSON
  244. {
  245. JSON[] json_objs;
  246. public JSONCollection(IEnumerable<JSON> xs) : this(xs != null ? xs.ToArray() : new JSON[0]) { }
  247. public JSONCollection(params JSON[] json)
  248. {
  249. json_objs = json;
  250. }
  251. public JSON this[int n]
  252. {
  253. get
  254. {
  255. return json_objs[n];
  256. }
  257. }
  258. public override string ToString()
  259. {
  260. return ToString(0);
  261. }
  262. public override string ToString(int n)
  263. {
  264. if (json_objs.Length == 0)
  265. return "new Array()";
  266. var sb = new StringBuilder();
  267. if(n > 0)
  268. sb.AppendLine();
  269. sb.AppendLine('\t'.RepeatAndAppend(n, "["));
  270. sb.Append(json_objs[0].ToString(n + 1));
  271. for (var i = 1; i < json_objs.Length; i++)
  272. {
  273. sb.Append(',');
  274. sb.Append("\r\n");
  275. sb.Append(json_objs[i].ToString(n + 1));
  276. }
  277. sb.Append("\r\n" + '\t'.RepeatAndAppend(n, "]"));
  278. return sb.ToString();
  279. }
  280. }
  281. }