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
);
730 protected override object Read (byte token
, BinaryReader r
, ReaderContext ctx
)
732 if (token
== PrimaryId
) {
733 string type
= r
.ReadString ();
734 string assembly
= r
.ReadString ();
736 Type t
= Assembly
.Load (assembly
).GetType (type
);
740 return ctx
.GetCache (r
.ReadInt16 ());
744 protected override Type Type
{
745 get { return typeof (Type); }
748 protected override int NumberOfIds
{
753 class SingleRankArrayFormatter
: ObjectFormatter
{
754 protected override void Write (BinaryWriter w
, object o
, WriterContext ctx
)
756 Array val
= (Array
) o
;
759 WriteObject (w
, val
.GetType ().GetElementType (), ctx
);
761 Write7BitEncodedInt (w
, val
.Length
);
762 foreach (object i
in val
)
763 WriteObject (w
, i
, ctx
);
766 protected override object Read (byte token
, BinaryReader r
, ReaderContext ctx
)
768 Type t
= (Type
) ReadObject (r
, ctx
);
769 int len
= Read7BitEncodedInt (r
);
770 Array val
= Array
.CreateInstance (t
, len
);
772 for (int i
= 0; i
< len
; i
++)
773 val
.SetValue (ReadObject (r
, ctx
), i
);
778 protected override Type Type
{
779 get { return typeof (Array); }
783 class FontUnitFormatter
: StringFormatter
{
784 protected override void Write (BinaryWriter w
, object o
, WriterContext ctx
)
786 base.Write (w
, o
.ToString (), ctx
);
789 protected override object Read (byte token
, BinaryReader r
, ReaderContext ctx
)
791 return FontUnit
.Parse ((string) base.Read (token
, r
, ctx
));
794 protected override Type Type
{
795 get { return typeof (FontUnit); }
799 class UnitFormatter
: StringFormatter
{
800 protected override void Write (BinaryWriter w
, object o
, WriterContext ctx
)
802 base.Write (w
, o
.ToString (), ctx
);
805 protected override object Read (byte token
, BinaryReader r
, ReaderContext ctx
)
807 return Unit
.Parse ((string) base.Read (token
, r
, ctx
));
810 protected override Type Type
{
811 get { return typeof (Unit); }
815 class TypeConverterFormatter
: StringFormatter
{
816 TypeConverter converter
;
818 protected override void Write (BinaryWriter w
, object o
, WriterContext ctx
)
821 ObjectFormatter
.WriteObject (w
, o
.GetType (), ctx
);
822 string v
= (string) converter
.ConvertTo (null, CultureInfo
.InvariantCulture
,
824 base.Write (w
, v
, ctx
);
827 protected override object Read (byte token
, BinaryReader r
, ReaderContext ctx
)
829 Type t
= (Type
) ObjectFormatter
.ReadObject (r
, ctx
);
830 converter
= TypeDescriptor
.GetConverter (t
);
831 token
= r
.ReadByte ();
832 string v
= (string) base.Read (token
, r
, ctx
);
833 return converter
.ConvertFrom (null, CultureInfo
.InvariantCulture
, v
);
836 protected override Type Type
{
837 get { return typeof (TypeConverter); }
840 public TypeConverter Converter
{
841 set { converter = value; }
845 class BinaryObjectFormatter
: ObjectFormatter
{
846 protected override void Write (BinaryWriter w
, object o
, WriterContext ctx
)
850 MemoryStream ms
= new MemoryStream (128);
851 new BinaryFormatter ().Serialize (ms
, o
);
853 byte [] buf
= ms
.GetBuffer ();
854 Write7BitEncodedInt (w
, buf
.Length
);
855 w
.Write (buf
, 0, buf
.Length
);
858 protected override object Read (byte token
, BinaryReader r
, ReaderContext ctx
)
860 int len
= Read7BitEncodedInt (r
);
861 byte [] buf
= r
.ReadBytes (len
);
862 if (buf
.Length
!= len
)
863 throw new Exception ();
865 return new BinaryFormatter ().Deserialize (new MemoryStream (buf
));
868 protected override Type Type
{
869 get { return typeof (object); }