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