2 // System.Web.UI.ObjectStateFormatter
5 // Ben Maurer (bmaurer@users.sourceforge.net)
12 using System.Collections;
15 using System.Reflection;
16 using System.Runtime.Serialization.Formatters.Binary;
17 using System.Runtime.Serialization;
19 using System.Web.UI.WebControls;
20 using System.Web.Util;
21 using System.Diagnostics;
23 namespace System.Web.UI {
29 sealed class ObjectStateFormatter : IFormatter {
30 public object Deserialize (Stream inputStream)
32 if (inputStream == null)
33 throw new ArgumentNullException ("inputStream");
35 return DeserializeObject (new BinaryReader (inputStream));
38 public object Deserialize (string inputString)
40 if (inputString == null)
41 throw new ArgumentNullException ("inputString");
43 if (inputString == "")
46 return Deserialize (new MemoryStream (Convert.FromBase64String (inputString)));
49 public string Serialize (object stateGraph)
51 if (stateGraph == null)
54 MemoryStream ms = new MemoryStream ();
55 Serialize (ms, stateGraph);
58 ms.WriteTo (File.OpenWrite (Path.GetTempFileName ()));
61 return Convert.ToBase64String (ms.GetBuffer (), 0, (int) ms.Length);
64 public void Serialize (Stream outputStream, object stateGraph)
66 if (outputStream == null)
67 throw new ArgumentNullException ("outputStream");
69 if (stateGraph == null)
70 throw new ArgumentNullException ("stateGraph");
72 SerializeValue (new BinaryWriter (outputStream), stateGraph);
75 void SerializeValue (BinaryWriter w, object o)
77 ObjectFormatter.WriteObject (w, o, new WriterContext ());
80 object DeserializeObject (BinaryReader r)
82 return ObjectFormatter.ReadObject (r, new ReaderContext ());
87 object IFormatter.Deserialize (Stream serializationStream)
89 return Deserialize (serializationStream);
92 void IFormatter.Serialize (Stream serializationStream, object stateGraph)
94 Serialize (serializationStream, stateGraph);
97 SerializationBinder IFormatter.Binder {
102 StreamingContext IFormatter.Context {
103 get { return new StreamingContext (StreamingContextStates.All); }
107 ISurrogateSelector IFormatter.SurrogateSelector {
114 #region Object Readers/Writers
116 class WriterContext {
120 public bool RegisterCache (object o, out short key)
123 cache = new Hashtable ();
124 cache.Add (o, key = nextKey++);
128 object posKey = cache [o];
129 if (posKey == null) {
130 cache.Add (o, key = nextKey++);
134 key = (short) posKey;
139 class ReaderContext {
142 public void CacheItem (object o)
145 cache = new ArrayList ();
150 public object GetCache (short key)
156 abstract class ObjectFormatter {
157 static readonly Hashtable writeMap = new Hashtable ();
158 static ObjectFormatter [] readMap = new ObjectFormatter [256];
159 static BinaryObjectFormatter binaryObjectFormatter;
160 static TypeFormatter typeFormatter;
161 static EnumFormatter enumFormatter;
162 static SingleRankArrayFormatter singleRankArrayFormatter;
164 static ObjectFormatter ()
166 new StringFormatter ().Register ();
167 new Int64Formatter ().Register ();
168 new Int32Formatter ().Register ();
169 new Int16Formatter ().Register ();
170 new ByteFormatter ().Register ();
171 new BooleanFormatter ().Register ();
172 new CharFormatter ().Register ();
173 new DateTimeFormatter ().Register ();
174 new PairFormatter ().Register ();
175 new TripletFormatter ().Register ();
176 new ArrayListFormatter ().Register ();
177 new HashtableFormatter ().Register ();
178 new ObjectArrayFormatter ().Register ();
179 new UnitFormatter ().Register ();
180 new FontUnitFormatter ().Register ();
182 new ColorFormatter ().Register ();
184 enumFormatter = new EnumFormatter ();
185 enumFormatter.Register ();
187 typeFormatter = new TypeFormatter ();
188 typeFormatter.Register ();
190 singleRankArrayFormatter = new SingleRankArrayFormatter ();
191 singleRankArrayFormatter.Register ();
193 binaryObjectFormatter = new BinaryObjectFormatter ();
194 binaryObjectFormatter.Register ();
198 static byte nextId = 1;
200 public ObjectFormatter ()
202 PrimaryId = nextId ++;
203 if (NumberOfIds == 1)
206 SecondaryId = nextId ++;
207 if (NumberOfIds == 2)
210 TertiaryId = nextId ++;
211 if (NumberOfIds == 3)
214 throw new Exception ();
217 protected readonly byte PrimaryId, SecondaryId = 255, TertiaryId = 255;
219 protected abstract void Write (BinaryWriter w, object o, WriterContext ctx);
220 protected abstract object Read (byte token, BinaryReader r, ReaderContext ctx);
221 protected abstract Type Type { get; }
222 protected virtual int NumberOfIds { get { return 1; } }
224 public virtual void Register ()
226 writeMap [Type] = this;
227 readMap [PrimaryId] = this;
228 if (SecondaryId != 255) {
229 readMap [SecondaryId] = this;
230 if (TertiaryId != 255)
231 readMap [TertiaryId] = this;
235 public static void WriteObject (BinaryWriter w, object o, WriterContext ctx)
239 Trace.WriteLine (String.Format ("Writing {0} (type: {1})", o, o.GetType ()));
242 Trace.WriteLine ("Writing null");
244 long pos = w.BaseStream.Position;
252 Type t = o.GetType ();
254 ObjectFormatter fmt = writeMap [t] as ObjectFormatter;
256 // Handle abstract types here
262 else if (t.IsArray && ((Array) o).Rank == 1)
263 fmt = singleRankArrayFormatter;
265 fmt = binaryObjectFormatter;
268 fmt.Write (w, o, ctx);
271 Trace.WriteLine (String.Format ("Wrote {0} (type: {1}) {2} bytes", o, o.GetType (), w.BaseStream.Position - pos));
275 public static object ReadObject (BinaryReader r, ReaderContext ctx)
277 byte sig = r.ReadByte ();
282 return readMap [sig].Read (sig, r, ctx);
285 protected void Write7BitEncodedInt (BinaryWriter w, int value)
288 int high = (value >> 7) & 0x01ffffff;
289 byte b = (byte)(value & 0x7f);
292 b = (byte)(b | 0x80);
300 protected int Read7BitEncodedInt (BinaryReader r)
309 ret = ret | ((b & 0x7f) << shift);
311 } while ((b & 0x80) == 0x80);
317 #region Primitive Formatters
318 class StringFormatter : ObjectFormatter {
319 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
322 if (ctx.RegisterCache (o, out key)) {
323 w.Write (SecondaryId);
331 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
333 if (token == PrimaryId) {
334 string s = r.ReadString ();
338 return ctx.GetCache (r.ReadInt16 ());
341 protected override Type Type {
342 get { return typeof (string); }
345 protected override int NumberOfIds {
350 class Int64Formatter : ObjectFormatter {
351 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
357 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
359 return r.ReadInt64 ();
361 protected override Type Type {
362 get { return typeof (long); }
366 class Int32Formatter : ObjectFormatter {
367 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
370 if ((int)(byte) i == i) {
371 w.Write (SecondaryId);
379 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
381 if (token == PrimaryId)
382 return r.ReadInt32 ();
384 return (int) r.ReadByte ();
386 protected override Type Type {
387 get { return typeof (int); }
390 protected override int NumberOfIds {
395 class Int16Formatter : ObjectFormatter {
396 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
402 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
404 return r.ReadInt16 ();
406 protected override Type Type {
407 get { return typeof (short); }
411 class ByteFormatter : ObjectFormatter {
412 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
418 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
420 return r.ReadByte ();
422 protected override Type Type {
423 get { return typeof (byte); }
427 class BooleanFormatter : ObjectFormatter {
428 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
433 w.Write (SecondaryId);
436 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
438 return token == PrimaryId;
441 protected override Type Type {
442 get { return typeof (bool); }
445 protected override int NumberOfIds {
450 class CharFormatter : ObjectFormatter {
451 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
457 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
459 return r.ReadChar ();
462 protected override Type Type {
463 get { return typeof (char); }
467 class DateTimeFormatter : ObjectFormatter {
468 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
471 w.Write (((DateTime) o).Ticks);
474 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
476 return new DateTime (r.ReadInt64 ());
479 protected override Type Type {
480 get { return typeof (DateTime); }
484 class PairFormatter : ObjectFormatter {
485 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
489 WriteObject (w, p.First, ctx);
490 WriteObject (w, p.Second, ctx);
493 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
495 Pair p = new Pair ();
496 p.First = ReadObject (r, ctx);
497 p.Second = ReadObject (r, ctx);
501 protected override Type Type {
502 get { return typeof (Pair); }
506 class TripletFormatter : ObjectFormatter {
507 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
509 Triplet t = (Triplet) o;
511 WriteObject (w, t.First, ctx);
512 WriteObject (w, t.Second, ctx);
513 WriteObject (w, t.Third, ctx);
516 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
518 Triplet t = new Triplet ();
519 t.First = ReadObject (r, ctx);
520 t.Second = ReadObject (r, ctx);
521 t.Third = ReadObject (r, ctx);
525 protected override Type Type {
526 get { return typeof (Triplet); }
530 class ArrayListFormatter : ObjectFormatter {
531 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
533 ArrayList l = (ArrayList) o;
536 Write7BitEncodedInt (w, l.Count);
537 foreach (object i in l)
538 WriteObject (w, i, ctx);
541 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
543 int len = Read7BitEncodedInt (r);
544 ArrayList l = new ArrayList (len);
546 for (int i = 0; i < len; i++)
547 l.Add (ReadObject (r, ctx));
552 protected override Type Type {
553 get { return typeof (ArrayList); }
557 class HashtableFormatter : ObjectFormatter {
558 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
560 Hashtable ht = (Hashtable) o;
563 Write7BitEncodedInt (w, ht.Count);
564 foreach (DictionaryEntry de in ht) {
565 WriteObject (w, de.Key, ctx);
566 WriteObject (w, de.Value, ctx);
570 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
572 int len = Read7BitEncodedInt (r);
573 Hashtable ht = new Hashtable (len);
575 for (int i = 0; i < len; i++) {
576 object key = ReadObject (r, ctx);
577 object val = ReadObject (r, ctx);
585 protected override Type Type {
586 get { return typeof (Hashtable); }
590 class ObjectArrayFormatter : ObjectFormatter {
591 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
593 object [] val = (object []) o;
596 Write7BitEncodedInt (w, val.Length);
597 foreach (object i in val)
598 WriteObject (w, i, ctx);
601 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
603 int len = Read7BitEncodedInt (r);
604 object [] ret = new object [len];
606 for (int i = 0; i < len; i++)
607 ret [i] = ReadObject (r, ctx);
612 protected override Type Type {
613 get { return typeof (object []); }
619 #region System.Web Optimizations
620 class ColorFormatter : ObjectFormatter {
621 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
625 if (!c.IsKnownColor) {
627 w.Write (c.ToArgb ());
629 w.Write (SecondaryId);
630 w.Write ((int) c.ToKnownColor ());
634 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
636 if (token == PrimaryId)
637 return Color.FromArgb (r.ReadInt32 ());
639 return Color.FromKnownColor ((KnownColor) r.ReadInt32 ());
642 protected override Type Type {
643 get { return typeof (Color); }
646 protected override int NumberOfIds {
653 #region Special Formatters
654 class EnumFormatter : ObjectFormatter {
655 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
657 object value = Convert.ChangeType (o, ((Enum) o).GetTypeCode ());
659 WriteObject (w, o.GetType (), ctx);
660 WriteObject (w, value, ctx);
663 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
665 Type t = (Type) ReadObject (r, ctx);
666 object value = ReadObject (r, ctx);
668 return Enum.ToObject (t, value);
670 protected override Type Type {
671 get { return typeof (Enum); }
675 class TypeFormatter : ObjectFormatter {
676 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
679 if (ctx.RegisterCache (o, out key)) {
680 w.Write (SecondaryId);
684 w.Write (((Type) o).FullName);
686 // We should cache the name of the assembly
687 w.Write (((Type) o).Assembly.FullName);
691 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
693 if (token == PrimaryId) {
694 string type = r.ReadString ();
695 string assembly = r.ReadString ();
697 Type t = Assembly.Load (assembly).GetType (type);
701 return ctx.GetCache (r.ReadInt16 ());
705 protected override Type Type {
706 get { return typeof (Type); }
709 protected override int NumberOfIds {
714 class SingleRankArrayFormatter : ObjectFormatter {
715 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
717 Array val = (Array) o;
720 WriteObject (w, val.GetType ().GetElementType (), ctx);
722 Write7BitEncodedInt (w, val.Length);
723 foreach (object i in val)
724 WriteObject (w, i, ctx);
727 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
729 Type t = (Type) ReadObject (r, ctx);
730 int len = Read7BitEncodedInt (r);
731 Array val = Array.CreateInstance (t, len);
733 for (int i = 0; i < len; i++)
734 val.SetValue (ReadObject (r, ctx), i);
739 protected override Type Type {
740 get { return typeof (Array); }
744 class FontUnitFormatter : StringFormatter {
745 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
747 base.Write (w, o.ToString (), ctx);
750 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
752 return FontUnit.Parse ((string) base.Read (token, r, ctx));
755 protected override Type Type {
756 get { return typeof (FontUnit); }
760 class UnitFormatter : StringFormatter {
761 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
763 base.Write (w, o.ToString (), ctx);
766 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
768 return Unit.Parse ((string) base.Read (token, r, ctx));
771 protected override Type Type {
772 get { return typeof (Unit); }
776 class BinaryObjectFormatter : ObjectFormatter {
777 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
781 MemoryStream ms = new MemoryStream (128);
782 new BinaryFormatter ().Serialize (ms, o);
784 byte [] buf = ms.GetBuffer ();
785 Write7BitEncodedInt (w, buf.Length);
786 w.Write (buf, 0, buf.Length);
789 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
791 int len = Read7BitEncodedInt (r);
792 byte [] buf = r.ReadBytes (len);
793 if (buf.Length != len)
794 throw new Exception ();
796 return new BinaryFormatter ().Deserialize (new MemoryStream (buf));
799 protected override Type Type {
800 get { return typeof (object); }