2 // System.Web.UI.ObjectStateFormatter
5 // Ben Maurer (bmaurer@users.sourceforge.net)
6 // Gonzalo Paniagua (gonzalo@ximian.com)
9 // (c) Copyright 2004-2010 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;
47 using System.Web.Configuration;
49 namespace System.Web.UI
51 public sealed class ObjectStateFormatter : IFormatter, IStateFormatter
53 const ushort SERIALIZED_STREAM_MAGIC = 0x01FF;
56 MachineKeySection section;
58 public ObjectStateFormatter ()
62 internal ObjectStateFormatter (Page page)
69 return (page == null) ? (section != null) : page.EnableViewStateMac;
73 bool NeedViewStateEncryption {
75 return (page == null) ? false : page.NeedViewStateEncryption;
79 internal MachineKeySection Section {
82 section = (MachineKeySection) WebConfigurationManager.GetWebApplicationSection ("system.web/machineKey");
90 // There's no need to implement encryption support in this overload. Encryption is
91 // performed only when ObjectStateFormatter is created in the Page context, and that
92 // can happen only internally to System.Web. Since System.Web doesn't use this
93 // overload, the encryption code in here would be effectively dead.
94 public object Deserialize (Stream inputStream)
96 if (inputStream == null)
97 throw new ArgumentNullException ("inputStream");
99 BinaryReader reader = new BinaryReader (inputStream);
100 short magic = reader.ReadInt16 ();
101 if (magic != SERIALIZED_STREAM_MAGIC)
102 throw new ArgumentException ("The serialized data is invalid");
104 return DeserializeObject (reader);
107 public object Deserialize (string inputString)
109 if (inputString == null)
110 throw new ArgumentNullException ("inputString");
111 if (inputString.Length == 0)
112 throw new ArgumentNullException ("inputString");
114 byte [] data = Convert.FromBase64String (inputString);
115 if (data == null || (data.Length) == 0)
116 throw new ArgumentNullException ("inputString");
118 if (NeedViewStateEncryption) {
120 data = MachineKeySectionUtils.VerifyDecrypt (Section, data);
122 data = MachineKeySectionUtils.Decrypt (Section, data);
124 } else if (EnableMac) {
125 data = MachineKeySectionUtils.Verify (Section, data);
129 throw new HttpException ("Unable to validate data.");
131 using (MemoryStream ms = new MemoryStream (data)) {
132 return Deserialize (ms);
136 public string Serialize (object stateGraph)
138 if (stateGraph == null)
142 using (MemoryStream ms = new MemoryStream ()) {
143 Serialize (ms, stateGraph);
144 data = ms.GetBuffer ();
147 if (NeedViewStateEncryption) {
149 data = MachineKeySectionUtils.EncryptSign (Section, data);
151 data = MachineKeySectionUtils.Encrypt (Section, data);
153 } else if (EnableMac) {
154 data = MachineKeySectionUtils.Sign (Section, data);
157 return Convert.ToBase64String (data, 0, data.Length);
160 // There's no need to implement encryption support in this overload. Encryption is
161 // performed only when ObjectStateFormatter is created in the Page context, and that
162 // can happen only internally to System.Web. Since System.Web doesn't use this
163 // overload, the encryption code in here would be effectively dead.
164 public void Serialize (Stream outputStream, object stateGraph)
166 if (outputStream == null)
167 throw new ArgumentNullException ("outputStream");
169 if (stateGraph == null)
170 throw new ArgumentNullException ("stateGraph");
172 BinaryWriter writer = new BinaryWriter (outputStream);
173 writer.Write (SERIALIZED_STREAM_MAGIC);
175 SerializeValue (writer, stateGraph);
178 void SerializeValue (BinaryWriter w, object o)
180 ObjectFormatter.WriteObject (w, o, new WriterContext ());
183 object DeserializeObject (BinaryReader r)
185 return ObjectFormatter.ReadObject (r, new ReaderContext ());
190 object IFormatter.Deserialize (Stream serializationStream)
192 return Deserialize (serializationStream);
195 void IFormatter.Serialize (Stream serializationStream, object stateGraph)
197 Serialize (serializationStream, stateGraph);
200 SerializationBinder IFormatter.Binder {
205 StreamingContext IFormatter.Context {
206 get { return new StreamingContext (StreamingContextStates.All); }
210 ISurrogateSelector IFormatter.SurrogateSelector {
217 #region Object Readers/Writers
219 sealed class WriterContext
229 public bool RegisterCache (object o)
231 if (nextKey == short.MaxValue)
235 cache = new Hashtable ();
236 cache.Add (o, key = nextKey++);
240 object posKey = cache [o];
241 if (posKey == null) {
242 cache.Add (o, key = nextKey++);
246 key = (short) posKey;
251 sealed class ReaderContext
255 public void CacheItem (object o)
258 cache = new ArrayList ();
263 public object GetCache (short key)
269 abstract class ObjectFormatter
271 static readonly Hashtable writeMap = new Hashtable ();
272 static ObjectFormatter [] readMap = new ObjectFormatter [256];
273 static BinaryObjectFormatter binaryObjectFormatter;
274 static TypeFormatter typeFormatter;
275 static EnumFormatter enumFormatter;
276 static SingleRankArrayFormatter singleRankArrayFormatter;
277 static TypeConverterFormatter typeConverterFormatter;
279 static ObjectFormatter ()
281 new StringFormatter ().Register ();
282 new Int64Formatter ().Register ();
283 new Int32Formatter ().Register ();
284 new Int16Formatter ().Register ();
285 new ByteFormatter ().Register ();
286 new BooleanFormatter ().Register ();
287 new CharFormatter ().Register ();
288 new DateTimeFormatter ().Register ();
289 new PairFormatter ().Register ();
290 new TripletFormatter ().Register ();
291 new ArrayListFormatter ().Register ();
292 new HashtableFormatter ().Register ();
293 new ObjectArrayFormatter ().Register ();
294 new UnitFormatter ().Register ();
295 new FontUnitFormatter ().Register ();
296 new IndexedStringFormatter ().Register ();
297 new ColorFormatter ().Register ();
299 enumFormatter = new EnumFormatter ();
300 enumFormatter.Register ();
302 typeFormatter = new TypeFormatter ();
303 typeFormatter.Register ();
305 singleRankArrayFormatter = new SingleRankArrayFormatter ();
306 singleRankArrayFormatter.Register ();
308 typeConverterFormatter = new TypeConverterFormatter ();
309 typeConverterFormatter.Register ();
311 binaryObjectFormatter = new BinaryObjectFormatter ();
312 binaryObjectFormatter.Register ();
316 static byte nextId = 1;
318 public ObjectFormatter ()
320 PrimaryId = nextId ++;
321 if (NumberOfIds == 1)
324 SecondaryId = nextId ++;
325 if (NumberOfIds == 2)
328 TertiaryId = nextId ++;
329 if (NumberOfIds == 3)
332 throw new Exception ();
335 protected readonly byte PrimaryId, SecondaryId = 255, TertiaryId = 255;
337 protected abstract void Write (BinaryWriter w, object o, WriterContext ctx);
338 protected abstract object Read (byte token, BinaryReader r, ReaderContext ctx);
339 protected abstract Type Type { get; }
340 protected virtual int NumberOfIds { get { return 1; } }
342 public virtual void Register ()
344 writeMap [Type] = this;
345 readMap [PrimaryId] = this;
346 if (SecondaryId != 255) {
347 readMap [SecondaryId] = this;
348 if (TertiaryId != 255)
349 readMap [TertiaryId] = this;
353 public static void WriteObject (BinaryWriter w, object o, WriterContext ctx)
357 Trace.WriteLine (String.Format ("Writing {0} (type: {1})", o, o.GetType ()));
360 Trace.WriteLine ("Writing null");
362 long pos = w.BaseStream.Position;
370 Type t = o.GetType ();
372 Trace.WriteLine (String.Format ("Looking up formatter for type {0}", t));
375 ObjectFormatter fmt = writeMap [t] as ObjectFormatter;
377 Trace.WriteLine (String.Format ("Formatter from writeMap: '{0}'", fmt));
380 // Handle abstract types here
386 else if (t.IsArray && ((Array) o).Rank == 1)
387 fmt = singleRankArrayFormatter;
389 TypeConverter converter;
390 converter = TypeDescriptor.GetConverter (o);
392 Trace.WriteLine (String.Format ("Type converter: '{0}' (to string: {1}; from {2}: {3})",
394 converter != null ? converter.CanConvertTo (typeof (string)) : false,
396 converter != null ? converter.CanConvertFrom (t) : false));
398 // Do not use the converter if it's an instance of
399 // TypeConverter itself - it reports it is able to
400 // convert to string, but it's only a conversion
401 // consisting of a call to ToString() with no
402 // reverse conversion supported. This leads to
403 // problems when deserializing the object.
404 if (converter == null || converter.GetType () == typeof (TypeConverter) ||
405 !converter.CanConvertTo (typeof (string)) || !converter.CanConvertFrom (typeof (string)))
406 fmt = binaryObjectFormatter;
408 typeConverterFormatter.Converter = converter;
409 fmt = typeConverterFormatter;
415 Trace.WriteLine (String.Format ("Writing with formatter '{0}'", fmt.GetType ()));
417 fmt.Write (w, o, ctx);
420 Trace.WriteLine (String.Format ("Wrote {0} (type: {1}) {2} bytes", o, o.GetType (), w.BaseStream.Position - pos));
424 public static object ReadObject (BinaryReader r, ReaderContext ctx)
426 byte sig = r.ReadByte ();
431 return readMap [sig].Read (sig, r, ctx);
434 protected void Write7BitEncodedInt (BinaryWriter w, int value)
437 int high = (value >> 7) & 0x01ffffff;
438 byte b = (byte)(value & 0x7f);
441 b = (byte)(b | 0x80);
448 protected int Read7BitEncodedInt (BinaryReader r)
457 ret = ret | ((b & 0x7f) << shift);
459 } while ((b & 0x80) == 0x80);
465 #region Primitive Formatters
466 class StringFormatter : ObjectFormatter
468 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
470 if (ctx.RegisterCache (o)) {
471 w.Write (SecondaryId);
479 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
481 if (token == PrimaryId) {
482 string s = r.ReadString ();
486 return ctx.GetCache (r.ReadInt16 ());
489 protected override Type Type {
490 get { return typeof (string); }
493 protected override int NumberOfIds {
498 class IndexedStringFormatter : StringFormatter
500 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
502 IndexedString s = o as IndexedString;
505 throw new InvalidOperationException ("object is not of the IndexedString type");
507 base.Write (w, s.Value, ctx);
510 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
512 string s = base.Read (token, r, ctx) as string;
513 if (String.IsNullOrEmpty (s))
514 throw new InvalidOperationException ("string must not be null or empty.");
516 return new IndexedString (s);
519 protected override Type Type {
520 get { return typeof (IndexedString); }
523 protected override int NumberOfIds {
528 class Int64Formatter : ObjectFormatter
530 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
536 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
538 return r.ReadInt64 ();
540 protected override Type Type {
541 get { return typeof (long); }
545 class Int32Formatter : ObjectFormatter
547 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
550 if ((int)(byte) i == i) {
551 w.Write (SecondaryId);
559 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
561 if (token == PrimaryId)
562 return r.ReadInt32 ();
564 return (int) r.ReadByte ();
567 protected override Type Type {
568 get { return typeof (int); }
571 protected override int NumberOfIds {
576 class Int16Formatter : ObjectFormatter
578 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
584 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
586 return r.ReadInt16 ();
589 protected override Type Type {
590 get { return typeof (short); }
594 class ByteFormatter : ObjectFormatter
596 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
602 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
604 return r.ReadByte ();
607 protected override Type Type {
608 get { return typeof (byte); }
612 class BooleanFormatter : ObjectFormatter
614 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
619 w.Write (SecondaryId);
622 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
624 return token == PrimaryId;
627 protected override Type Type {
628 get { return typeof (bool); }
631 protected override int NumberOfIds {
636 class CharFormatter : ObjectFormatter
638 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
644 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
646 return r.ReadChar ();
649 protected override Type Type {
650 get { return typeof (char); }
654 class DateTimeFormatter : ObjectFormatter
656 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
659 w.Write (((DateTime) o).Ticks);
662 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
664 return new DateTime (r.ReadInt64 ());
667 protected override Type Type {
668 get { return typeof (DateTime); }
672 class PairFormatter : ObjectFormatter
674 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
678 WriteObject (w, p.First, ctx);
679 WriteObject (w, p.Second, ctx);
682 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
684 Pair p = new Pair ();
685 p.First = ReadObject (r, ctx);
686 p.Second = ReadObject (r, ctx);
690 protected override Type Type {
691 get { return typeof (Pair); }
695 class TripletFormatter : ObjectFormatter
697 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
699 Triplet t = (Triplet) o;
701 WriteObject (w, t.First, ctx);
702 WriteObject (w, t.Second, ctx);
703 WriteObject (w, t.Third, ctx);
706 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
708 Triplet t = new Triplet ();
709 t.First = ReadObject (r, ctx);
710 t.Second = ReadObject (r, ctx);
711 t.Third = ReadObject (r, ctx);
715 protected override Type Type {
716 get { return typeof (Triplet); }
720 class ArrayListFormatter : ObjectFormatter
722 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
724 ArrayList l = (ArrayList) o;
727 Write7BitEncodedInt (w, l.Count);
728 for (int i = 0; i < l.Count; i++)
729 WriteObject (w, l [i], ctx);
732 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
734 int len = Read7BitEncodedInt (r);
735 ArrayList l = new ArrayList (len);
737 for (int i = 0; i < len; i++)
738 l.Add (ReadObject (r, ctx));
743 protected override Type Type {
744 get { return typeof (ArrayList); }
748 class HashtableFormatter : ObjectFormatter
750 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
752 Hashtable ht = (Hashtable) o;
755 Write7BitEncodedInt (w, ht.Count);
756 foreach (DictionaryEntry de in ht) {
757 WriteObject (w, de.Key, ctx);
758 WriteObject (w, de.Value, ctx);
762 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
764 int len = Read7BitEncodedInt (r);
765 Hashtable ht = new Hashtable (len);
767 for (int i = 0; i < len; i++) {
768 object key = ReadObject (r, ctx);
769 object val = ReadObject (r, ctx);
777 protected override Type Type {
778 get { return typeof (Hashtable); }
782 class ObjectArrayFormatter : ObjectFormatter
784 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
786 object [] val = (object []) o;
789 Write7BitEncodedInt (w, val.Length);
790 for (int i = 0; i < val.Length; i++)
791 WriteObject (w, val [i], ctx);
794 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
796 int len = Read7BitEncodedInt (r);
797 object [] ret = new object [len];
799 for (int i = 0; i < len; i++)
800 ret [i] = ReadObject (r, ctx);
805 protected override Type Type {
806 get { return typeof (object []); }
812 #region System.Web Optimizations
813 class ColorFormatter : ObjectFormatter
815 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
819 if (c.IsEmpty || c.IsKnownColor) {
820 w.Write (SecondaryId);
822 w.Write (-1); //isempty marker
824 w.Write ((int) c.ToKnownColor ());
827 w.Write (c.ToArgb ());
831 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
833 int value = r.ReadInt32 ();
834 if (token == PrimaryId)
835 return Color.FromArgb (value);
837 if (value == -1) //isempty marker
839 return Color.FromKnownColor ((KnownColor)value);
843 protected override Type Type {
844 get { return typeof (Color); }
847 protected override int NumberOfIds {
854 #region Special Formatters
855 class EnumFormatter : ObjectFormatter
857 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
859 object value = Convert.ChangeType (o, ((Enum) o).GetTypeCode ());
861 WriteObject (w, o.GetType (), ctx);
862 WriteObject (w, value, ctx);
865 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
867 Type t = (Type) ReadObject (r, ctx);
868 object value = ReadObject (r, ctx);
870 return Enum.ToObject (t, value);
873 protected override Type Type {
874 get { return typeof (Enum); }
878 class TypeFormatter : ObjectFormatter
880 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
882 if (ctx.RegisterCache (o)) {
883 w.Write (SecondaryId);
887 w.Write (((Type) o).FullName);
889 // We should cache the name of the assembly
890 w.Write (((Type) o).Assembly.FullName);
894 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
896 if (token == PrimaryId) {
897 string type = r.ReadString ();
898 string assembly = r.ReadString ();
899 Type t = Assembly.Load (assembly).GetType (type);
903 return ctx.GetCache (r.ReadInt16 ());
907 protected override Type Type {
908 get { return typeof (Type); }
911 protected override int NumberOfIds {
916 class SingleRankArrayFormatter : ObjectFormatter
918 readonly BinaryFormatter _binaryFormatter = new BinaryFormatter ();
920 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
922 Array val = (Array) o;
923 if (val.GetType ().GetElementType ().IsPrimitive) {
924 w.Write (SecondaryId);
925 _binaryFormatter.Serialize (w.BaseStream, o);
930 WriteObject (w, val.GetType ().GetElementType (), ctx);
932 Write7BitEncodedInt (w, val.Length);
933 for (int i = 0; i < val.Length; i++)
934 WriteObject (w, val.GetValue (i), ctx);
937 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
939 if (token == SecondaryId)
940 return _binaryFormatter.Deserialize (r.BaseStream);
941 Type t = (Type) ReadObject (r, ctx);
942 int len = Read7BitEncodedInt (r);
943 Array val = Array.CreateInstance (t, len);
945 for (int i = 0; i < len; i++)
946 val.SetValue (ReadObject (r, ctx), i);
951 protected override Type Type {
952 get { return typeof (Array); }
955 protected override int NumberOfIds {
960 class FontUnitFormatter : StringFormatter
962 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
964 base.Write (w, o.ToString (), ctx);
967 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
969 return FontUnit.Parse ((string) base.Read (token, r, ctx));
972 protected override Type Type {
973 get { return typeof (FontUnit); }
977 class UnitFormatter : StringFormatter
979 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
981 base.Write (w, o.ToString (), ctx);
984 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
986 return Unit.Parse ((string) base.Read (token, r, ctx));
989 protected override Type Type {
990 get { return typeof (Unit); }
994 class TypeConverterFormatter : StringFormatter
996 TypeConverter converter;
998 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
1000 w.Write (PrimaryId);
1001 ObjectFormatter.WriteObject (w, o.GetType (), ctx);
1002 string v = (string) converter.ConvertTo (null, Helpers.InvariantCulture,
1003 o, typeof (string));
1004 base.Write (w, v, ctx);
1007 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
1009 Type t = (Type) ObjectFormatter.ReadObject (r, ctx);
1010 converter = TypeDescriptor.GetConverter (t);
1011 token = r.ReadByte ();
1012 string v = (string) base.Read (token, r, ctx);
1013 return converter.ConvertFrom (null, Helpers.InvariantCulture, v);
1016 protected override Type Type {
1017 get { return typeof (TypeConverter); }
1020 public TypeConverter Converter {
1021 set { converter = value; }
1025 class BinaryObjectFormatter : ObjectFormatter
1027 protected override void Write (BinaryWriter w, object o, WriterContext ctx)
1029 w.Write (PrimaryId);
1031 MemoryStream ms = new MemoryStream (128);
1032 new BinaryFormatter ().Serialize (ms, o);
1034 byte [] buf = ms.GetBuffer ();
1035 Write7BitEncodedInt (w, buf.Length);
1036 w.Write (buf, 0, buf.Length);
1039 protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
1041 int len = Read7BitEncodedInt (r);
1042 byte [] buf = r.ReadBytes (len);
1043 if (buf.Length != len)
1044 throw new Exception ();
1046 return new BinaryFormatter ().Deserialize (new MemoryStream (buf));
1049 protected override Type Type {
1050 get { return typeof (object); }