LosFormatter.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  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.Runtime.Serialization.Formatters.Binary;
  14. using System.Text;
  15. using System.Web.UI;
  16. using System.Web.Util;
  17. namespace System.Web.UI
  18. {
  19. public sealed class LosFormatter
  20. {
  21. delegate void WriteObject (LosFormatter formatter, TextWriter writer, object value);
  22. static char [] specialChars = new char [] {'<', '>', ';'};
  23. const char booleanID = 'o';
  24. const char stringID = 's';
  25. const char charID = 'c';
  26. const char int16ID = 'i';
  27. const char int32ID = 'I';
  28. const char int64ID = 'l';
  29. const char colorID = 'C';
  30. const char pairID = 'p';
  31. const char tripletID = 't';
  32. const char arrayListID = 'L';
  33. const char hashtableID = 'h';
  34. const char binaryID = 'b';
  35. const char arrayID = 'a';
  36. const char dateTimeID = 'd';
  37. static Hashtable specialTypes;
  38. static Hashtable idToType;
  39. static LosFormatter ()
  40. {
  41. specialTypes = new Hashtable ();
  42. specialTypes.Add (typeof (Boolean), new WriteObject (WriteBoolean));
  43. specialTypes.Add (typeof (Pair), new WriteObject (WritePair));
  44. specialTypes.Add (typeof (Triplet), new WriteObject (WriteTriplet));
  45. specialTypes.Add (typeof (Color), new WriteObject (WriteColor));
  46. specialTypes.Add (typeof (ArrayList), new WriteObject (WriteArrayList));
  47. specialTypes.Add (typeof (Hashtable), new WriteObject (WriteHashtable));
  48. specialTypes.Add (typeof (Array), new WriteObject (WriteArray));
  49. specialTypes.Add (typeof (DateTime), new WriteObject (WriteDateTime));
  50. idToType = new Hashtable ();
  51. idToType.Add (typeof (string), stringID);
  52. idToType.Add (typeof (char), charID);
  53. idToType.Add (typeof (Int16), int16ID);
  54. idToType.Add (typeof (Int32), int32ID);
  55. idToType.Add (typeof (Int64), int64ID);
  56. idToType.Add (typeof (Boolean), booleanID);
  57. idToType.Add (typeof (Pair), pairID);
  58. idToType.Add (typeof (Triplet), tripletID);
  59. idToType.Add (typeof (Color), colorID);
  60. idToType.Add (typeof (ArrayList), arrayListID);
  61. idToType.Add (typeof (Hashtable), hashtableID);
  62. idToType.Add (typeof (Array), arrayID);
  63. }
  64. public object Deserialize (Stream stream)
  65. {
  66. if (stream == null)
  67. throw new ArgumentNullException ("stream");
  68. return Deserialize (new StreamReader (stream));
  69. }
  70. public object Deserialize (TextReader input)
  71. {
  72. if (input == null)
  73. throw new ArgumentNullException ("input");
  74. return Deserialize (input.ReadToEnd ());
  75. }
  76. public object Deserialize (string input)
  77. {
  78. if (input == null)
  79. throw new ArgumentNullException ("input");
  80. string real_input = WebEncoding.Encoding.GetString (Convert.FromBase64String (input));
  81. return DeserializeObject (real_input);
  82. }
  83. private static string UnEscapeSpecialChars (string str)
  84. {
  85. if (str.IndexOf ('\\') == -1)
  86. return str;
  87. string result = str.Replace ("\\;", ";");
  88. result = result.Replace ("\\>", ">");
  89. result = result.Replace ("\\<", "<");
  90. result = result.Replace ("\\\\", "\\");
  91. return result;
  92. }
  93. private static string GetEnclosedString (string input)
  94. {
  95. if (input [0] != '<')
  96. throw new ArgumentException (input);
  97. int count = 1;
  98. bool escaped = false;
  99. StringBuilder result = new StringBuilder ();
  100. for (int i = 1; count != 0 && i < input.Length; i++) {
  101. char c = input [i];
  102. if (escaped)
  103. escaped = false;
  104. else if (c == '\\')
  105. escaped = true;
  106. else if (c == '<')
  107. count++;
  108. else if (c == '>')
  109. count--;
  110. result.Append (c);
  111. }
  112. result.Length--;
  113. return result.ToString ();
  114. }
  115. private static string [] GetStringValues (string input)
  116. {
  117. if (input == null || input.Length == 0)
  118. return new string [0];
  119. int length = input.Length;
  120. bool escaped = false;
  121. int opened = 0;
  122. ArrayList list = new ArrayList ();
  123. StringBuilder builder = new StringBuilder ();
  124. for (int i = 0; i < length; i++) {
  125. char c = input [i];
  126. if (escaped)
  127. escaped = false;
  128. else if (c == '\\')
  129. escaped = true;
  130. else if (c == '<')
  131. opened++;
  132. else if (c == '>')
  133. opened--;
  134. else if (c == ';' && opened == 0) {
  135. list.Add (builder.ToString ());
  136. builder = new StringBuilder ();
  137. continue;
  138. }
  139. builder.Append (c);
  140. }
  141. list.Add (builder.ToString ());
  142. string [] result = new string [list.Count];
  143. list.CopyTo (result, 0);
  144. return result;
  145. }
  146. private object DeserializeObject (string input)
  147. {
  148. if (input == null || input.Length < 2)
  149. return null;
  150. object obj;
  151. string enclosed = GetEnclosedString (input.Substring (1));
  152. string [] splitted;
  153. switch (input [0]) {
  154. case booleanID:
  155. obj = enclosed.Length == 1;
  156. break;
  157. case stringID:
  158. obj = UnEscapeSpecialChars (enclosed);
  159. break;
  160. case int16ID:
  161. obj = Int16.Parse (enclosed);
  162. break;
  163. case int32ID:
  164. obj = Int32.Parse (enclosed);
  165. break;
  166. case int64ID:
  167. obj = Int64.Parse (enclosed);
  168. break;
  169. case colorID:
  170. obj = Color.FromArgb (Int32.Parse (enclosed));
  171. break;
  172. case pairID:
  173. Pair pair = new Pair ();
  174. obj = pair;
  175. splitted = GetStringValues (enclosed);
  176. if (splitted.Length > 0) {
  177. pair.First = DeserializeObject (splitted [0]);
  178. if (splitted.Length > 1)
  179. pair.Second = DeserializeObject (splitted [1]);
  180. }
  181. break;
  182. case tripletID:
  183. Triplet triplet = new Triplet ();
  184. obj = triplet;
  185. splitted = GetStringValues (enclosed);
  186. if (splitted.Length == 0)
  187. break;
  188. triplet.First = DeserializeObject (splitted [0]);
  189. if (splitted.Length < 1)
  190. break;
  191. triplet.Second = DeserializeObject (splitted [1]);
  192. if (splitted.Length < 2)
  193. break;
  194. triplet.Third = DeserializeObject (splitted [2]);
  195. break;
  196. case arrayListID:
  197. case arrayID:
  198. ArrayList list = new ArrayList ();
  199. obj = list;
  200. splitted = GetStringValues (enclosed);
  201. foreach (string s in splitted) {
  202. object o = DeserializeObject (s);
  203. list.Add (o);
  204. }
  205. if (input [0] == arrayID)
  206. obj = list.ToArray (typeof (object));
  207. break;
  208. case hashtableID:
  209. object key;
  210. object value;
  211. Hashtable hash = new Hashtable ();
  212. obj = hash;
  213. splitted = GetStringValues (enclosed);
  214. int length = splitted.Length;
  215. for (int i = 0; i < length; i++) {
  216. key = DeserializeObject (splitted [i++]);
  217. if (i < length)
  218. value = DeserializeObject (splitted [i]);
  219. else
  220. value = null;
  221. hash.Add (key, value);
  222. }
  223. break;
  224. case binaryID:
  225. byte [] buffer = Convert.FromBase64String (enclosed);
  226. MemoryStream ms = new MemoryStream (buffer);
  227. BinaryFormatter fmt = new BinaryFormatter ();
  228. obj = fmt.Deserialize (ms);
  229. break;
  230. case dateTimeID:
  231. obj = new DateTime (Int64.Parse (enclosed));
  232. break;
  233. default:
  234. throw new ArgumentException ("input");
  235. }
  236. return obj;
  237. }
  238. public void Serialize (Stream stream, object value)
  239. {
  240. if (stream == null)
  241. throw new ArgumentNullException ("stream");
  242. if (value == null)
  243. throw new ArgumentNullException ("value");
  244. StreamWriter writer = new StreamWriter (stream);
  245. Serialize (writer, value);
  246. writer.Flush ();
  247. }
  248. public void Serialize (TextWriter output, object value)
  249. {
  250. if (value == null)
  251. return;
  252. if (output == null)
  253. throw new ArgumentNullException ("output");
  254. StringBuilder builder = new StringBuilder ();
  255. StringWriter writer = new StringWriter (builder);
  256. SerializeObject (writer, value);
  257. byte [] bytes = WebEncoding.Encoding.GetBytes (builder.ToString ());
  258. output.Write (Convert.ToBase64String (bytes));
  259. }
  260. private static void WriteBoolean (LosFormatter formatter, TextWriter output, object value)
  261. {
  262. if (value == null)
  263. return;
  264. output.Write (booleanID);
  265. bool b = (bool) value;
  266. output.Write (b ? "<t>" : "<>");
  267. }
  268. private static void WritePair (LosFormatter formatter, TextWriter output, object value)
  269. {
  270. if (value == null)
  271. return;
  272. output.Write (pairID);
  273. Pair pair = (Pair) value;
  274. output.Write ('<');
  275. formatter.SerializeObject (output, pair.First);
  276. output.Write (';');
  277. formatter.SerializeObject (output, pair.Second);
  278. output.Write ('>');
  279. }
  280. private static void WriteTriplet (LosFormatter formatter, TextWriter output, object value)
  281. {
  282. if (value == null)
  283. return;
  284. output.Write (tripletID);
  285. Triplet triplet = (Triplet) value;
  286. output.Write ('<');
  287. formatter.SerializeObject (output, triplet.First);
  288. output.Write (';');
  289. formatter.SerializeObject (output, triplet.Second);
  290. output.Write (';');
  291. formatter.SerializeObject (output, triplet.Third);
  292. output.Write ('>');
  293. }
  294. private static void WriteColor (LosFormatter formatter, TextWriter output, object value)
  295. {
  296. if (value == null)
  297. return;
  298. Color c = (Color) value;
  299. output.Write (String.Format ("{0}<{1}>", colorID, c.ToArgb ()));
  300. }
  301. private static void WriteArrayList (LosFormatter formatter, TextWriter output, object value)
  302. {
  303. if (value == null)
  304. return;
  305. output.Write (arrayListID);
  306. output.Write ('<');
  307. ArrayList list = (ArrayList) value;
  308. for (int i = 0; i < list.Count; i++) {
  309. formatter.SerializeObject (output, list [i]);
  310. if (i != list.Count - 1)
  311. output.Write (';');
  312. }
  313. output.Write('>');
  314. }
  315. private static void WriteArray (LosFormatter formatter, TextWriter output, object value)
  316. {
  317. if (value == null)
  318. return;
  319. output.Write (arrayID);
  320. output.Write ('<');
  321. Array array = (Array) value;
  322. for (int i = 0; i < array.Length; i++) {
  323. formatter.SerializeObject (output, array.GetValue (i));
  324. if (i != array.Length - 1)
  325. output.Write (';');
  326. }
  327. output.Write('>');
  328. }
  329. private static void WriteHashtable (LosFormatter formatter, TextWriter output, object value)
  330. {
  331. if (value == null)
  332. return;
  333. output.Write (hashtableID);
  334. output.Write ('<');
  335. Hashtable hash = (Hashtable) value;
  336. int i = 0;
  337. foreach (DictionaryEntry entry in hash) {
  338. formatter.SerializeObject (output, entry.Key);
  339. output.Write (';');
  340. formatter.SerializeObject (output, entry.Value);
  341. if (i != hash.Count - 1)
  342. output.Write (';');
  343. i++;
  344. }
  345. output.Write('>');
  346. }
  347. private static void WriteDateTime (LosFormatter formatter, TextWriter output, object value)
  348. {
  349. if (value == null)
  350. return;
  351. output.Write (dateTimeID);
  352. output.Write ('<');
  353. output.Write (((DateTime) value).Ticks);
  354. output.Write('>');
  355. }
  356. private static string EscapeSpecialChars (string str)
  357. {
  358. if (str.IndexOfAny (specialChars) == -1)
  359. return str;
  360. string result = str.Replace ("\\", "\\\\");
  361. result = result.Replace ("<", "\\<");
  362. result = result.Replace (">", "\\>");
  363. result = result.Replace (";", "\\;");
  364. return result;
  365. }
  366. private void SerializeBinary (TextWriter output, object value)
  367. {
  368. WebTrace.PushContext ("LosFormatter.SerializeBinary");
  369. /* This is just for debugging purposes */
  370. /*if (value is Array) {
  371. Array array = (Array) value;
  372. for (int i = 0; i < array.Length; i++) {
  373. object o = array.GetValue (i);
  374. if (o == null)
  375. WebTrace.WriteLine ("\t{0} is null", i);
  376. else
  377. WebTrace.WriteLine ("\t{0} {1} {2}", i, o.GetType (), o);
  378. }
  379. }
  380. */
  381. BinaryFormatter fmt = new BinaryFormatter ();
  382. MemoryStream stream = new MemoryStream ();
  383. fmt.Serialize (stream, value);
  384. output.Write (binaryID);
  385. output.Write ('<');
  386. byte [] buffer = stream.GetBuffer ();
  387. output.Write (Convert.ToBase64String (buffer));
  388. output.Write ('>');
  389. WebTrace.PopContext ();
  390. }
  391. private void SerializeObject (TextWriter output, object value)
  392. {
  393. WebTrace.PushContext ("LosFormatter.SerializeObject");
  394. if (value == null) {
  395. WebTrace.WriteLine ("value is null");
  396. WebTrace.PopContext ();
  397. return;
  398. }
  399. Type t = value.GetType ();
  400. if (t.IsArray)
  401. t = typeof (Array);
  402. if (specialTypes.Contains (t)) {
  403. WriteObject w = (WriteObject) specialTypes [t];
  404. w (this, output, value);
  405. WebTrace.WriteLine ("special type: {0}", value.GetType ());
  406. WebTrace.PopContext ();
  407. return;
  408. }
  409. if (idToType.Contains (t)) {
  410. char c = (char) idToType [t];
  411. string s = EscapeSpecialChars (value.ToString ());
  412. output.Write (String.Format ("{0}<{1}>", c, value.ToString ()));
  413. WebTrace.WriteLine ("regular type: {0}", value.GetType ());
  414. WebTrace.PopContext ();
  415. return;
  416. }
  417. SerializeBinary (output, value);
  418. WebTrace.PopContext ();
  419. }
  420. }
  421. }