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