LosFormatter.cs 9.9 KB

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