2 // System.Web.UI.LosFormatter
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // (C) 2002 Ximian, Inc (http://www.ximian.com)
11 using System.Collections;
14 using System.Runtime.Serialization.Formatters.Binary;
17 using System.Web.Util;
19 namespace System.Web.UI
21 public sealed class LosFormatter
23 delegate void WriteObject (LosFormatter formatter, TextWriter writer, object value);
24 static char [] specialChars = new char [] {'<', '>', ';'};
26 const char booleanID = 'o';
27 const char stringID = 's';
28 const char charID = 'c';
29 const char int16ID = 'i';
30 const char int32ID = 'I';
31 const char int64ID = 'l';
32 const char colorID = 'C';
33 const char pairID = 'p';
34 const char tripletID = 't';
35 const char arrayListID = 'L';
36 const char hashtableID = 'h';
37 const char binaryID = 'b';
38 const char arrayID = 'a';
40 static Hashtable specialTypes;
41 static Hashtable idToType;
43 static LosFormatter ()
45 specialTypes = new Hashtable ();
46 specialTypes.Add (typeof (Boolean), new WriteObject (WriteBoolean));
47 specialTypes.Add (typeof (Pair), new WriteObject (WritePair));
48 specialTypes.Add (typeof (Triplet), new WriteObject (WriteTriplet));
49 specialTypes.Add (typeof (Color), new WriteObject (WriteColor));
50 specialTypes.Add (typeof (ArrayList), new WriteObject (WriteArrayList));
51 specialTypes.Add (typeof (Hashtable), new WriteObject (WriteHashtable));
52 specialTypes.Add (typeof (Array), new WriteObject (WriteArray));
54 idToType = new Hashtable ();
55 idToType.Add (typeof (string), stringID);
56 idToType.Add (typeof (char), charID);
57 idToType.Add (typeof (Int16), int16ID);
58 idToType.Add (typeof (Int32), int32ID);
59 idToType.Add (typeof (Int64), int64ID);
60 idToType.Add (typeof (Boolean), booleanID);
61 idToType.Add (typeof (Pair), pairID);
62 idToType.Add (typeof (Triplet), tripletID);
63 idToType.Add (typeof (Color), colorID);
64 idToType.Add (typeof (ArrayList), arrayListID);
65 idToType.Add (typeof (Hashtable), hashtableID);
66 idToType.Add (typeof (Array), arrayID);
69 public object Deserialize (Stream stream)
72 throw new ArgumentNullException ("stream");
74 return Deserialize (new StreamReader (stream));
77 public object Deserialize (TextReader input)
80 throw new ArgumentNullException ("input");
82 return Deserialize (input.ReadToEnd ());
85 public object Deserialize (string input)
88 throw new ArgumentNullException ("input");
90 string real_input = WebEncoding.Encoding.GetString (Convert.FromBase64String (input));
91 return DeserializeObject (real_input);
94 private static string UnEscapeSpecialChars (string str)
96 if (str.IndexOf ('\\') == -1)
99 string result = str.Replace ("\\;", ";");
100 result = result.Replace ("\\>", ">");
101 result = result.Replace ("\\<", "<");
102 result = result.Replace ("\\\\", "\\");
106 private static string GetEnclosedString (string input)
108 if (input [0] != '<')
109 throw new ArgumentException (input);
112 bool escaped = false;
113 StringBuilder result = new StringBuilder ();
114 for (int i = 1; count != 0 && i < input.Length; i++) {
129 return result.ToString ();
132 private static string [] GetStringValues (string input)
134 if (input == null || input.Length == 0)
135 return new string [0];
137 int length = input.Length;
138 bool escaped = false;
140 ArrayList list = new ArrayList ();
141 StringBuilder builder = new StringBuilder ();
142 for (int i = 0; i < length; i++) {
152 else if (c == ';' && opened == 0) {
153 list.Add (builder.ToString ());
154 builder = new StringBuilder ();
161 list.Add (builder.ToString ());
163 string [] result = new string [list.Count];
164 list.CopyTo (result, 0);
168 private object DeserializeObject (string input)
170 if (input == null || input.Length < 2)
174 string enclosed = GetEnclosedString (input.Substring (1));
179 obj = enclosed.Length == 1;
182 obj = UnEscapeSpecialChars (enclosed);
185 obj = Int16.Parse (enclosed);
188 obj = Int32.Parse (enclosed);
191 obj = Int64.Parse (enclosed);
194 obj = Color.FromArgb (Int32.Parse (enclosed));
197 Pair pair = new Pair ();
199 splitted = GetStringValues (enclosed);
200 if (splitted.Length > 0) {
201 pair.First = DeserializeObject (splitted [0]);
202 if (splitted.Length > 1)
203 pair.Second = DeserializeObject (splitted [1]);
207 Triplet triplet = new Triplet ();
209 splitted = GetStringValues (enclosed);
210 if (splitted.Length == 0)
212 triplet.First = DeserializeObject (splitted [0]);
213 if (splitted.Length < 1)
215 triplet.Second = DeserializeObject (splitted [1]);
216 if (splitted.Length < 2)
218 triplet.Third = DeserializeObject (splitted [2]);
222 ArrayList list = new ArrayList ();
224 splitted = GetStringValues (enclosed);
225 foreach (string s in splitted) {
226 object o = DeserializeObject (s);
230 if (input [0] == arrayID)
231 obj = list.ToArray (typeof (object));
237 Hashtable hash = new Hashtable ();
239 splitted = GetStringValues (enclosed);
240 int length = splitted.Length;
241 for (int i = 0; i < length; i++) {
242 key = DeserializeObject (splitted [i++]);
244 value = DeserializeObject (splitted [i]);
248 hash.Add (key, value);
252 byte [] buffer = WebEncoding.Encoding.GetBytes (enclosed);
253 MemoryStream ms = new MemoryStream (buffer);
254 BinaryFormatter fmt = new BinaryFormatter ();
255 obj = fmt.Deserialize (ms);
258 throw new ArgumentException ("input");
264 public void Serialize (Stream stream, object value)
267 throw new ArgumentNullException ("stream");
270 throw new ArgumentNullException ("value");
272 StreamWriter writer = new StreamWriter (stream);
273 Serialize (writer, value);
277 public void Serialize (TextWriter output, object value)
283 throw new ArgumentNullException ("output");
285 StringBuilder builder = new StringBuilder ();
286 StringWriter writer = new StringWriter (builder);
287 SerializeObject (writer, value);
288 byte [] bytes = WebEncoding.Encoding.GetBytes (builder.ToString ());
289 output.Write (Convert.ToBase64String (bytes));
292 private static void WriteBoolean (LosFormatter formatter, TextWriter output, object value)
297 output.Write (booleanID);
298 bool b = (bool) value;
299 output.Write (b ? "<t>" : "<>");
302 private static void WritePair (LosFormatter formatter, TextWriter output, object value)
307 output.Write (pairID);
308 Pair pair = (Pair) value;
310 formatter.SerializeObject (output, pair.First);
312 formatter.SerializeObject (output, pair.Second);
316 private static void WriteTriplet (LosFormatter formatter, TextWriter output, object value)
321 output.Write (tripletID);
322 Triplet triplet = (Triplet) value;
324 formatter.SerializeObject (output, triplet.First);
326 formatter.SerializeObject (output, triplet.Second);
328 formatter.SerializeObject (output, triplet.Third);
332 private static void WriteColor (LosFormatter formatter, TextWriter output, object value)
337 Color c = (Color) value;
338 output.Write (String.Format ("{0}<{1}>", colorID, c.ToArgb ()));
341 private static void WriteArrayList (LosFormatter formatter, TextWriter output, object value)
346 output.Write (arrayListID);
348 ArrayList list = (ArrayList) value;
349 for (int i = 0; i < list.Count; i++) {
350 formatter.SerializeObject (output, list [i]);
351 if (i != list.Count - 1)
357 private static void WriteArray (LosFormatter formatter, TextWriter output, object value)
362 output.Write (arrayID);
364 Array array = (Array) value;
365 for (int i = 0; i < array.Length; i++) {
366 formatter.SerializeObject (output, array.GetValue (i));
367 if (i != array.Length - 1)
373 private static void WriteHashtable (LosFormatter formatter, TextWriter output, object value)
378 output.Write (hashtableID);
380 Hashtable hash = (Hashtable) value;
382 foreach (DictionaryEntry entry in hash) {
383 formatter.SerializeObject (output, entry.Key);
385 formatter.SerializeObject (output, entry.Value);
386 if (i != hash.Count - 1)
393 private static string EscapeSpecialChars (string str)
395 if (str.IndexOfAny (specialChars) == -1)
398 string result = str.Replace ("\\", "\\\\");
399 result = result.Replace ("<", "\\<");
400 result = result.Replace (">", "\\>");
401 result = result.Replace (";", "\\;");
405 private void SerializeBinary (TextWriter output, object value)
407 WebTrace.PushContext ("LosFormatter.SerializeBinary");
408 WebTrace.WriteLine ("not serializing value type: " + value.GetType ());
409 /* This is just for debugging purposes */
410 /*if (value is Array) {
411 Array array = (Array) value;
412 for (int i = 0; i < array.Length; i++) {
413 object o = array.GetValue (i);
415 WebTrace.WriteLine ("\t{0} is null", i);
417 WebTrace.WriteLine ("\t{0} {1} {2}", i, o.GetType (), o);
422 BinaryFormatter fmt = new BinaryFormatter ();
423 MemoryStream stream = new MemoryStream ();
425 fmt.Serialize (stream, value);
426 output.Write (binaryID);
428 byte [] buffer = stream.GetBuffer ();
429 output.Write (Convert.ToBase64String (stream.GetBuffer ()));
432 WebTrace.PopContext ();
435 private void SerializeObject (TextWriter output, object value)
437 WebTrace.PushContext ("LosFormatter.SerializeObject");
439 WebTrace.WriteLine ("value is null");
440 WebTrace.PopContext ();
444 Type t = value.GetType ();
448 if (specialTypes.Contains (t)) {
449 WriteObject w = (WriteObject) specialTypes [t];
450 w (this, output, value);
451 WebTrace.WriteLine ("special type: {0}", value.GetType ());
452 WebTrace.PopContext ();
456 if (idToType.Contains (t)) {
457 char c = (char) idToType [t];
458 string s = EscapeSpecialChars (value.ToString ());
459 output.Write (String.Format ("{0}<{1}>", c, value.ToString ()));
460 WebTrace.WriteLine ("regular type: {0}", value.GetType ());
461 WebTrace.PopContext ();
465 SerializeBinary (output, value);
466 WebTrace.PopContext ();