[System.Web] Public event handlers from reference source
[mono.git] / mcs / class / System.Web / System.Web.UI / ObjectStateFormatter.cs
1 //
2 // System.Web.UI.ObjectStateFormatter
3 //
4 // Authors:
5 //      Ben Maurer (bmaurer@users.sourceforge.net)
6 //      Gonzalo Paniagua (gonzalo@ximian.com)
7 //
8 // (C) 2003 Ben Maurer
9 // (c) Copyright 2004-2010 Novell, Inc. (http://www.novell.com)
10 //
11
12 //
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:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
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.
31 //
32
33 //#define TRACE
34
35 using System.Collections;
36 using System.ComponentModel;
37 using System.Globalization;
38 using System.Drawing;
39 using System.IO;
40 using System.Reflection;
41 using System.Runtime.Serialization.Formatters.Binary;
42 using System.Runtime.Serialization;
43 using System.Text;
44 using System.Web.UI.WebControls;
45 using System.Web.Util;
46 using System.Diagnostics;
47 using System.Web.Configuration;
48
49 namespace System.Web.UI
50 {
51         public sealed class ObjectStateFormatter : IFormatter, IStateFormatter
52         {
53                 const ushort SERIALIZED_STREAM_MAGIC = 0x01FF;
54
55                 Page page;
56                 MachineKeySection section;
57
58                 public ObjectStateFormatter ()
59                 {
60                 }
61                 
62                 internal ObjectStateFormatter (Page page)
63                 {
64                         this.page = page;
65                 }
66
67                 bool EnableMac {
68                         get {
69                                 return (page == null) ? (section != null) : page.EnableViewStateMac;
70                         }
71                 }
72
73                 bool NeedViewStateEncryption {
74                         get {
75                                 return (page == null) ? false : page.NeedViewStateEncryption;
76                         }
77                 }
78
79                 internal MachineKeySection Section {
80                         get {
81                                 if (section == null)
82                                         section = (MachineKeySection) WebConfigurationManager.GetWebApplicationSection ("system.web/machineKey");
83                                 return section;
84                         }
85                         set {
86                                 section = value;
87                         }
88                 }
89
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)
95                 {
96                         if (inputStream == null)
97                                 throw new ArgumentNullException ("inputStream");
98
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");
103
104                         return DeserializeObject (reader);
105                 }
106                 
107                 public object Deserialize (string inputString)
108                 {
109                         if (inputString == null)
110                                 throw new ArgumentNullException ("inputString");
111                         if (inputString.Length == 0)
112                                 throw new ArgumentNullException ("inputString");
113
114                         byte [] data = Convert.FromBase64String (inputString);
115                         if (data == null || (data.Length) == 0)
116                                 throw new ArgumentNullException ("inputString");
117
118                         if (NeedViewStateEncryption) {
119                                 if (EnableMac) {
120                                         data = MachineKeySectionUtils.VerifyDecrypt (Section, data);
121                                 } else {
122                                         data = MachineKeySectionUtils.Decrypt (Section, data);
123                                 }
124                         } else if (EnableMac) {
125                                 data = MachineKeySectionUtils.Verify (Section, data);
126                         }
127
128                         if (data == null)
129                                 throw new HttpException ("Unable to validate data.");
130
131                         using (MemoryStream ms = new MemoryStream (data)) {
132                                 return Deserialize (ms);
133                         }
134                 }
135                 
136                 public string Serialize (object stateGraph)
137                 {
138                         if (stateGraph == null)
139                                 return String.Empty;
140
141                         byte[] data = null;
142                         using (MemoryStream ms = new MemoryStream ()) {
143                                 Serialize (ms, stateGraph);
144                                 data = ms.GetBuffer ();
145                         }
146
147                         if (NeedViewStateEncryption) {
148                                 if (EnableMac) {
149                                         data = MachineKeySectionUtils.EncryptSign (Section, data);
150                                 } else {
151                                         data = MachineKeySectionUtils.Encrypt (Section, data);
152                                 }
153                         } else if (EnableMac) {
154                                 data = MachineKeySectionUtils.Sign (Section, data);
155                         }
156                         
157                         return Convert.ToBase64String (data, 0, data.Length);
158                 }
159
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)
165                 {
166                         if (outputStream == null)
167                                 throw new ArgumentNullException ("outputStream");
168
169                         if (stateGraph == null)
170                                 throw new ArgumentNullException ("stateGraph");
171
172                         BinaryWriter writer = new BinaryWriter (outputStream);
173                         writer.Write (SERIALIZED_STREAM_MAGIC);
174
175                         SerializeValue (writer, stateGraph);
176                 }
177                 
178                 void SerializeValue (BinaryWriter w, object o)
179                 {
180                         ObjectFormatter.WriteObject (w, o, new WriterContext ());
181                 }
182                 
183                 object DeserializeObject (BinaryReader r)
184                 {
185                         return ObjectFormatter.ReadObject (r, new ReaderContext ());
186                 }
187                 
188 #region IFormatter
189                 
190                 object IFormatter.Deserialize (Stream serializationStream)
191                 {
192                         return Deserialize (serializationStream);
193                 }
194                 
195                 void IFormatter.Serialize (Stream serializationStream, object stateGraph)
196                 {
197                         Serialize (serializationStream, stateGraph);
198                 }
199                 
200                 SerializationBinder IFormatter.Binder {
201                         get { return null; }
202                         set { }
203                 }
204                 
205                 StreamingContext IFormatter.Context {
206                         get { return new StreamingContext (StreamingContextStates.All); }
207                         set { }
208                 }
209                 
210                 ISurrogateSelector IFormatter.SurrogateSelector {
211                         get { return null; }
212                         set { }
213                 }
214                 
215 #endregion
216
217 #region Object Readers/Writers
218                 
219                 sealed class WriterContext
220                 {
221                         Hashtable cache;
222                         short nextKey = 0;
223                         short key = 0;
224
225                         public short Key {
226                                 get { return key; }
227                         }
228
229                         public bool RegisterCache (object o)
230                         {
231                                 if (nextKey == short.MaxValue)
232                                         return false;
233
234                                 if (cache == null) {
235                                         cache = new Hashtable ();
236                                         cache.Add (o, key = nextKey++);
237                                         return false;
238                                 }
239                                 
240                                 object posKey = cache [o];
241                                 if (posKey == null) {
242                                         cache.Add (o, key = nextKey++);
243                                         return false;
244                                 }
245                                 
246                                 key = (short) posKey;
247                                 return true;
248                         }
249                 }
250                 
251                 sealed class ReaderContext
252                 {
253                         ArrayList cache;
254                         
255                         public void CacheItem (object o)
256                         {
257                                 if (cache == null)
258                                         cache = new ArrayList ();
259                                 
260                                 cache.Add (o);
261                         }
262                         
263                         public object GetCache (short key)
264                         {
265                                 return cache [key];
266                         }
267                 }
268                 
269                 abstract class ObjectFormatter
270                 {
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;
278                         
279                         static ObjectFormatter ()
280                         {                       
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 ();
298
299                                 enumFormatter = new EnumFormatter ();
300                                 enumFormatter.Register ();
301
302                                 typeFormatter = new TypeFormatter ();
303                                 typeFormatter.Register ();
304
305                                 singleRankArrayFormatter = new SingleRankArrayFormatter ();
306                                 singleRankArrayFormatter.Register ();
307
308                                 typeConverterFormatter = new TypeConverterFormatter ();
309                                 typeConverterFormatter.Register ();
310
311                                 binaryObjectFormatter = new BinaryObjectFormatter ();
312                                 binaryObjectFormatter.Register ();
313                         }
314                 
315                         // 0 == null
316                         static byte nextId = 1;
317                         
318                         public ObjectFormatter ()
319                         {
320                                 PrimaryId = nextId ++;
321                                 if (NumberOfIds == 1)
322                                         return;
323                                 
324                                 SecondaryId = nextId ++;
325                                 if (NumberOfIds == 2)
326                                         return;
327                                 
328                                 TertiaryId = nextId ++;
329                                 if (NumberOfIds == 3)
330                                         return;
331                                 
332                                 throw new Exception ();
333                         }
334                         
335                         protected readonly byte PrimaryId, SecondaryId = 255, TertiaryId = 255;
336                         
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; } }
341                         
342                         public virtual void Register ()
343                         {
344                                 writeMap [Type] = this;
345                                 readMap [PrimaryId] = this;
346                                 if (SecondaryId != 255) {
347                                         readMap [SecondaryId] = this;
348                                         if (TertiaryId != 255)
349                                                 readMap [TertiaryId] = this;
350                                 }
351                         }
352                         
353                         public static void WriteObject (BinaryWriter w, object o, WriterContext ctx)
354                         {
355 #if TRACE
356                                 if (o != null) {
357                                         Trace.WriteLine (String.Format ("Writing {0} (type: {1})", o, o.GetType ()));
358                                         Trace.Indent ();
359                                 } else {
360                                         Trace.WriteLine ("Writing null");
361                                 }
362                                 long pos = w.BaseStream.Position;
363 #endif
364                                 
365                                 if (o == null) {
366                                         w.Write ((byte) 0);
367                                         return;
368                                 }
369                                 
370                                 Type t = o.GetType ();
371 #if TRACE
372                                 Trace.WriteLine (String.Format ("Looking up formatter for type {0}", t));
373 #endif
374
375                                 ObjectFormatter fmt = writeMap [t] as ObjectFormatter;
376 #if TRACE
377                                 Trace.WriteLine (String.Format ("Formatter from writeMap: '{0}'", fmt));
378 #endif
379                                 if (fmt == null) {
380                                         // Handle abstract types here
381                                         
382                                         if (o is Type)
383                                                 fmt = typeFormatter;
384                                         else if (t.IsEnum)
385                                                 fmt = enumFormatter;
386                                         else if (t.IsArray && ((Array) o).Rank == 1)
387                                                 fmt = singleRankArrayFormatter;
388                                         else {
389                                                 TypeConverter converter;
390                                                 converter = TypeDescriptor.GetConverter (o);
391 #if TRACE
392                                                 Trace.WriteLine (String.Format ("Type converter: '{0}' (to string: {1}; from {2}: {3})",
393                                                                                 converter,
394                                                                                 converter != null ? converter.CanConvertTo (typeof (string)) : false,
395                                                                                 t,
396                                                                                 converter != null ? converter.CanConvertFrom (t) : false));
397 #endif
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;
407                                                 else {
408                                                         typeConverterFormatter.Converter = converter;
409                                                         fmt = typeConverterFormatter;
410                                                 }
411                                         }
412                                 }
413
414 #if TRACE
415                                 Trace.WriteLine (String.Format ("Writing with formatter '{0}'", fmt.GetType ()));
416 #endif
417                                 fmt.Write (w, o, ctx);
418 #if TRACE
419                                 Trace.Unindent ();
420                                 Trace.WriteLine (String.Format ("Wrote {0} (type: {1}) {2} bytes", o, o.GetType (), w.BaseStream.Position - pos));
421 #endif
422                         }
423                         
424                         public static object ReadObject (BinaryReader r, ReaderContext ctx)
425                         {
426                                 byte sig = r.ReadByte ();
427                                 
428                                 if (sig == 0)
429                                         return null;
430                                 
431                                 return readMap [sig].Read (sig, r, ctx);
432                         }
433                         
434                         protected void Write7BitEncodedInt (BinaryWriter w, int value)
435                         {
436                                 do {
437                                         int high = (value >> 7) & 0x01ffffff;
438                                         byte b = (byte)(value & 0x7f);
439         
440                                         if (high != 0)
441                                                 b = (byte)(b | 0x80);
442         
443                                         w.Write(b);
444                                         value = high;
445                                 } while(value != 0);
446                         }
447                         
448                         protected int Read7BitEncodedInt (BinaryReader r)
449                         {
450                                 int ret = 0;
451                                 int shift = 0;
452                                 byte b;
453         
454                                 do {
455                                         b = r.ReadByte();
456                                         
457                                         ret = ret | ((b & 0x7f) << shift);
458                                         shift += 7;
459                                 } while ((b & 0x80) == 0x80);
460         
461                                 return ret;
462                         }
463                 }
464                 
465 #region Primitive Formatters
466                 class StringFormatter : ObjectFormatter
467                 {
468                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
469                         {
470                                 if (ctx.RegisterCache (o)) {
471                                         w.Write (SecondaryId);
472                                         w.Write (ctx.Key);
473                                 } else {
474                                         w.Write (PrimaryId);
475                                         w.Write ((string)o);
476                                 }
477                         }
478                         
479                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
480                         {
481                                 if (token == PrimaryId) {
482                                         string s = r.ReadString ();
483                                         ctx.CacheItem (s);
484                                         return s;
485                                 } else {
486                                         return ctx.GetCache (r.ReadInt16 ());
487                                 }
488                         }
489                         protected override Type Type {
490                                 get { return typeof (string); }
491                         }
492                         
493                         protected override int NumberOfIds {
494                                 get { return 2; }
495                         }
496                 }
497
498                 class IndexedStringFormatter : StringFormatter
499                 {
500                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
501                         {
502                                 IndexedString s = o as IndexedString;
503
504                                 if (s == null)
505                                         throw new InvalidOperationException ("object is not of the IndexedString type");
506                                 
507                                 base.Write (w, s.Value, ctx);
508                         }
509                         
510                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
511                         {
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.");
515                                 
516                                 return new IndexedString (s);
517                         }
518                         
519                         protected override Type Type {
520                                 get { return typeof (IndexedString); }
521                         }
522                         
523                         protected override int NumberOfIds {
524                                 get { return 2; }
525                         }
526                 }
527                 
528                 class Int64Formatter : ObjectFormatter
529                 {
530                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
531                         {
532                                 w.Write (PrimaryId);
533                                 w.Write ((long)o);
534                         }
535                         
536                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
537                         {
538                                 return r.ReadInt64 ();
539                         }
540                         protected override Type Type {
541                                 get { return typeof (long); }
542                         }
543                 }
544                 
545                 class Int32Formatter : ObjectFormatter
546                 {
547                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
548                         {
549                                 int i = (int) o;
550                                 if ((int)(byte) i == i) {
551                                         w.Write (SecondaryId);
552                                         w.Write ((byte) i);
553                                 } else {
554                                         w.Write (PrimaryId);
555                                         w.Write (i);
556                                 }
557                         }
558                         
559                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
560                         {
561                                 if (token == PrimaryId)
562                                         return r.ReadInt32 ();
563                                 else
564                                         return (int) r.ReadByte ();
565                         }
566                         
567                         protected override Type Type {
568                                 get { return typeof (int); }
569                         }
570                         
571                         protected override int NumberOfIds {
572                                 get { return 2; }
573                         }
574                 }
575                 
576                 class Int16Formatter : ObjectFormatter
577                 {
578                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
579                         {
580                                 w.Write (PrimaryId);
581                                 w.Write ((short)o);
582                         }
583                         
584                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
585                         {
586                                 return r.ReadInt16 ();
587                         }
588
589                         protected override Type Type {
590                                 get { return typeof (short); }
591                         }
592                 }
593                 
594                 class ByteFormatter : ObjectFormatter
595                 {
596                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
597                         {
598                                 w.Write (PrimaryId);
599                                 w.Write ((byte)o);
600                         }
601                         
602                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
603                         {
604                                 return r.ReadByte ();
605                         }
606
607                         protected override Type Type {
608                                 get { return typeof (byte); }
609                         }
610                 }
611                 
612                 class BooleanFormatter : ObjectFormatter
613                 {
614                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
615                         {
616                                 if ((bool)o == true)
617                                         w.Write (PrimaryId);
618                                 else
619                                         w.Write (SecondaryId);
620                         }
621                         
622                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
623                         {
624                                 return token == PrimaryId;
625                         }
626                         
627                         protected override Type Type {
628                                 get { return typeof (bool); }
629                         }
630                         
631                         protected override int NumberOfIds {
632                                 get { return 2; }
633                         }
634                 }
635                 
636                 class CharFormatter : ObjectFormatter
637                 {
638                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
639                         {
640                                 w.Write (PrimaryId);
641                                 w.Write ((char) o);
642                         }
643                         
644                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
645                         {
646                                 return r.ReadChar ();
647                         }
648                         
649                         protected override Type Type {
650                                 get { return typeof (char); }
651                         }
652                 }
653                 
654                 class DateTimeFormatter : ObjectFormatter
655                 {
656                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
657                         {
658                                 w.Write (PrimaryId);
659                                 w.Write (((DateTime) o).Ticks);
660                         }
661                         
662                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
663                         {
664                                 return new DateTime (r.ReadInt64 ());
665                         }
666                         
667                         protected override Type Type {
668                                 get { return typeof (DateTime); }
669                         }
670                 }
671                 
672                 class PairFormatter : ObjectFormatter
673                 {
674                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
675                         {
676                                 Pair p = (Pair) o;
677                                 w.Write (PrimaryId);
678                                 WriteObject (w, p.First, ctx);
679                                 WriteObject (w, p.Second, ctx);
680                         }
681                         
682                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
683                         {
684                                 Pair p = new Pair ();
685                                 p.First = ReadObject (r, ctx);
686                                 p.Second = ReadObject (r, ctx);
687                                 return p;
688                         }
689                         
690                         protected override Type Type {
691                                 get { return typeof (Pair); }
692                         }
693                 }
694                 
695                 class TripletFormatter : ObjectFormatter
696                 {
697                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
698                         {
699                                 Triplet t = (Triplet) o;
700                                 w.Write (PrimaryId);
701                                 WriteObject (w, t.First, ctx);
702                                 WriteObject (w, t.Second, ctx);
703                                 WriteObject (w, t.Third, ctx);
704                         }
705                         
706                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
707                         {
708                                 Triplet t = new Triplet ();
709                                 t.First = ReadObject (r, ctx);
710                                 t.Second = ReadObject (r, ctx);
711                                 t.Third = ReadObject (r, ctx);
712                                 return t;
713                         }
714                         
715                         protected override Type Type {
716                                 get { return typeof (Triplet); }
717                         }
718                 }
719                 
720                 class ArrayListFormatter : ObjectFormatter
721                 {
722                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
723                         {
724                                 ArrayList l = (ArrayList) o;
725                                 
726                                 w.Write (PrimaryId);
727                                 Write7BitEncodedInt (w, l.Count);
728                                 for (int i = 0; i < l.Count; i++)
729                                         WriteObject (w, l [i], ctx);
730                         }
731                         
732                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
733                         {
734                                 int len = Read7BitEncodedInt (r);
735                                 ArrayList l = new ArrayList (len);
736                                 
737                                 for (int i = 0; i < len; i++)
738                                         l.Add (ReadObject (r, ctx));
739                                 
740                                 return l;
741                         }
742                         
743                         protected override Type Type {
744                                 get { return typeof (ArrayList); }
745                         }
746                 }
747                 
748                 class HashtableFormatter : ObjectFormatter
749                 {
750                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
751                         {
752                                 Hashtable ht = (Hashtable) o;
753                                 
754                                 w.Write (PrimaryId);
755                                 Write7BitEncodedInt (w, ht.Count);
756                                 foreach (DictionaryEntry de in ht) {
757                                         WriteObject (w, de.Key, ctx);
758                                         WriteObject (w, de.Value, ctx);
759                                 }
760                         }
761                         
762                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
763                         {
764                                 int len = Read7BitEncodedInt (r);
765                                 Hashtable ht = new Hashtable (len);
766                                 
767                                 for (int i = 0; i < len; i++) {
768                                         object key = ReadObject (r, ctx);
769                                         object val = ReadObject (r, ctx);
770                                         
771                                         ht.Add (key, val);
772                                 }
773                                 
774                                 return ht;
775                         }
776                         
777                         protected override Type Type {
778                                 get { return typeof (Hashtable); }
779                         }
780                 }
781                 
782                 class ObjectArrayFormatter : ObjectFormatter
783                 {
784                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
785                         {
786                                 object [] val = (object []) o;
787                                 
788                                 w.Write (PrimaryId);
789                                 Write7BitEncodedInt (w, val.Length);
790                                 for (int i = 0; i < val.Length; i++)
791                                         WriteObject (w, val [i], ctx);
792                         }
793                         
794                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
795                         {
796                                 int len = Read7BitEncodedInt (r);
797                                 object [] ret = new object [len];
798                                 
799                                 for (int i = 0; i < len; i++)
800                                         ret [i] = ReadObject (r, ctx);
801                                 
802                                 return ret;
803                         }
804                         
805                         protected override Type Type {
806                                 get { return typeof (object []); }
807                         }
808                 }
809                 
810 #endregion
811                 
812 #region System.Web Optimizations
813                 class ColorFormatter : ObjectFormatter
814                 {
815                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
816                         {
817                                 Color c = (Color) o;
818                                 
819                                 if (c.IsEmpty || c.IsKnownColor) {
820                                         w.Write (SecondaryId);
821                                         if (c.IsEmpty)
822                                                 w.Write (-1); //isempty marker
823                                         else
824                                                 w.Write ((int) c.ToKnownColor ());
825                                 } else {
826                                         w.Write (PrimaryId);
827                                         w.Write (c.ToArgb ());
828                                 }
829                         }
830                         
831                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
832                         {
833                                 int value = r.ReadInt32 ();
834                                 if (token == PrimaryId)
835                                         return Color.FromArgb (value);
836                                 else {
837                                         if (value == -1) //isempty marker
838                                                 return Color.Empty;
839                                         return Color.FromKnownColor ((KnownColor)value);
840                                 }
841                         }
842                         
843                         protected override Type Type {
844                                 get { return typeof (Color); }
845                         }
846                         
847                         protected override int NumberOfIds {
848                                 get { return 2; }
849                         }
850                 }
851                 
852 #endregion
853                 
854 #region Special Formatters
855                 class EnumFormatter : ObjectFormatter
856                 {
857                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
858                         {
859                                 object value = Convert.ChangeType (o, ((Enum) o).GetTypeCode ());
860                                 w.Write (PrimaryId);
861                                 WriteObject (w, o.GetType (), ctx);
862                                 WriteObject (w, value, ctx);
863                         }
864                         
865                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
866                         {
867                                 Type t = (Type) ReadObject (r, ctx);
868                                 object value = ReadObject (r, ctx);
869                                 
870                                 return Enum.ToObject (t, value);
871                         }
872
873                         protected override Type Type {
874                                 get { return typeof (Enum); }
875                         }
876                 }
877                 
878                 class TypeFormatter : ObjectFormatter
879                 {
880                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
881                         {
882                                 if (ctx.RegisterCache (o)) {
883                                         w.Write (SecondaryId);
884                                         w.Write (ctx.Key);
885                                 } else {
886                                         w.Write (PrimaryId);
887                                         w.Write (((Type) o).FullName);
888
889                                         // We should cache the name of the assembly
890                                         w.Write (((Type) o).Assembly.FullName);
891                                 }
892                         }
893                         
894                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
895                         {
896                                 if (token == PrimaryId) {
897                                         string type = r.ReadString ();
898                                         string assembly = r.ReadString ();
899                                         Type t = Assembly.Load (assembly).GetType (type);
900                                         ctx.CacheItem (t);
901                                         return t;
902                                 } else {
903                                         return ctx.GetCache (r.ReadInt16 ());
904                                 }
905                         }
906                         
907                         protected override Type Type {
908                                 get { return typeof (Type); }
909                         }
910                         
911                         protected override int NumberOfIds {
912                                 get { return 2; }
913                         }
914                 }
915                 
916                 class SingleRankArrayFormatter : ObjectFormatter
917                 {
918                         readonly BinaryFormatter _binaryFormatter = new BinaryFormatter ();
919
920                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
921                         {
922                                 Array val = (Array) o;
923                                 if (val.GetType ().GetElementType ().IsPrimitive) {
924                                         w.Write (SecondaryId);
925                                         _binaryFormatter.Serialize (w.BaseStream, o);
926                                         return;
927                                 }
928                                 
929                                 w.Write (PrimaryId);
930                                 WriteObject (w, val.GetType ().GetElementType (), ctx);
931                                 
932                                 Write7BitEncodedInt (w, val.Length);
933                                 for (int i = 0; i < val.Length; i++)
934                                         WriteObject (w, val.GetValue (i), ctx);
935                         }
936                         
937                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
938                         {
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);
944                                 
945                                 for (int i = 0; i < len; i++)
946                                         val.SetValue (ReadObject (r, ctx), i);
947                                 
948                                 return val;
949                         }
950                         
951                         protected override Type Type {
952                                 get { return typeof (Array); }
953                         }
954
955                         protected override int NumberOfIds {
956                                 get { return 2; }
957                         }
958                 }
959                 
960                 class FontUnitFormatter : StringFormatter
961                 {
962                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
963                         {
964                                 base.Write (w, o.ToString (), ctx);
965                         }
966                         
967                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
968                         {
969                                 return FontUnit.Parse ((string) base.Read (token, r, ctx));
970                         }
971                         
972                         protected override Type Type {
973                                 get { return typeof (FontUnit); }
974                         }
975                 }
976
977                 class UnitFormatter : StringFormatter
978                 {
979                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
980                         {
981                                 base.Write (w, o.ToString (), ctx);
982                         }
983                         
984                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
985                         {
986                                 return Unit.Parse ((string) base.Read (token, r, ctx));
987                         }
988                         
989                         protected override Type Type {
990                                 get { return typeof (Unit); }
991                         }
992                 }
993
994                 class TypeConverterFormatter : StringFormatter
995                 {
996                         TypeConverter converter;
997
998                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
999                         {
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);
1005                         }
1006                         
1007                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
1008                         {
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);
1014                         }
1015                         
1016                         protected override Type Type {
1017                                 get { return typeof (TypeConverter); }
1018                         }
1019
1020                         public TypeConverter Converter {
1021                                 set { converter = value; }
1022                         }
1023                 }
1024
1025                 class BinaryObjectFormatter : ObjectFormatter
1026                 {
1027                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
1028                         {
1029                                 w.Write (PrimaryId);
1030                                 
1031                                 MemoryStream ms = new MemoryStream (128);
1032                                 new BinaryFormatter ().Serialize (ms, o);
1033                                 
1034                                 byte [] buf = ms.GetBuffer ();
1035                                 Write7BitEncodedInt (w, buf.Length);
1036                                 w.Write (buf, 0, buf.Length);
1037                         }
1038                         
1039                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
1040                         {
1041                                 int len = Read7BitEncodedInt (r);
1042                                 byte [] buf = r.ReadBytes (len);
1043                                 if (buf.Length != len)
1044                                         throw new Exception ();
1045                                 
1046                                 return new BinaryFormatter ().Deserialize (new MemoryStream (buf));
1047                         }
1048                         
1049                         protected override Type Type {
1050                                 get { return typeof (object); }
1051                         }
1052                 }
1053                 
1054 #endregion
1055                 
1056 #endregion
1057         }
1058 }