2 // System.Web.UI.ObjectStateFormatter
5 // Ben Maurer (bmaurer@users.sourceforge.net)
6 // Gonzalo Paniagua (gonzalo@ximian.com)
9 // (c) Copyright 2004 Novell, Inc. (http://www.novell.com)
14 using System.Collections;
15 using System.ComponentModel;
16 using System.Globalization;
19 using System.Reflection;
20 using System.Runtime.Serialization.Formatters.Binary;
21 using System.Runtime.Serialization;
23 using System.Web.UI.WebControls;
24 using System.Web.Util;
25 using System.Diagnostics;
27 namespace System.Web.UI {
33 sealed class ObjectStateFormatter : IFormatter {
34 public object Deserialize (Stream inputStream)
36 if (inputStream == null)
37 throw new ArgumentNullException ("inputStream");
39 return DeserializeObject (new BinaryReader (inputStream));
42 public object Deserialize (string inputString)
44 if (inputString == null)
45 throw new ArgumentNullException ("inputString");
47 if (inputString == "")
50 return Deserialize (new MemoryStream (Convert.FromBase64String (inputString)));
53 public string Serialize (object stateGraph)
55 if (stateGraph == null)
58 MemoryStream ms = new MemoryStream ();
59 Serialize (ms, stateGraph);
62 ms.WriteTo (File.OpenWrite (Path.GetTempFileName ()));
65 return Convert.ToBase64String (ms.GetBuffer (), 0, (int) ms.Length);
68 public void Serialize (Stream outputStream, object stateGraph)
70 if (outputStream == null)
71 throw new ArgumentNullException ("outputStream");
73 if (stateGraph == null)
74 throw new ArgumentNullException ("stateGraph");
76 SerializeValue (new BinaryWriter (outputStream), stateGraph);
79 void SerializeValue (BinaryWriter w, object o)
81 ObjectFormatter.WriteObject (w, o, new WriterContext ());
84 object DeserializeObject (BinaryReader r)
86 return ObjectFormatter.ReadObject (r, new ReaderContext ());
91 object IFormatter.Deserialize (Stream serializationStream)
93 return Deserialize (serializationStream);
96 void IFormatter.Serialize (Stream serializationStream, object stateGraph)
98 Serialize (serializationStream, stateGraph);
101 SerializationBinder IFormatter.Binder {
106 StreamingContext IFormatter.Context {
107 get { return new StreamingContext (StreamingContextStates.All); }
111 ISurrogateSelector IFormatter.SurrogateSelector {
118 #region Object Readers/Writers
120 class WriterContext {
124 public bool RegisterCache (object o, out short key)
127 cache = new Hashtable ();
128 cache.Add (o, key = nextKey++);
132 object posKey = cache [o];
133 if (posKey == null) {
134 cache.Add (o, key = nextKey++);
138 key = (short) posKey;
143 class ReaderContext {
146 public void CacheItem (object o)
149 cache = new ArrayList ();
154 public object GetCache (short key)
160 abstract class ObjectFormatter {
161 static readonly Hashtable writeMap = new Hashtable ();
162 static ObjectFormatter [] readMap = new ObjectFormatter [256];
163 static BinaryObjectFormatter binaryObjectFormatter;
164 static TypeFormatter typeFormatter;
165 static EnumFormatter enumFormatter;
166 static SingleRankArrayFormatter singleRankArrayFormatter;
167 static TypeConverterFormatter typeConverterFormatter;
169 static ObjectFormatter ()
171 new StringFormatter ().Register ();
172 new Int64Formatter ().Register ();
173 new Int32Formatter ().Register ();
174 new Int16Formatter ().Register ();
175 new ByteFormatter ().Register ();
176 new BooleanFormatter ().Register ();
177 new CharFormatter ().Register ();
178 new DateTimeFormatter ().Register ();
179 new PairFormatter ().Register ();
180 new TripletFormatter ().Register ();
181 new ArrayListFormatter ().Register ();
182 new HashtableFormatter ().Register ();
183 new ObjectArrayFormatter ().Register ();
184 new UnitFormatter ().Register ();
185 new FontUnitFormatter ().Register ();
187 new ColorFormatter ().Register ();
189 enumFormatter = new EnumFormatter ();
190 enumFormatter.Register ();
192 typeFormatter = new TypeFormatter ();
193 typeFormatter.Register ();
195 singleRankArrayFormatter = new SingleRankArrayFormatter ();
196 singleRankArrayFormatter.Register ();
198 typeConverterFormatter = new TypeConverterFormatter ();
199 typeConverterFormatter.Register ();
201 binaryObjectFormatter = new BinaryObjectFormatter ();
202 binaryObjectFormatter.Register ();
206 static byte nextId = 1;
208 public ObjectFormatter ()
210 PrimaryId = nextId ++;
211 if (NumberOfIds == 1)
214 SecondaryId = nextId ++;
215 if (NumberOfIds == 2)
218 TertiaryId = nextId ++;
219 if (NumberOfIds == 3)
222 throw new Exception ();
225 protected readonly byte PrimaryId, SecondaryId = 255, TertiaryId = 255;
227 protected abstract void Write (BinaryWriter w, object o, WriterContext ctx);
228 protected abstract object Read (byte token, BinaryReader r, ReaderContext ctx);
229 protected abstract Type Type { get; }
230 protected virtual int NumberOfIds { get { return 1; } }
232 public virtual void Register ()
234 writeMap [Type] = this;
235 readMap [PrimaryId] = this;
236 if (SecondaryId != 255) {
237 readMap [SecondaryId] = this;
238 if (TertiaryId != 255)
239 readMap [TertiaryId] = this;
243 public static void WriteObject (BinaryWriter w, object o, WriterContext ctx)
247 Trace.WriteLine (String.Format ("Writing {0} (type: {1})", o, o.GetType ()));
250 Trace.WriteLine ("Writing null");
252 long pos = w.BaseStream.Position;
260 Type t = o.GetType ();
262 ObjectFormatter fmt = writeMap [t] as ObjectFormatter;
264 // Handle abstract types here
270 else if (t.IsArray && ((Array) o).Rank == 1)
271 fmt = singleRankArrayFormatter;
273 TypeConverter converter;
274 converter = TypeDescriptor.GetConverter (o);
275 if (converter == null ||
276 !converter.CanConvertTo (typeof (string)) ||
277 !converter.CanConvertFrom (typeof (string))) {
278 fmt = binaryObjectFormatter;
280 typeConverterFormatter.Converter = converter;
281 fmt = typeConverterFormatter;
286 fmt.Write (w, o, ctx);
289 Trace.WriteLine (String.Format ("Wrote {0} (type: {1}) {2} bytes", o, o.GetType (), w.BaseStream.Position - pos));
293 public static object ReadObject (BinaryReader r, ReaderContext ctx)
295 byte sig = r.ReadByte ();
300 return readMap [sig].Read (sig, r, ctx);
303 protected void Write7BitEncodedInt (BinaryWriter w, int value)
306 int high = (value >> 7) & 0x01ffffff;
307 byte b = (byte)(value & 0x7f);
310 b = (byte)(b | 0x80);
318 protected int Read7BitEncodedInt (BinaryReader r)
327 ret = ret | ((b & 0x7f) << shift);
329 } while ((b & 0x80) == 0x80);
335 #region Primitive Formatters
336 class StringFormatter : ObjectFormatter {
337 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
340 if (ctx.RegisterCache (o, out key)) {
341 w.Write (SecondaryId);
349 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
351 if (token == PrimaryId) {
352 string s = r.ReadString ();
356 return ctx.GetCache (r.ReadInt16 ());
359 protected override Type Type {
360 get { return typeof (string); }
363 protected override int NumberOfIds {
368 class Int64Formatter : ObjectFormatter {
369 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
375 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
377 return r.ReadInt64 ();
379 protected override Type Type {
380 get { return typeof (long); }
384 class Int32Formatter : ObjectFormatter {
385 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
388 if ((int)(byte) i == i) {
389 w.Write (SecondaryId);
397 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
399 if (token == PrimaryId)
400 return r.ReadInt32 ();
402 return (int) r.ReadByte ();
404 protected override Type Type {
405 get { return typeof (int); }
408 protected override int NumberOfIds {
413 class Int16Formatter : ObjectFormatter {
414 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
420 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
422 return r.ReadInt16 ();
424 protected override Type Type {
425 get { return typeof (short); }
429 class ByteFormatter : ObjectFormatter {
430 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
436 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
438 return r.ReadByte ();
440 protected override Type Type {
441 get { return typeof (byte); }
445 class BooleanFormatter : ObjectFormatter {
446 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
451 w.Write (SecondaryId);
454 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
456 return token == PrimaryId;
459 protected override Type Type {
460 get { return typeof (bool); }
463 protected override int NumberOfIds {
468 class CharFormatter : ObjectFormatter {
469 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
475 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
477 return r.ReadChar ();
480 protected override Type Type {
481 get { return typeof (char); }
485 class DateTimeFormatter : ObjectFormatter {
486 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
489 w.Write (((DateTime) o).Ticks);
492 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
494 return new DateTime (r.ReadInt64 ());
497 protected override Type Type {
498 get { return typeof (DateTime); }
502 class PairFormatter : ObjectFormatter {
503 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
507 WriteObject (w, p.First, ctx);
508 WriteObject (w, p.Second, ctx);
511 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
513 Pair p = new Pair ();
514 p.First = ReadObject (r, ctx);
515 p.Second = ReadObject (r, ctx);
519 protected override Type Type {
520 get { return typeof (Pair); }
524 class TripletFormatter : ObjectFormatter {
525 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
527 Triplet t = (Triplet) o;
529 WriteObject (w, t.First, ctx);
530 WriteObject (w, t.Second, ctx);
531 WriteObject (w, t.Third, ctx);
534 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
536 Triplet t = new Triplet ();
537 t.First = ReadObject (r, ctx);
538 t.Second = ReadObject (r, ctx);
539 t.Third = ReadObject (r, ctx);
543 protected override Type Type {
544 get { return typeof (Triplet); }
548 class ArrayListFormatter : ObjectFormatter {
549 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
551 ArrayList l = (ArrayList) o;
554 Write7BitEncodedInt (w, l.Count);
555 foreach (object i in l)
556 WriteObject (w, i, ctx);
559 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
561 int len = Read7BitEncodedInt (r);
562 ArrayList l = new ArrayList (len);
564 for (int i = 0; i < len; i++)
565 l.Add (ReadObject (r, ctx));
570 protected override Type Type {
571 get { return typeof (ArrayList); }
575 class HashtableFormatter : ObjectFormatter {
576 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
578 Hashtable ht = (Hashtable) o;
581 Write7BitEncodedInt (w, ht.Count);
582 foreach (DictionaryEntry de in ht) {
583 WriteObject (w, de.Key, ctx);
584 WriteObject (w, de.Value, ctx);
588 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
590 int len = Read7BitEncodedInt (r);
591 Hashtable ht = new Hashtable (len);
593 for (int i = 0; i < len; i++) {
594 object key = ReadObject (r, ctx);
595 object val = ReadObject (r, ctx);
603 protected override Type Type {
604 get { return typeof (Hashtable); }
608 class ObjectArrayFormatter : ObjectFormatter {
609 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
611 object [] val = (object []) o;
614 Write7BitEncodedInt (w, val.Length);
615 foreach (object i in val)
616 WriteObject (w, i, ctx);
619 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
621 int len = Read7BitEncodedInt (r);
622 object [] ret = new object [len];
624 for (int i = 0; i < len; i++)
625 ret [i] = ReadObject (r, ctx);
630 protected override Type Type {
631 get { return typeof (object []); }
637 #region System.Web Optimizations
638 class ColorFormatter : ObjectFormatter {
639 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
643 if (!c.IsKnownColor) {
645 w.Write (c.ToArgb ());
647 w.Write (SecondaryId);
648 w.Write ((int) c.ToKnownColor ());
652 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
654 if (token == PrimaryId)
655 return Color.FromArgb (r.ReadInt32 ());
657 return Color.FromKnownColor ((KnownColor) r.ReadInt32 ());
660 protected override Type Type {
661 get { return typeof (Color); }
664 protected override int NumberOfIds {
671 #region Special Formatters
672 class EnumFormatter : ObjectFormatter {
673 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
675 object value = Convert.ChangeType (o, ((Enum) o).GetTypeCode ());
677 WriteObject (w, o.GetType (), ctx);
678 WriteObject (w, value, ctx);
681 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
683 Type t = (Type) ReadObject (r, ctx);
684 object value = ReadObject (r, ctx);
686 return Enum.ToObject (t, value);
688 protected override Type Type {
689 get { return typeof (Enum); }
693 class TypeFormatter : ObjectFormatter {
694 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
697 if (ctx.RegisterCache (o, out key)) {
698 w.Write (SecondaryId);
702 w.Write (((Type) o).FullName);
704 // We should cache the name of the assembly
705 w.Write (((Type) o).Assembly.FullName);
709 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
711 if (token == PrimaryId) {
712 string type = r.ReadString ();
713 string assembly = r.ReadString ();
715 Type t = Assembly.Load (assembly).GetType (type);
719 return ctx.GetCache (r.ReadInt16 ());
723 protected override Type Type {
724 get { return typeof (Type); }
727 protected override int NumberOfIds {
732 class SingleRankArrayFormatter : ObjectFormatter {
733 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
735 Array val = (Array) o;
738 WriteObject (w, val.GetType ().GetElementType (), ctx);
740 Write7BitEncodedInt (w, val.Length);
741 foreach (object i in val)
742 WriteObject (w, i, ctx);
745 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
747 Type t = (Type) ReadObject (r, ctx);
748 int len = Read7BitEncodedInt (r);
749 Array val = Array.CreateInstance (t, len);
751 for (int i = 0; i < len; i++)
752 val.SetValue (ReadObject (r, ctx), i);
757 protected override Type Type {
758 get { return typeof (Array); }
762 class FontUnitFormatter : StringFormatter {
763 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
765 base.Write (w, o.ToString (), ctx);
768 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
770 return FontUnit.Parse ((string) base.Read (token, r, ctx));
773 protected override Type Type {
774 get { return typeof (FontUnit); }
778 class UnitFormatter : StringFormatter {
779 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
781 base.Write (w, o.ToString (), ctx);
784 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
786 return Unit.Parse ((string) base.Read (token, r, ctx));
789 protected override Type Type {
790 get { return typeof (Unit); }
794 class TypeConverterFormatter : StringFormatter {
795 TypeConverter converter;
797 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
800 ObjectFormatter.WriteObject (w, o.GetType (), ctx);
801 string v = (string) converter.ConvertTo (null, CultureInfo.InvariantCulture,
803 base.Write (w, v, ctx);
806 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
808 Type t = (Type) ObjectFormatter.ReadObject (r, ctx);
809 converter = TypeDescriptor.GetConverter (t);
810 token = r.ReadByte ();
811 string v = (string) base.Read (token, r, ctx);
812 return converter.ConvertFrom (null, CultureInfo.InvariantCulture, v);
815 protected override Type Type {
816 get { return typeof (TypeConverter); }
819 public TypeConverter Converter {
820 set { converter = value; }
824 class BinaryObjectFormatter : ObjectFormatter {
825 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
829 MemoryStream ms = new MemoryStream (128);
830 new BinaryFormatter ().Serialize (ms, o);
832 byte [] buf = ms.GetBuffer ();
833 Write7BitEncodedInt (w, buf.Length);
834 w.Write (buf, 0, buf.Length);
837 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
839 int len = Read7BitEncodedInt (r);
840 byte [] buf = r.ReadBytes (len);
841 if (buf.Length != len)
842 throw new Exception ();
844 return new BinaryFormatter ().Deserialize (new MemoryStream (buf));
847 protected override Type Type {
848 get { return typeof (object); }