LosFormatter.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. //
  2. // System.Web.UI.LosFormatter
  3. //
  4. // Authors:
  5. // Gonzalo Paniagua Javier ([email protected])
  6. //
  7. // (C) 2002 Ximian, Inc (http://www.ximian.com)
  8. //
  9. using System;
  10. using System.Collections;
  11. using System.Drawing;
  12. using System.IO;
  13. using System.Text;
  14. using System.Web.UI;
  15. using System.Web.Util;
  16. namespace System.Web.UI
  17. {
  18. public sealed class LosFormatter
  19. {
  20. delegate void WriteObject (LosFormatter formatter, TextWriter writer, object value);
  21. static char [] specialChars = new char [] {'<', '>', ';'};
  22. const char booleanID = 'o';
  23. const char stringID = 's';
  24. const char charID = 'c';
  25. const char int16ID = 'i';
  26. const char int32ID = 'I';
  27. const char int64ID = 'l';
  28. const char colorID = 'C';
  29. const char pairID = 'p';
  30. const char tripletID = 't';
  31. const char arrayListID = 'L';
  32. const char hashtableID = 'h';
  33. static Hashtable specialTypes;
  34. static Hashtable idToType;
  35. static LosFormatter ()
  36. {
  37. specialTypes = new Hashtable ();
  38. specialTypes.Add (typeof (Boolean), new WriteObject (WriteBoolean));
  39. specialTypes.Add (typeof (Pair), new WriteObject (WritePair));
  40. specialTypes.Add (typeof (Triplet), new WriteObject (WriteTriplet));
  41. specialTypes.Add (typeof (Color), new WriteObject (WriteColor));
  42. specialTypes.Add (typeof (ArrayList), new WriteObject (WriteArrayList));
  43. specialTypes.Add (typeof (Hashtable), new WriteObject (WriteHashtable));
  44. idToType = new Hashtable ();
  45. idToType.Add (typeof (string), stringID);
  46. idToType.Add (typeof (char), charID);
  47. idToType.Add (typeof (Int16), int16ID);
  48. idToType.Add (typeof (Int32), int32ID);
  49. idToType.Add (typeof (Int64), int64ID);
  50. idToType.Add (typeof (Boolean), booleanID);
  51. idToType.Add (typeof (Pair), pairID);
  52. idToType.Add (typeof (Triplet), tripletID);
  53. idToType.Add (typeof (Color), colorID);
  54. idToType.Add (typeof (ArrayList), arrayListID);
  55. idToType.Add (typeof (Hashtable), hashtableID);
  56. }
  57. public object Deserialize (Stream stream)
  58. {
  59. if (stream == null)
  60. throw new ArgumentNullException ("stream");
  61. return Deserialize (new StreamReader (stream));
  62. }
  63. public object Deserialize (TextReader input)
  64. {
  65. if (input == null)
  66. throw new ArgumentNullException ("input");
  67. return Deserialize (input.ReadToEnd ());
  68. }
  69. public object Deserialize (string input)
  70. {
  71. if (input == null)
  72. throw new ArgumentNullException ("input");
  73. string real_input = WebEncoding.Encoding.GetString (Convert.FromBase64String (input));
  74. return DeserializeObject (real_input);
  75. }
  76. private static string UnEscapeSpecialChars (string str)
  77. {
  78. if (str.IndexOf ('\\') == -1)
  79. return str;
  80. string result = str.Replace ("\\;", ";");
  81. result = result.Replace ("\\>", ">");
  82. result = result.Replace ("\\<", "<");
  83. result = result.Replace ("\\\\", "\\");
  84. return result;
  85. }
  86. private static string GetEnclosedString (string input)
  87. {
  88. if (input [0] != '<')
  89. throw new ArgumentException (input);
  90. int count = 1;
  91. bool escaped = false;
  92. StringBuilder result = new StringBuilder ();
  93. for (int i = 1; count != 0 && i < input.Length; i++) {
  94. char c = input [i];
  95. if (escaped)
  96. escaped = false;
  97. else if (c == '\\')
  98. escaped = true;
  99. else if (c == '<')
  100. count++;
  101. else if (c == '>')
  102. count--;
  103. result.Append (c);
  104. }
  105. result.Length--;
  106. return result.ToString ();
  107. }
  108. private static string [] GetStringValues (string input)
  109. {
  110. if (input == null || input.Length == 0)
  111. return new string [0];
  112. int length = input.Length;
  113. bool escaped = false;
  114. int opened = 0;
  115. ArrayList list = new ArrayList ();
  116. StringBuilder builder = new StringBuilder ();
  117. for (int i = 0; i < length; i++) {
  118. char c = input [i];
  119. if (escaped)
  120. escaped = false;
  121. else if (c == '\\')
  122. escaped = true;
  123. else if (c == '<')
  124. opened++;
  125. else if (c == '>')
  126. opened--;
  127. else if (c == ';' && opened == 0) {
  128. list.Add (builder.ToString ());
  129. builder = new StringBuilder ();
  130. continue;
  131. }
  132. builder.Append (c);
  133. }
  134. list.Add (builder.ToString ());
  135. string [] result = new string [list.Count];
  136. list.CopyTo (result, 0);
  137. return result;
  138. }
  139. private object DeserializeObject (string input)
  140. {
  141. if (input == null || input.Length < 2)
  142. return null;
  143. object obj;
  144. string enclosed = GetEnclosedString (input.Substring (1));
  145. string [] splitted;
  146. switch (input [0]) {
  147. case booleanID:
  148. obj = enclosed.Length == 1;
  149. break;
  150. case stringID:
  151. obj = UnEscapeSpecialChars (enclosed);
  152. break;
  153. case int16ID:
  154. obj = Int16.Parse (enclosed);
  155. break;
  156. case int32ID:
  157. obj = Int32.Parse (enclosed);
  158. break;
  159. case int64ID:
  160. obj = Int64.Parse (enclosed);
  161. break;
  162. case colorID:
  163. obj = Color.FromArgb (Int32.Parse (enclosed));
  164. break;
  165. case pairID:
  166. Pair pair = new Pair ();
  167. obj = pair;
  168. splitted = GetStringValues (enclosed);
  169. if (splitted.Length > 0) {
  170. pair.First = DeserializeObject (splitted [0]);
  171. if (splitted.Length > 1)
  172. pair.Second = DeserializeObject (splitted [1]);
  173. }
  174. break;
  175. case tripletID:
  176. Triplet triplet = new Triplet ();
  177. obj = triplet;
  178. splitted = GetStringValues (enclosed);
  179. if (splitted.Length == 0)
  180. break;
  181. triplet.First = DeserializeObject (splitted [0]);
  182. if (splitted.Length < 1)
  183. break;
  184. triplet.Second = DeserializeObject (splitted [1]);
  185. if (splitted.Length < 2)
  186. break;
  187. triplet.Third = DeserializeObject (splitted [2]);
  188. break;
  189. case arrayListID:
  190. ArrayList list = new ArrayList ();
  191. obj = list;
  192. splitted = GetStringValues (enclosed);
  193. foreach (string s in splitted) {
  194. object o = DeserializeObject (s);
  195. list.Add (o);
  196. }
  197. break;
  198. case hashtableID:
  199. object key;
  200. object value;
  201. Hashtable hash = new Hashtable ();
  202. obj = hash;
  203. splitted = GetStringValues (enclosed);
  204. int length = splitted.Length;
  205. for (int i = 0; i < length; i++) {
  206. key = DeserializeObject (splitted [i++]);
  207. if (i < length)
  208. value = DeserializeObject (splitted [i]);
  209. else
  210. value = null;
  211. hash.Add (key, value);
  212. }
  213. break;
  214. default:
  215. throw new ArgumentException ("input");
  216. }
  217. return obj;
  218. }
  219. public void Serialize (Stream stream, object value)
  220. {
  221. if (stream == null)
  222. throw new ArgumentNullException ("stream");
  223. if (value == null)
  224. throw new ArgumentNullException ("value");
  225. StreamWriter writer = new StreamWriter (stream);
  226. Serialize (writer, value);
  227. writer.Flush ();
  228. }
  229. public void Serialize (TextWriter output, object value)
  230. {
  231. if (value == null)
  232. return;
  233. if (output == null)
  234. throw new ArgumentNullException ("output");
  235. StringBuilder builder = new StringBuilder ();
  236. StringWriter writer = new StringWriter (builder);
  237. SerializeObject (writer, value);
  238. byte [] bytes = WebEncoding.Encoding.GetBytes (builder.ToString ());
  239. output.Write (Convert.ToBase64String (bytes));
  240. }
  241. private static void WriteBoolean (LosFormatter formatter, TextWriter output, object value)
  242. {
  243. if (value == null)
  244. return;
  245. output.Write (booleanID);
  246. bool b = (bool) value;
  247. output.Write (b ? "<t>" : "<>");
  248. }
  249. private static void WritePair (LosFormatter formatter, TextWriter output, object value)
  250. {
  251. if (value == null)
  252. return;
  253. output.Write (pairID);
  254. Pair pair = (Pair) value;
  255. output.Write ('<');
  256. formatter.SerializeObject (output, pair.First);
  257. output.Write (';');
  258. formatter.SerializeObject (output, pair.Second);
  259. output.Write ('>');
  260. }
  261. private static void WriteTriplet (LosFormatter formatter, TextWriter output, object value)
  262. {
  263. if (value == null)
  264. return;
  265. output.Write (tripletID);
  266. Triplet triplet = (Triplet) value;
  267. output.Write ('<');
  268. formatter.SerializeObject (output, triplet.First);
  269. output.Write (';');
  270. formatter.SerializeObject (output, triplet.Second);
  271. output.Write (';');
  272. formatter.SerializeObject (output, triplet.Third);
  273. output.Write ('>');
  274. }
  275. private static void WriteColor (LosFormatter formatter, TextWriter output, object value)
  276. {
  277. if (value == null)
  278. return;
  279. Color c = (Color) value;
  280. output.Write (String.Format ("{0}<{1}>", colorID, c.ToArgb ()));
  281. }
  282. private static void WriteArrayList (LosFormatter formatter, TextWriter output, object value)
  283. {
  284. if (value == null)
  285. return;
  286. output.Write (arrayListID);
  287. output.Write ('<');
  288. ArrayList list = (ArrayList) value;
  289. for (int i = 0; i < list.Count; i++) {
  290. formatter.SerializeObject (output, list [i]);
  291. if (i != list.Count - 1)
  292. output.Write (';');
  293. }
  294. output.Write('>');
  295. }
  296. private static void WriteHashtable (LosFormatter formatter, TextWriter output, object value)
  297. {
  298. if (value == null)
  299. return;
  300. output.Write (hashtableID);
  301. output.Write ('<');
  302. Hashtable hash = (Hashtable) value;
  303. int i = 0;
  304. foreach (DictionaryEntry entry in hash) {
  305. formatter.SerializeObject (output, entry.Key);
  306. output.Write (';');
  307. formatter.SerializeObject (output, entry.Value);
  308. if (i != hash.Count - 1)
  309. output.Write (';');
  310. i++;
  311. }
  312. output.Write('>');
  313. }
  314. private static string EscapeSpecialChars (string str)
  315. {
  316. if (str.IndexOfAny (specialChars) == -1)
  317. return str;
  318. string result = str.Replace ("\\", "\\\\");
  319. result = result.Replace ("<", "\\<");
  320. result = result.Replace (">", "\\>");
  321. result = result.Replace (";", "\\;");
  322. return result;
  323. }
  324. private void SerializeObject (TextWriter output, object value)
  325. {
  326. if (value == null)
  327. return;
  328. Type t = value.GetType ();
  329. if (specialTypes.Contains (t)) {
  330. WriteObject w = (WriteObject) specialTypes [t];
  331. w (this, output, value);
  332. return;
  333. }
  334. if (idToType.Contains (t)) {
  335. char c = (char) idToType [t];
  336. string s = EscapeSpecialChars (value.ToString ());
  337. output.Write (String.Format ("{0}<{1}>", c, value.ToString ()));
  338. return;
  339. }
  340. //TODO: support more types. Serialize if serializable?
  341. throw new NotImplementedException (String.Format ("Type {0} not supported yet.", t));
  342. }
  343. }
  344. }