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