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)
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System.Collections;
36 using System.ComponentModel;
37 using System.Globalization;
40 using System.Reflection;
41 using System.Runtime.Serialization.Formatters.Binary;
42 using System.Runtime.Serialization;
44 using System.Web.UI.WebControls;
45 using System.Web.Util;
46 using System.Diagnostics;
48 namespace System.Web.UI {
54 sealed class ObjectStateFormatter : IFormatter {
55 public object Deserialize (Stream inputStream)
57 if (inputStream == null)
58 throw new ArgumentNullException ("inputStream");
60 return DeserializeObject (new BinaryReader (inputStream));
63 public object Deserialize (string inputString)
65 if (inputString == null)
66 throw new ArgumentNullException ("inputString");
68 if (inputString == "")
71 return Deserialize (new MemoryStream (Convert.FromBase64String (inputString)));
74 public string Serialize (object stateGraph)
76 if (stateGraph == null)
79 MemoryStream ms = new MemoryStream ();
80 Serialize (ms, stateGraph);
83 ms.WriteTo (File.OpenWrite (Path.GetTempFileName ()));
86 return Convert.ToBase64String (ms.GetBuffer (), 0, (int) ms.Length);
89 public void Serialize (Stream outputStream, object stateGraph)
91 if (outputStream == null)
92 throw new ArgumentNullException ("outputStream");
94 if (stateGraph == null)
95 throw new ArgumentNullException ("stateGraph");
97 SerializeValue (new BinaryWriter (outputStream), stateGraph);
100 void SerializeValue (BinaryWriter w, object o)
102 ObjectFormatter.WriteObject (w, o, new WriterContext ());
105 object DeserializeObject (BinaryReader r)
107 return ObjectFormatter.ReadObject (r, new ReaderContext ());
112 object IFormatter.Deserialize (Stream serializationStream)
114 return Deserialize (serializationStream);
117 void IFormatter.Serialize (Stream serializationStream, object stateGraph)
119 Serialize (serializationStream, stateGraph);
122 SerializationBinder IFormatter.Binder {
127 StreamingContext IFormatter.Context {
128 get { return new StreamingContext (StreamingContextStates.All); }
132 ISurrogateSelector IFormatter.SurrogateSelector {
139 #region Object Readers/Writers
141 class WriterContext {
145 public bool RegisterCache (object o, out short key)
148 cache = new Hashtable ();
149 cache.Add (o, key = nextKey++);
153 object posKey = cache [o];
154 if (posKey == null) {
155 cache.Add (o, key = nextKey++);
159 key = (short) posKey;
164 class ReaderContext {
167 public void CacheItem (object o)
170 cache = new ArrayList ();
175 public object GetCache (short key)
181 abstract class ObjectFormatter {
182 static readonly Hashtable writeMap = new Hashtable ();
183 static ObjectFormatter [] readMap = new ObjectFormatter [256];
184 static BinaryObjectFormatter binaryObjectFormatter;
185 static TypeFormatter typeFormatter;
186 static EnumFormatter enumFormatter;
187 static SingleRankArrayFormatter singleRankArrayFormatter;
188 static TypeConverterFormatter typeConverterFormatter;
190 static ObjectFormatter ()
192 new StringFormatter ().Register ();
193 new Int64Formatter ().Register ();
194 new Int32Formatter ().Register ();
195 new Int16Formatter ().Register ();
196 new ByteFormatter ().Register ();
197 new BooleanFormatter ().Register ();
198 new CharFormatter ().Register ();
199 new DateTimeFormatter ().Register ();
200 new PairFormatter ().Register ();
201 new TripletFormatter ().Register ();
202 new ArrayListFormatter ().Register ();
203 new HashtableFormatter ().Register ();
204 new ObjectArrayFormatter ().Register ();
205 new UnitFormatter ().Register ();
206 new FontUnitFormatter ().Register ();
208 new ColorFormatter ().Register ();
210 enumFormatter = new EnumFormatter ();
211 enumFormatter.Register ();
213 typeFormatter = new TypeFormatter ();
214 typeFormatter.Register ();
216 singleRankArrayFormatter = new SingleRankArrayFormatter ();
217 singleRankArrayFormatter.Register ();
219 typeConverterFormatter = new TypeConverterFormatter ();
220 typeConverterFormatter.Register ();
222 binaryObjectFormatter = new BinaryObjectFormatter ();
223 binaryObjectFormatter.Register ();
227 static byte nextId = 1;
229 public ObjectFormatter ()
231 PrimaryId = nextId ++;
232 if (NumberOfIds == 1)
235 SecondaryId = nextId ++;
236 if (NumberOfIds == 2)
239 TertiaryId = nextId ++;
240 if (NumberOfIds == 3)
243 throw new Exception ();
246 protected readonly byte PrimaryId, SecondaryId = 255, TertiaryId = 255;
248 protected abstract void Write (BinaryWriter w, object o, WriterContext ctx);
249 protected abstract object Read (byte token, BinaryReader r, ReaderContext ctx);
250 protected abstract Type Type { get; }
251 protected virtual int NumberOfIds { get { return 1; } }
253 public virtual void Register ()
255 writeMap [Type] = this;
256 readMap [PrimaryId] = this;
257 if (SecondaryId != 255) {
258 readMap [SecondaryId] = this;
259 if (TertiaryId != 255)
260 readMap [TertiaryId] = this;
264 public static void WriteObject (BinaryWriter w, object o, WriterContext ctx)
268 Trace.WriteLine (String.Format ("Writing {0} (type: {1})", o, o.GetType ()));
271 Trace.WriteLine ("Writing null");
273 long pos = w.BaseStream.Position;
281 Type t = o.GetType ();
283 ObjectFormatter fmt = writeMap [t] as ObjectFormatter;
285 // Handle abstract types here
291 else if (t.IsArray && ((Array) o).Rank == 1)
292 fmt = singleRankArrayFormatter;
294 TypeConverter converter;
295 converter = TypeDescriptor.GetConverter (o);
296 if (converter == null ||
297 !converter.CanConvertTo (typeof (string)) ||
298 !converter.CanConvertFrom (typeof (string))) {
299 fmt = binaryObjectFormatter;
301 typeConverterFormatter.Converter = converter;
302 fmt = typeConverterFormatter;
307 fmt.Write (w, o, ctx);
310 Trace.WriteLine (String.Format ("Wrote {0} (type: {1}) {2} bytes", o, o.GetType (), w.BaseStream.Position - pos));
314 public static object ReadObject (BinaryReader r, ReaderContext ctx)
316 byte sig = r.ReadByte ();
321 return readMap [sig].Read (sig, r, ctx);
324 protected void Write7BitEncodedInt (BinaryWriter w, int value)
327 int high = (value >> 7) & 0x01ffffff;
328 byte b = (byte)(value & 0x7f);
331 b = (byte)(b | 0x80);
339 protected int Read7BitEncodedInt (BinaryReader r)
348 ret = ret | ((b & 0x7f) << shift);
350 } while ((b & 0x80) == 0x80);
356 #region Primitive Formatters
357 class StringFormatter : ObjectFormatter {
358 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
361 if (ctx.RegisterCache (o, out key)) {
362 w.Write (SecondaryId);
370 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
372 if (token == PrimaryId) {
373 string s = r.ReadString ();
377 return ctx.GetCache (r.ReadInt16 ());
380 protected override Type Type {
381 get { return typeof (string); }
384 protected override int NumberOfIds {
389 class Int64Formatter : ObjectFormatter {
390 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
396 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
398 return r.ReadInt64 ();
400 protected override Type Type {
401 get { return typeof (long); }
405 class Int32Formatter : ObjectFormatter {
406 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
409 if ((int)(byte) i == i) {
410 w.Write (SecondaryId);
418 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
420 if (token == PrimaryId)
421 return r.ReadInt32 ();
423 return (int) r.ReadByte ();
425 protected override Type Type {
426 get { return typeof (int); }
429 protected override int NumberOfIds {
434 class Int16Formatter : ObjectFormatter {
435 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
441 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
443 return r.ReadInt16 ();
445 protected override Type Type {
446 get { return typeof (short); }
450 class ByteFormatter : 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.ReadByte ();
461 protected override Type Type {
462 get { return typeof (byte); }
466 class BooleanFormatter : ObjectFormatter {
467 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
472 w.Write (SecondaryId);
475 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
477 return token == PrimaryId;
480 protected override Type Type {
481 get { return typeof (bool); }
484 protected override int NumberOfIds {
489 class CharFormatter : ObjectFormatter {
490 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
496 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
498 return r.ReadChar ();
501 protected override Type Type {
502 get { return typeof (char); }
506 class DateTimeFormatter : ObjectFormatter {
507 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
510 w.Write (((DateTime) o).Ticks);
513 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
515 return new DateTime (r.ReadInt64 ());
518 protected override Type Type {
519 get { return typeof (DateTime); }
523 class PairFormatter : ObjectFormatter {
524 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
528 WriteObject (w, p.First, ctx);
529 WriteObject (w, p.Second, ctx);
532 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
534 Pair p = new Pair ();
535 p.First = ReadObject (r, ctx);
536 p.Second = ReadObject (r, ctx);
540 protected override Type Type {
541 get { return typeof (Pair); }
545 class TripletFormatter : ObjectFormatter {
546 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
548 Triplet t = (Triplet) o;
550 WriteObject (w, t.First, ctx);
551 WriteObject (w, t.Second, ctx);
552 WriteObject (w, t.Third, ctx);
555 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
557 Triplet t = new Triplet ();
558 t.First = ReadObject (r, ctx);
559 t.Second = ReadObject (r, ctx);
560 t.Third = ReadObject (r, ctx);
564 protected override Type Type {
565 get { return typeof (Triplet); }
569 class ArrayListFormatter : ObjectFormatter {
570 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
572 ArrayList l = (ArrayList) o;
575 Write7BitEncodedInt (w, l.Count);
576 foreach (object i in l)
577 WriteObject (w, i, ctx);
580 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
582 int len = Read7BitEncodedInt (r);
583 ArrayList l = new ArrayList (len);
585 for (int i = 0; i < len; i++)
586 l.Add (ReadObject (r, ctx));
591 protected override Type Type {
592 get { return typeof (ArrayList); }
596 class HashtableFormatter : ObjectFormatter {
597 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
599 Hashtable ht = (Hashtable) o;
602 Write7BitEncodedInt (w, ht.Count);
603 foreach (DictionaryEntry de in ht) {
604 WriteObject (w, de.Key, ctx);
605 WriteObject (w, de.Value, ctx);
609 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
611 int len = Read7BitEncodedInt (r);
612 Hashtable ht = new Hashtable (len);
614 for (int i = 0; i < len; i++) {
615 object key = ReadObject (r, ctx);
616 object val = ReadObject (r, ctx);
624 protected override Type Type {
625 get { return typeof (Hashtable); }
629 class ObjectArrayFormatter : ObjectFormatter {
630 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
632 object [] val = (object []) o;
635 Write7BitEncodedInt (w, val.Length);
636 foreach (object i in val)
637 WriteObject (w, i, ctx);
640 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
642 int len = Read7BitEncodedInt (r);
643 object [] ret = new object [len];
645 for (int i = 0; i < len; i++)
646 ret [i] = ReadObject (r, ctx);
651 protected override Type Type {
652 get { return typeof (object []); }
658 #region System.Web Optimizations
659 class ColorFormatter : ObjectFormatter {
660 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
664 if (!c.IsKnownColor) {
666 w.Write (c.ToArgb ());
668 w.Write (SecondaryId);
669 w.Write ((int) c.ToKnownColor ());
673 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
675 if (token == PrimaryId)
676 return Color.FromArgb (r.ReadInt32 ());
678 return Color.FromKnownColor ((KnownColor) r.ReadInt32 ());
681 protected override Type Type {
682 get { return typeof (Color); }
685 protected override int NumberOfIds {
692 #region Special Formatters
693 class EnumFormatter : ObjectFormatter {
694 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
696 object value = Convert.ChangeType (o, ((Enum) o).GetTypeCode ());
698 WriteObject (w, o.GetType (), ctx);
699 WriteObject (w, value, ctx);
702 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
704 Type t = (Type) ReadObject (r, ctx);
705 object value = ReadObject (r, ctx);
707 return Enum.ToObject (t, value);
709 protected override Type Type {
710 get { return typeof (Enum); }
714 class TypeFormatter : ObjectFormatter {
715 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
718 if (ctx.RegisterCache (o, out key)) {
719 w.Write (SecondaryId);
723 w.Write (((Type) o).FullName);
725 // We should cache the name of the assembly
726 w.Write (((Type) o).Assembly.FullName);
731 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
733 if (token == PrimaryId) {
734 string type = r.ReadString ();
736 string assembly = r.ReadString ();
737 Type t = Assembly.Load (assembly).GetType (type);
739 Type t = Type.GetType(type);
744 return ctx.GetCache (r.ReadInt16 ());
748 protected override Type Type {
749 get { return typeof (Type); }
752 protected override int NumberOfIds {
757 class SingleRankArrayFormatter : ObjectFormatter {
758 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
760 Array val = (Array) o;
763 WriteObject (w, val.GetType ().GetElementType (), ctx);
765 Write7BitEncodedInt (w, val.Length);
766 foreach (object i in val)
767 WriteObject (w, i, ctx);
770 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
772 Type t = (Type) ReadObject (r, ctx);
773 int len = Read7BitEncodedInt (r);
774 Array val = Array.CreateInstance (t, len);
776 for (int i = 0; i < len; i++)
777 val.SetValue (ReadObject (r, ctx), i);
782 protected override Type Type {
783 get { return typeof (Array); }
787 class FontUnitFormatter : StringFormatter {
788 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
790 base.Write (w, o.ToString (), ctx);
793 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
795 return FontUnit.Parse ((string) base.Read (token, r, ctx));
798 protected override Type Type {
799 get { return typeof (FontUnit); }
803 class UnitFormatter : StringFormatter {
804 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
806 base.Write (w, o.ToString (), ctx);
809 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
811 return Unit.Parse ((string) base.Read (token, r, ctx));
814 protected override Type Type {
815 get { return typeof (Unit); }
819 class TypeConverterFormatter : StringFormatter {
820 TypeConverter converter;
822 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
825 ObjectFormatter.WriteObject (w, o.GetType (), ctx);
826 string v = (string) converter.ConvertTo (null, CultureInfo.InvariantCulture,
828 base.Write (w, v, ctx);
831 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
833 Type t = (Type) ObjectFormatter.ReadObject (r, ctx);
834 converter = TypeDescriptor.GetConverter (t);
835 token = r.ReadByte ();
836 string v = (string) base.Read (token, r, ctx);
837 return converter.ConvertFrom (null, CultureInfo.InvariantCulture, v);
840 protected override Type Type {
841 get { return typeof (TypeConverter); }
844 public TypeConverter Converter {
845 set { converter = value; }
849 class BinaryObjectFormatter : ObjectFormatter {
850 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
854 MemoryStream ms = new MemoryStream (128);
855 new BinaryFormatter ().Serialize (ms, o);
857 byte [] buf = ms.GetBuffer ();
858 Write7BitEncodedInt (w, buf.Length);
859 w.Write (buf, 0, buf.Length);
862 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
864 int len = Read7BitEncodedInt (r);
865 byte [] buf = r.ReadBytes (len);
866 if (buf.Length != len)
867 throw new Exception ();
869 return new BinaryFormatter ().Deserialize (new MemoryStream (buf));
872 protected override Type Type {
873 get { return typeof (object); }