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