2004-01-28 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mcs / class / System.Web / System.Web.UI / ObjectStateFormatter.cs
1 //
2 // System.Web.UI.ObjectStateFormatter
3 //
4 // Authors:
5 //      Ben Maurer (bmaurer@users.sourceforge.net)
6 //
7 // (C) 2003 Ben Maurer
8 //
9
10 //#define TRACE
11
12 using System.Collections;
13 using System.Drawing;
14 using System.IO;
15 using System.Reflection;
16 using System.Runtime.Serialization.Formatters.Binary;
17 using System.Runtime.Serialization;
18 using System.Text;
19 using System.Web.UI.WebControls;
20 using System.Web.Util;
21 using System.Diagnostics;
22
23 namespace System.Web.UI {
24         #if NET_1_2
25                 public
26         #else
27                 internal
28         #endif
29         sealed class ObjectStateFormatter : IFormatter {
30                 public object Deserialize (Stream inputStream)
31                 {
32                         if (inputStream == null)
33                                 throw new ArgumentNullException ("inputStream");
34
35                         return DeserializeObject (new BinaryReader (inputStream));
36                 }
37                 
38                 public object Deserialize (string inputString)
39                 {
40                         if (inputString == null)
41                                 throw new ArgumentNullException ("inputString");
42
43                         if (inputString == "")
44                                 return null;
45
46                         return Deserialize (new MemoryStream (Convert.FromBase64String (inputString)));
47                 }
48                 
49                 public string Serialize (object stateGraph)
50                 {
51                         if (stateGraph == null)
52                                 return "";
53                         
54                         MemoryStream ms = new MemoryStream ();
55                         Serialize (ms, stateGraph);
56                         
57                         #if TRACE
58                                 ms.WriteTo (File.OpenWrite (Path.GetTempFileName ()));
59                         #endif
60                         
61                         return Convert.ToBase64String (ms.GetBuffer (), 0, (int) ms.Length);
62                 }
63                 
64                 public void Serialize (Stream outputStream, object stateGraph)
65                 {
66                         if (outputStream == null)
67                                 throw new ArgumentNullException ("outputStream");
68
69                         if (stateGraph == null)
70                                 throw new ArgumentNullException ("stateGraph");
71
72                         SerializeValue (new BinaryWriter (outputStream), stateGraph);
73                 }
74                 
75                 void SerializeValue (BinaryWriter w, object o)
76                 {
77                         ObjectFormatter.WriteObject (w, o, new WriterContext ());
78                 }
79                 
80                 object DeserializeObject (BinaryReader r)
81                 {
82                         return ObjectFormatter.ReadObject (r, new ReaderContext ());
83                 }
84                 
85                 #region IFormatter
86                 
87                 object IFormatter.Deserialize (Stream serializationStream)
88                 {
89                         return Deserialize (serializationStream);
90                 }
91                 
92                 void IFormatter.Serialize (Stream serializationStream, object stateGraph)
93                 {
94                         Serialize (serializationStream, stateGraph);
95                 }
96                 
97                 SerializationBinder IFormatter.Binder {
98                         get { return null; }
99                         set { }
100                 }
101                 
102                 StreamingContext IFormatter.Context {
103                         get { return new StreamingContext (StreamingContextStates.All); }
104                         set { }
105                 }
106                 
107                 ISurrogateSelector IFormatter.SurrogateSelector {
108                         get { return null; }
109                         set { }
110                 }
111                 
112                 #endregion
113
114                 #region Object Readers/Writers
115                 
116                 class WriterContext {
117                         Hashtable cache;
118                         short nextKey = 0;
119                         
120                         public bool RegisterCache (object o, out short key)
121                         {
122                                 if (cache == null) {
123                                         cache = new Hashtable ();
124                                         cache.Add (o, key = nextKey++);
125                                         return false;
126                                 }
127                                 
128                                 object posKey = cache [o];
129                                 if (posKey == null) {
130                                         cache.Add (o, key = nextKey++);
131                                         return false;
132                                 }
133                                 
134                                 key = (short) posKey;
135                                 return true;
136                         }
137                 }
138                 
139                 class ReaderContext {
140                         ArrayList cache;
141                         
142                         public void CacheItem (object o)
143                         {
144                                 if (cache == null)
145                                         cache = new ArrayList ();
146                                 
147                                 cache.Add (o);
148                         }
149                         
150                         public object GetCache (short key)
151                         {
152                                 return cache [key];
153                         }
154                 }
155                 
156                 abstract class ObjectFormatter {
157                         static readonly Hashtable writeMap = new Hashtable ();
158                         static ObjectFormatter [] readMap = new ObjectFormatter [256];
159                         static BinaryObjectFormatter binaryObjectFormatter;
160                         static TypeFormatter typeFormatter;
161                         static EnumFormatter enumFormatter;
162                         static SingleRankArrayFormatter singleRankArrayFormatter;
163                         
164                         static ObjectFormatter ()
165                         {                       
166                                 new StringFormatter ().Register ();
167                                 new Int64Formatter ().Register ();
168                                 new Int32Formatter ().Register ();
169                                 new Int16Formatter ().Register ();
170                                 new ByteFormatter ().Register ();
171                                 new BooleanFormatter ().Register ();
172                                 new CharFormatter ().Register ();
173                                 new DateTimeFormatter ().Register ();
174                                 new PairFormatter ().Register ();
175                                 new TripletFormatter ().Register ();
176                                 new ArrayListFormatter ().Register ();
177                                 new HashtableFormatter ().Register ();
178                                 new ObjectArrayFormatter ().Register ();
179                                 new UnitFormatter ().Register ();
180                                 new FontUnitFormatter ().Register ();
181                                 
182                                 new ColorFormatter ().Register ();
183                                 
184                                 enumFormatter = new EnumFormatter ();
185                                 enumFormatter.Register ();
186                                 
187                                 typeFormatter = new TypeFormatter ();
188                                 typeFormatter.Register ();
189                                 
190                                 singleRankArrayFormatter = new SingleRankArrayFormatter ();
191                                 singleRankArrayFormatter.Register ();
192                                 
193                                 binaryObjectFormatter = new BinaryObjectFormatter ();
194                                 binaryObjectFormatter.Register ();
195                         }
196                 
197                         // 0 == null
198                         static byte nextId = 1;
199                         
200                         public ObjectFormatter ()
201                         {
202                                 PrimaryId = nextId ++;
203                                 if (NumberOfIds == 1)
204                                         return;
205                                 
206                                 SecondaryId = nextId ++;
207                                 if (NumberOfIds == 2)
208                                         return;
209                                 
210                                 TertiaryId = nextId ++;
211                                 if (NumberOfIds == 3)
212                                         return;
213                                 
214                                 throw new Exception ();
215                         }
216                         
217                         protected readonly byte PrimaryId, SecondaryId = 255, TertiaryId = 255;
218                         
219                         protected abstract void Write (BinaryWriter w, object o, WriterContext ctx);
220                         protected abstract object Read (byte token, BinaryReader r, ReaderContext ctx);
221                         protected abstract Type Type { get; }
222                         protected virtual int NumberOfIds { get { return 1; } }
223                         
224                         public virtual void Register ()
225                         {
226                                 writeMap [Type] = this;
227                                 readMap [PrimaryId] = this;
228                                 if (SecondaryId != 255) {
229                                         readMap [SecondaryId] = this;
230                                         if (TertiaryId != 255)
231                                                 readMap [TertiaryId] = this;
232                                 }
233                         }
234                         
235                         public static void WriteObject (BinaryWriter w, object o, WriterContext ctx)
236                         {
237                                 #if TRACE
238                                 if (o != null) {
239                                         Trace.WriteLine (String.Format ("Writing {0} (type: {1})", o, o.GetType ()));
240                                         Trace.Indent ();
241                                 } else {
242                                         Trace.WriteLine ("Writing null");
243                                 }
244                                 long pos = w.BaseStream.Position;
245                                 #endif
246                                 
247                                 if (o == null) {
248                                         w.Write ((byte) 0);
249                                         return;
250                                 }
251                                 
252                                 Type t = o.GetType ();
253                                 
254                                 ObjectFormatter fmt = writeMap [t] as ObjectFormatter;
255                                 if (fmt == null) {
256                                         // Handle abstract types here
257                                         
258                                         if (o is Type)
259                                                 fmt = typeFormatter;
260                                         else if (t.IsEnum)
261                                                 fmt = enumFormatter;
262                                         else if (t.IsArray && ((Array) o).Rank == 1)
263                                                 fmt = singleRankArrayFormatter;
264                                         else
265                                                 fmt = binaryObjectFormatter;
266                                 }
267
268                                 fmt.Write (w, o, ctx);
269                                 #if TRACE
270                                 Trace.Unindent ();
271                                 Trace.WriteLine (String.Format ("Wrote {0} (type: {1}) {2} bytes", o, o.GetType (), w.BaseStream.Position - pos));
272                                 #endif
273                         }
274                         
275                         public static object ReadObject (BinaryReader r, ReaderContext ctx)
276                         {
277                                 byte sig = r.ReadByte ();
278                                 
279                                 if (sig == 0)
280                                         return null;
281                                 
282                                 return readMap [sig].Read (sig, r, ctx);
283                         }
284                         
285                         protected void Write7BitEncodedInt (BinaryWriter w, int value)
286                         {
287                                 do {
288                                         int high = (value >> 7) & 0x01ffffff;
289                                         byte b = (byte)(value & 0x7f);
290         
291                                         if (high != 0) {
292                                                 b = (byte)(b | 0x80);
293                                         }
294         
295                                         w.Write(b);
296                                         value = high;
297                                 } while(value != 0);
298                         }
299                         
300                         protected int Read7BitEncodedInt (BinaryReader r)
301                         {
302                                 int ret = 0;
303                                 int shift = 0;
304                                 byte b;
305         
306                                 do {
307                                         b = r.ReadByte();
308                                         
309                                         ret = ret | ((b & 0x7f) << shift);
310                                         shift += 7;
311                                 } while ((b & 0x80) == 0x80);
312         
313                                 return ret;
314                         }
315                 }
316                 
317                 #region Primitive Formatters
318                 class StringFormatter : ObjectFormatter {
319                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
320                         {
321                                 short key;
322                                 if (ctx.RegisterCache (o, out key)) {
323                                         w.Write (SecondaryId);
324                                         w.Write (key);
325                                 } else {
326                                         w.Write (PrimaryId);
327                                         w.Write ((string)o);
328                                 }
329                         }
330                         
331                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
332                         {
333                                 if (token == PrimaryId) {
334                                         string s = r.ReadString ();
335                                         ctx.CacheItem (s);
336                                         return s;
337                                 } else {
338                                         return ctx.GetCache (r.ReadInt16 ());
339                                 }
340                         }
341                         protected override Type Type {
342                                 get { return typeof (string); }
343                         }
344                         
345                         protected override int NumberOfIds {
346                                 get { return 2; }
347                         }
348                 }
349                 
350                 class Int64Formatter : ObjectFormatter {
351                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
352                         {
353                                 w.Write (PrimaryId);
354                                 w.Write ((long)o);
355                         }
356                         
357                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
358                         {
359                                 return r.ReadInt64 ();
360                         }
361                         protected override Type Type {
362                                 get { return typeof (long); }
363                         }
364                 }
365                 
366                 class Int32Formatter : ObjectFormatter {
367                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
368                         {
369                                 int i = (int) o;
370                                 if ((int)(byte) i == i) {
371                                         w.Write (SecondaryId);
372                                         w.Write ((byte) i);
373                                 } else {
374                                         w.Write (PrimaryId);
375                                         w.Write (i);
376                                 }
377                         }
378                         
379                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
380                         {
381                                 if (token == PrimaryId)
382                                         return r.ReadInt32 ();
383                                 else
384                                         return (int) r.ReadByte ();
385                         }
386                         protected override Type Type {
387                                 get { return typeof (int); }
388                         }
389                         
390                         protected override int NumberOfIds {
391                                 get { return 2; }
392                         }
393                 }
394                 
395                 class Int16Formatter : ObjectFormatter {
396                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
397                         {
398                                 w.Write (PrimaryId);
399                                 w.Write ((short)o);
400                         }
401                         
402                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
403                         {
404                                 return r.ReadInt16 ();
405                         }
406                         protected override Type Type {
407                                 get { return typeof (short); }
408                         }
409                 }
410                 
411                 class ByteFormatter : ObjectFormatter {
412                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
413                         {
414                                 w.Write (PrimaryId);
415                                 w.Write ((byte)o);
416                         }
417                         
418                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
419                         {
420                                 return r.ReadByte ();
421                         }
422                         protected override Type Type {
423                                 get { return typeof (byte); }
424                         }
425                 }
426                 
427                 class BooleanFormatter : ObjectFormatter {
428                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
429                         {
430                                 if ((bool)o == true)
431                                         w.Write (PrimaryId);
432                                 else
433                                         w.Write (SecondaryId);
434                         }
435                         
436                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
437                         {
438                                 return token == PrimaryId;
439                         }
440                         
441                         protected override Type Type {
442                                 get { return typeof (bool); }
443                         }
444                         
445                         protected override int NumberOfIds {
446                                 get { return 2; }
447                         }
448                 }
449                 
450                 class CharFormatter : ObjectFormatter {
451                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
452                         {
453                                 w.Write (PrimaryId);
454                                 w.Write ((char) o);
455                         }
456                         
457                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
458                         {
459                                 return r.ReadChar ();
460                         }
461                         
462                         protected override Type Type {
463                                 get { return typeof (char); }
464                         }
465                 }
466                 
467                 class DateTimeFormatter : ObjectFormatter {
468                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
469                         {
470                                 w.Write (PrimaryId);
471                                 w.Write (((DateTime) o).Ticks);
472                         }
473                         
474                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
475                         {
476                                 return new DateTime (r.ReadInt64 ());
477                         }
478                         
479                         protected override Type Type {
480                                 get { return typeof (DateTime); }
481                         }
482                 }
483                 
484                 class PairFormatter : ObjectFormatter {
485                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
486                         {
487                                 Pair p = (Pair) o;
488                                 w.Write (PrimaryId);
489                                 WriteObject (w, p.First, ctx);
490                                 WriteObject (w, p.Second, ctx);
491                         }
492                         
493                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
494                         {
495                                 Pair p = new Pair ();
496                                 p.First = ReadObject (r, ctx);
497                                 p.Second = ReadObject (r, ctx);
498                                 return p;
499                         }
500                         
501                         protected override Type Type {
502                                 get { return typeof (Pair); }
503                         }
504                 }
505                 
506                 class TripletFormatter : ObjectFormatter {
507                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
508                         {
509                                 Triplet t = (Triplet) o;
510                                 w.Write (PrimaryId);
511                                 WriteObject (w, t.First, ctx);
512                                 WriteObject (w, t.Second, ctx);
513                                 WriteObject (w, t.Third, ctx);
514                         }
515                         
516                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
517                         {
518                                 Triplet t = new Triplet ();
519                                 t.First = ReadObject (r, ctx);
520                                 t.Second = ReadObject (r, ctx);
521                                 t.Third = ReadObject (r, ctx);
522                                 return t;
523                         }
524                         
525                         protected override Type Type {
526                                 get { return typeof (Triplet); }
527                         }
528                 }
529                 
530                 class ArrayListFormatter : ObjectFormatter {
531                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
532                         {
533                                 ArrayList l = (ArrayList) o;
534                                 
535                                 w.Write (PrimaryId);
536                                 Write7BitEncodedInt (w, l.Count);
537                                 foreach (object i in l)
538                                         WriteObject (w, i, ctx);
539                         }
540                         
541                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
542                         {
543                                 int len = Read7BitEncodedInt (r);
544                                 ArrayList l = new ArrayList (len);
545                                 
546                                 for (int i = 0; i < len; i++)
547                                         l.Add (ReadObject (r, ctx));
548                                 
549                                 return l;
550                         }
551                         
552                         protected override Type Type {
553                                 get { return typeof (ArrayList); }
554                         }
555                 }
556                 
557                 class HashtableFormatter : ObjectFormatter {
558                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
559                         {
560                                 Hashtable ht = (Hashtable) o;
561                                 
562                                 w.Write (PrimaryId);
563                                 Write7BitEncodedInt (w, ht.Count);
564                                 foreach (DictionaryEntry de in ht) {
565                                         WriteObject (w, de.Key, ctx);
566                                         WriteObject (w, de.Value, ctx);
567                                 }
568                         }
569                         
570                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
571                         {
572                                 int len = Read7BitEncodedInt (r);
573                                 Hashtable ht = new Hashtable (len);
574                                 
575                                 for (int i = 0; i < len; i++) {
576                                         object key = ReadObject (r, ctx);
577                                         object val = ReadObject (r, ctx);
578                                         
579                                         ht.Add (key, val);
580                                 }
581                                 
582                                 return ht;
583                         }
584                         
585                         protected override Type Type {
586                                 get { return typeof (Hashtable); }
587                         }
588                 }
589                 
590                 class ObjectArrayFormatter : ObjectFormatter {
591                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
592                         {
593                                 object [] val = (object []) o;
594                                 
595                                 w.Write (PrimaryId);
596                                 Write7BitEncodedInt (w, val.Length);
597                                 foreach (object i in val)
598                                         WriteObject (w, i, ctx);
599                         }
600                         
601                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
602                         {
603                                 int len = Read7BitEncodedInt (r);
604                                 object [] ret = new object [len];
605                                 
606                                 for (int i = 0; i < len; i++)
607                                         ret [i] = ReadObject (r, ctx);
608                                 
609                                 return ret;
610                         }
611                         
612                         protected override Type Type {
613                                 get { return typeof (object []); }
614                         }
615                 }
616                 
617                 #endregion
618                 
619                 #region System.Web Optimizations
620                 class ColorFormatter : ObjectFormatter {
621                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
622                         {
623                                 Color c = (Color) o;
624                                 
625                                 if (!c.IsKnownColor) {
626                                         w.Write (PrimaryId);
627                                         w.Write (c.ToArgb ());
628                                 } else {
629                                         w.Write (SecondaryId);
630                                         w.Write ((int) c.ToKnownColor ());
631                                 }
632                         }
633                         
634                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
635                         {
636                                 if (token == PrimaryId)
637                                         return Color.FromArgb (r.ReadInt32 ());
638                                 else
639                                         return Color.FromKnownColor ((KnownColor) r.ReadInt32 ());
640                         }
641                         
642                         protected override Type Type {
643                                 get { return typeof (Color); }
644                         }
645                         
646                         protected override int NumberOfIds {
647                                 get { return 2; }
648                         }
649                 }
650                 
651                 #endregion
652                 
653                 #region Special Formatters
654                 class EnumFormatter : ObjectFormatter {
655                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
656                         {
657                                 object value = Convert.ChangeType (o, ((Enum) o).GetTypeCode ());
658                                 w.Write (PrimaryId);
659                                 WriteObject (w, o.GetType (), ctx);
660                                 WriteObject (w, value, ctx);
661                         }
662                         
663                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
664                         {
665                                 Type t = (Type) ReadObject (r, ctx);
666                                 object value = ReadObject (r, ctx);
667                                 
668                                 return Enum.ToObject (t, value);
669                         }
670                         protected override Type Type {
671                                 get { return typeof (Enum); }
672                         }
673                 }
674                 
675                 class TypeFormatter : ObjectFormatter {
676                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
677                         {
678                                 short key;
679                                 if (ctx.RegisterCache (o, out key)) {
680                                         w.Write (SecondaryId);
681                                         w.Write (key);
682                                 } else {
683                                         w.Write (PrimaryId);
684                                         w.Write (((Type) o).FullName);
685                                         
686                                         // We should cache the name of the assembly
687                                         w.Write (((Type) o).Assembly.FullName);
688                                 }
689                         }
690                         
691                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
692                         {
693                                 if (token == PrimaryId) {
694                                         string type = r.ReadString ();
695                                         string assembly = r.ReadString ();
696                                         
697                                         Type t = Assembly.Load (assembly).GetType (type);
698                                         ctx.CacheItem (t);
699                                         return t;
700                                 } else {
701                                         return ctx.GetCache (r.ReadInt16 ());
702                                 }
703                         }
704                         
705                         protected override Type Type {
706                                 get { return typeof (Type); }
707                         }
708                         
709                         protected override int NumberOfIds {
710                                 get { return 2; }
711                         }
712                 }
713                 
714                 class SingleRankArrayFormatter : ObjectFormatter {
715                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
716                         {
717                                 Array val = (Array) o;
718                                 
719                                 w.Write (PrimaryId);
720                                 WriteObject (w, val.GetType ().GetElementType (), ctx);
721                                 
722                                 Write7BitEncodedInt (w, val.Length);
723                                 foreach (object i in val)
724                                         WriteObject (w, i, ctx);
725                         }
726                         
727                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
728                         {
729                                 Type t = (Type) ReadObject (r, ctx);
730                                 int len = Read7BitEncodedInt (r);
731                                 Array val = Array.CreateInstance (t, len);
732                                 
733                                 for (int i = 0; i < len; i++)
734                                         val.SetValue (ReadObject (r, ctx), i);
735                                 
736                                 return val;
737                         }
738                         
739                         protected override Type Type {
740                                 get { return typeof (Array); }
741                         }
742                 }
743                 
744                 class FontUnitFormatter : StringFormatter {
745                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
746                         {
747                                 base.Write (w, o.ToString (), ctx);
748                         }
749                         
750                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
751                         {
752                                 return FontUnit.Parse ((string) base.Read (token, r, ctx));
753                         }
754                         
755                         protected override Type Type {
756                                 get { return typeof (FontUnit); }
757                         }
758                 }
759
760                 class UnitFormatter : StringFormatter {
761                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
762                         {
763                                 base.Write (w, o.ToString (), ctx);
764                         }
765                         
766                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
767                         {
768                                 return Unit.Parse ((string) base.Read (token, r, ctx));
769                         }
770                         
771                         protected override Type Type {
772                                 get { return typeof (Unit); }
773                         }
774                 }
775
776                 class BinaryObjectFormatter : ObjectFormatter {
777                         protected override void Write (BinaryWriter w, object o, WriterContext ctx)
778                         {
779                                 w.Write (PrimaryId);
780                                 
781                                 MemoryStream ms = new MemoryStream (128);
782                                 new BinaryFormatter ().Serialize (ms, o);
783                                 
784                                 byte [] buf = ms.GetBuffer ();
785                                 Write7BitEncodedInt (w, buf.Length);
786                                 w.Write (buf, 0, buf.Length);
787                         }
788                         
789                         protected override object Read (byte token, BinaryReader r, ReaderContext ctx)
790                         {
791                                 int len = Read7BitEncodedInt (r);
792                                 byte [] buf = r.ReadBytes (len);
793                                 if (buf.Length != len)
794                                         throw new Exception ();
795                                 
796                                 return new BinaryFormatter ().Deserialize (new MemoryStream (buf));
797                         }
798                         
799                         protected override Type Type {
800                                 get { return typeof (object); }
801                         }
802                 }
803                 
804                 #endregion
805                 
806                 #endregion
807         }
808 }