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