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