[corlib] Fixed StringBuilder construction bugs in marshalling caused by changes to...
[mono.git] / mcs / class / corlib / System.Runtime.Serialization.Formatters.Binary / ObjectReader.cs
1 // ObjectReader.cs
2 //
3 // Author:
4 //   Lluis Sanchez Gual (lluis@ideary.com)
5 //   Patrik Torstensson
6 //
7 // (C) 2003 Lluis Sanchez Gual
8
9 //
10 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System;
33 using System.Runtime.Serialization;
34 using System.IO;
35 using System.Collections;
36 using System.Reflection;
37 using System.Runtime.Remoting.Messaging;
38 using System.Globalization;
39
40 namespace System.Runtime.Serialization.Formatters.Binary
41 {
42         internal class ObjectReader
43         {
44 //              BinaryFormatter _formatter;
45                 ISurrogateSelector _surrogateSelector;
46                 StreamingContext _context;
47                 SerializationBinder _binder;
48                 
49                 TypeFilterLevel _filterLevel;
50
51                 ObjectManager _manager;
52                 Hashtable _registeredAssemblies = new Hashtable();
53                 Hashtable _typeMetadataCache = new Hashtable();
54
55                 object _lastObject = null;
56                 long _lastObjectID = 0;
57                 long _rootObjectID = 0;
58                 byte[] arrayBuffer;
59                 int ArrayBufferLength = 4096;
60
61                 class TypeMetadata
62                 {
63                         public Type Type;
64                         public Type[] MemberTypes;
65                         public string[] MemberNames;
66                         public MemberInfo[] MemberInfos;
67                         public int FieldCount;
68                         public bool NeedsSerializationInfo;
69                 }
70
71                 class ArrayNullFiller
72                 {
73                         public ArrayNullFiller(int count) { NullCount = count; }
74                         public int NullCount;
75                 }
76
77                 public ObjectReader (BinaryFormatter formatter)
78                 {
79 //                      _formatter = formatter;
80                         _surrogateSelector = formatter.SurrogateSelector;
81                         _context = formatter.Context;
82                         _binder = formatter.Binder;
83                         _manager = new ObjectManager (_surrogateSelector, _context);
84                         
85                         _filterLevel = formatter.FilterLevel;
86                 }
87
88                 public void ReadObjectGraph (BinaryReader reader, bool readHeaders, out object result, out Header[] headers)
89                 {
90                         BinaryElement elem = (BinaryElement)reader.ReadByte ();
91                         ReadObjectGraph (elem, reader, readHeaders, out result, out headers);
92                 }
93
94                 public void ReadObjectGraph (BinaryElement elem, BinaryReader reader, bool readHeaders, out object result, out Header[] headers)
95                 {
96                         headers = null;
97
98                         // Reads the objects. The first object in the stream is the
99                         // root object.
100                         bool next = ReadNextObject (elem, reader);
101                         if (next) {
102                                 do {
103                                         if (readHeaders && (headers == null))
104                                                 headers = (Header[])CurrentObject;
105                                         else
106                                                 if (_rootObjectID == 0) _rootObjectID = _lastObjectID;
107                                 } while (ReadNextObject (reader));
108                         }
109
110                         result = _manager.GetObject (_rootObjectID);
111                 }
112
113                 bool ReadNextObject (BinaryElement element, BinaryReader reader)
114                 {
115                         if (element == BinaryElement.End)
116                         {
117                                 _manager.DoFixups();
118
119                                 _manager.RaiseDeserializationEvent();
120                                 return false;
121                         }
122
123                         SerializationInfo info;
124                         long objectId;
125
126                         ReadObject (element, reader, out objectId, out _lastObject, out info);
127
128                         if (objectId != 0) {
129                                 RegisterObject (objectId, _lastObject, info, 0, null, null);
130                                 _lastObjectID = objectId;               
131                         }
132         
133                         return true;
134                 }
135
136                 public bool ReadNextObject (BinaryReader reader)
137                 {
138                         BinaryElement element = (BinaryElement)reader.ReadByte ();
139                         if (element == BinaryElement.End)
140                         {
141                                 _manager.DoFixups();
142
143                                 _manager.RaiseDeserializationEvent();
144                                 return false;
145                         }
146
147                         SerializationInfo info;
148                         long objectId;
149
150                         ReadObject (element, reader, out objectId, out _lastObject, out info);
151
152                         if (objectId != 0) {
153                                 RegisterObject (objectId, _lastObject, info, 0, null, null);
154                                 _lastObjectID = objectId;               
155                         }
156         
157                         return true;
158                 }
159
160                 public object CurrentObject
161                 {
162                         get { return _lastObject; }
163                 }
164
165                 // Reads an object from the stream. The object is registered in the ObjectManager.
166                 // The result can be either the object instance
167                 // or the id of the object (when what is found in the stream is an object reference).
168                 // If an object instance is read, the objectId is set to 0.
169                 
170                 private void ReadObject (BinaryElement element, BinaryReader reader, out long objectId, out object value, out SerializationInfo info)
171                 {
172                         switch (element)
173                         {
174                                 case BinaryElement.RefTypeObject:
175                                         ReadRefTypeObjectInstance (reader, out objectId, out value, out info);
176                                         break;
177
178                                 case BinaryElement.UntypedRuntimeObject:
179                                         ReadObjectInstance (reader, true, false, out objectId, out value, out info);
180                                         break;
181
182                                 case BinaryElement.UntypedExternalObject:
183                                         ReadObjectInstance (reader, false, false, out objectId, out value, out info);
184                                         break;
185
186                                 case BinaryElement.RuntimeObject:
187                                         ReadObjectInstance (reader, true, true, out objectId, out value, out info);
188                                         break;
189
190                                 case BinaryElement.ExternalObject:
191                                         ReadObjectInstance (reader, false, true, out objectId, out value, out info);
192                                         break;
193
194                                 case BinaryElement.String:
195                                         info = null;
196                                         ReadStringIntance (reader, out objectId, out value);
197                                         break;
198
199                                 case BinaryElement.GenericArray:
200                                         info = null;
201                                         ReadGenericArray (reader, out objectId, out value);
202                                         break;
203
204
205                                 case BinaryElement.BoxedPrimitiveTypeValue:
206                                         value = ReadBoxedPrimitiveTypeValue (reader);
207                                         objectId = 0;
208                                         info = null;
209                                         break;
210
211                                 case BinaryElement.NullValue:
212                                         value = null;
213                                         objectId = 0;
214                                         info = null;
215                                         break;
216
217                                 case BinaryElement.Assembly:
218                                         ReadAssembly (reader);
219                                         ReadObject ((BinaryElement)reader.ReadByte (), reader, out objectId, out value, out info);
220                                         break;
221
222                                 case BinaryElement.ArrayFiller8b:
223                                         value = new ArrayNullFiller(reader.ReadByte());
224                                         objectId = 0;
225                                         info = null;
226                                         break;
227
228                                 case BinaryElement.ArrayFiller32b:
229                                         value = new ArrayNullFiller(reader.ReadInt32());
230                                         objectId = 0;
231                                         info = null;
232                                         break;
233
234                                 case BinaryElement.ArrayOfPrimitiveType:
235                                         ReadArrayOfPrimitiveType (reader, out objectId, out value);
236                                         info = null;
237                                         break;
238
239                                 case BinaryElement.ArrayOfObject:
240                                         ReadArrayOfObject (reader, out objectId, out value);
241                                         info = null;
242                                         break;
243
244                                 case BinaryElement.ArrayOfString:
245                                         ReadArrayOfString (reader, out objectId, out value);
246                                         info = null;
247                                         break;
248
249                                 default:
250                                         throw new SerializationException ("Unexpected binary element: " + (int)element);
251                         }
252                 }
253
254                 private void ReadAssembly (BinaryReader reader)
255                 {
256                         long id = (long) reader.ReadUInt32 ();
257                         string assemblyName = reader.ReadString ();
258                         _registeredAssemblies [id] = assemblyName;
259                 }
260
261                 private void ReadObjectInstance (BinaryReader reader, bool isRuntimeObject, bool hasTypeInfo, out long objectId, out object value, out SerializationInfo info)
262                 {
263                         objectId = (long) reader.ReadUInt32 ();
264
265                         TypeMetadata metadata = ReadTypeMetadata (reader, isRuntimeObject, hasTypeInfo);
266                         ReadObjectContent (reader, metadata, objectId, out value, out info);
267                 }
268
269                 private void ReadRefTypeObjectInstance (BinaryReader reader, out long objectId, out object value, out SerializationInfo info)
270                 {
271                         objectId = (long) reader.ReadUInt32 ();
272                         long refTypeObjectId = (long) reader.ReadUInt32 ();
273
274                         // Gets the type of the referred object and its metadata
275
276                         object refObj = _manager.GetObject (refTypeObjectId);
277                         if (refObj == null) throw new SerializationException ("Invalid binary format");
278                         TypeMetadata metadata = (TypeMetadata)_typeMetadataCache [refObj.GetType()];
279
280                         ReadObjectContent (reader, metadata, objectId, out value, out info);
281                 }
282
283                 private void ReadObjectContent (BinaryReader reader, TypeMetadata metadata, long objectId, out object objectInstance, out SerializationInfo info)
284                 {
285                         if (_filterLevel == TypeFilterLevel.Low)
286                                 objectInstance = FormatterServices.GetSafeUninitializedObject (metadata.Type);
287                         else
288                                 objectInstance = FormatterServices.GetUninitializedObject (metadata.Type);
289                         _manager.RaiseOnDeserializingEvent (objectInstance);
290                                 
291                         info = metadata.NeedsSerializationInfo ? new SerializationInfo(metadata.Type, new FormatterConverter()) : null;
292
293                         if (metadata.MemberNames != null) {
294                                 for (int n=0; n<metadata.FieldCount; n++)
295                                         ReadValue (reader, objectInstance, objectId, info, metadata.MemberTypes[n], metadata.MemberNames[n], null, null);
296                         } else
297                                 for (int n=0; n<metadata.FieldCount; n++) {
298                                         if (metadata.MemberInfos [n] != null)
299                                                 ReadValue (reader, objectInstance, objectId, info, metadata.MemberTypes[n], metadata.MemberInfos[n].Name, metadata.MemberInfos[n], null);
300                                         else if (BinaryCommon.IsPrimitive(metadata.MemberTypes[n])) {
301                                                 // Since the member info is null, the type in this
302                                                 // domain does not have this type. Even though we
303                                                 // are not going to store the value, we will read
304                                                 // it from the stream so that we can advance to the
305                                                 // next block.
306                                                 ReadPrimitiveTypeValue (reader, metadata.MemberTypes[n]);
307                                         }
308                                 }
309                 }
310
311                 private void RegisterObject (long objectId, object objectInstance, SerializationInfo info, long parentObjectId, MemberInfo parentObjectMemeber, int[] indices)
312                 {
313                         if (parentObjectId == 0) indices = null;
314
315                         if (!objectInstance.GetType().IsValueType || parentObjectId == 0)
316                                 _manager.RegisterObject (objectInstance, objectId, info, 0, null, null);
317                         else
318                         {
319                                 if (indices != null) indices = (int[])indices.Clone();
320                                 _manager.RegisterObject (objectInstance, objectId, info, parentObjectId, parentObjectMemeber, indices);
321                         }
322                 }
323
324                 private void ReadStringIntance (BinaryReader reader, out long objectId, out object value)
325                 {
326                         objectId = (long) reader.ReadUInt32 ();
327                         value = reader.ReadString ();
328                 }
329
330                 private void ReadGenericArray (BinaryReader reader, out long objectId, out object val)
331                 {
332                         objectId = (long) reader.ReadUInt32 ();
333                         // Array structure
334                         reader.ReadByte();
335
336                         int rank = reader.ReadInt32();
337
338                         bool emptyDim = false;
339                         int[] lengths = new int[rank];
340                         for (int n=0; n<rank; n++)
341                         {
342                                 lengths[n] = reader.ReadInt32();
343                                 if (lengths[n] == 0) emptyDim = true;
344                         }
345
346                         TypeTag code = (TypeTag) reader.ReadByte ();
347                         Type elementType = ReadType (reader, code);
348
349                         Array array = Array.CreateInstance (elementType, lengths);
350
351                         if (emptyDim) 
352                         { 
353                                 val = array;
354                                 return;
355                         }
356
357                         int[] indices = new int[rank];
358
359                         // Initialize indexes
360                         for (int dim = rank-1; dim >= 0; dim--)
361                                 indices[dim] = array.GetLowerBound (dim);
362
363                         bool end = false;
364                         while (!end)
365                         {
366                                 ReadValue (reader, array, objectId, null, elementType, null, null, indices);
367
368                                 for (int dim = array.Rank-1; dim >= 0; dim--)
369                                 {
370                                         indices[dim]++;
371                                         if (indices[dim] > array.GetUpperBound (dim))
372                                         {
373                                                 if (dim > 0) 
374                                                 {
375                                                         indices[dim] = array.GetLowerBound (dim);
376                                                         continue;       // Increment the next dimension's index
377                                                 }
378                                                 end = true;     // That was the last dimension. Finished.
379                                         }
380                                         break;
381                                 }
382                         }
383                         val = array;
384                 }
385
386                 private object ReadBoxedPrimitiveTypeValue (BinaryReader reader)
387                 {
388                         Type type = ReadType (reader, TypeTag.PrimitiveType);
389                         return ReadPrimitiveTypeValue (reader, type);
390                 }
391
392                 private void ReadArrayOfPrimitiveType (BinaryReader reader, out long objectId, out object val)
393                 {
394                         objectId = (long) reader.ReadUInt32 ();
395                         int length = reader.ReadInt32 ();
396                         Type elementType = ReadType (reader, TypeTag.PrimitiveType);
397
398                         switch (Type.GetTypeCode (elementType))
399                         {
400                                 case TypeCode.Boolean: {
401                                         bool[] arr = new bool [length];
402                                         for (int n = 0; n < length; n++) arr [n] = reader.ReadBoolean();
403                                         val = arr;
404                                         break;
405                                 }
406
407                                 case TypeCode.Byte: {
408                                         byte[] arr = new byte [length];
409                                         int pos = 0;
410                                         while (pos < length) {
411                                                 int nr = reader.Read (arr, pos, length - pos);
412                                                 if (nr == 0) break;
413                                                 pos += nr;
414                                         }
415                                         val = arr;
416                                         break;
417                                 }
418
419                                 case TypeCode.Char: {
420                                         char[] arr = new char [length];
421                                         int pos = 0;
422                                         while (pos < length) {
423                                                 int nr = reader.Read (arr, pos, length - pos);
424                                                 if (nr == 0) break;
425                                                 pos += nr;
426                                         }
427                                         val = arr;
428                                         break;
429                                 }
430
431                                 case TypeCode.DateTime: {
432                                         DateTime[] arr = new DateTime [length];
433                                         for (int n = 0; n < length; n++) {
434                                                 arr [n] = DateTime.FromBinary (reader.ReadInt64 ());
435                                         }
436                                         val = arr;
437                                         break;
438                                 }
439
440                                 case TypeCode.Decimal: {
441                                         Decimal[] arr = new Decimal [length];
442                                         for (int n = 0; n < length; n++) arr [n] = reader.ReadDecimal();
443                                         val = arr;
444                                         break;
445                                 }
446
447                                 case TypeCode.Double: {
448                                         Double[] arr = new Double [length];
449                                         if (length > 2)
450                                                 BlockRead (reader, arr, 8);
451                                         else
452                                                 for (int n = 0; n < length; n++) arr [n] = reader.ReadDouble();
453                                         val = arr;
454                                         break;
455                                 }
456
457                                 case TypeCode.Int16: {
458                                         short[] arr = new short [length];
459                                         if (length > 2)
460                                                 BlockRead (reader, arr, 2);
461                                         else
462                                                 for (int n = 0; n < length; n++) arr [n] = reader.ReadInt16();
463                                         val = arr;
464                                         break;
465                                 }
466
467                                 case TypeCode.Int32: {
468                                         int[] arr = new int [length];
469                                         if (length > 2)
470                                                 BlockRead (reader, arr, 4);
471                                         else
472                                                 for (int n = 0; n < length; n++) arr [n] = reader.ReadInt32();
473                                         val = arr;
474                                         break;
475                                 }
476
477                                 case TypeCode.Int64: {
478                                         long[] arr = new long [length];
479                                         if (length > 2)
480                                                 BlockRead (reader, arr, 8);
481                                         else
482                                                 for (int n = 0; n < length; n++) arr [n] = reader.ReadInt64();
483                                         val = arr;
484                                         break;
485                                 }
486
487                                 case TypeCode.SByte: {
488                                         sbyte[] arr = new sbyte [length];
489                                         if (length > 2)
490                                                 BlockRead (reader, arr, 1);
491                                         else
492                                                 for (int n = 0; n < length; n++) arr [n] = reader.ReadSByte();
493                                         val = arr;
494                                         break;
495                                 }
496
497                                 case TypeCode.Single: {
498                                         float[] arr = new float [length];
499                                         if (length > 2)
500                                                 BlockRead (reader, arr, 4);
501                                         else
502                                                 for (int n = 0; n < length; n++) arr [n] = reader.ReadSingle();
503                                         val = arr;
504                                         break;
505                                 }
506
507                                 case TypeCode.UInt16: {
508                                         ushort[] arr = new ushort [length];
509                                         if (length > 2)
510                                                 BlockRead (reader, arr, 2);
511                                         else
512                                                 for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt16();
513                                         val = arr;
514                                         break;
515                                 }
516
517                                 case TypeCode.UInt32: {
518                                         uint[] arr = new uint [length];
519                                         if (length > 2)
520                                                 BlockRead (reader, arr, 4);
521                                         else
522                                                 for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt32();
523                                         val = arr;
524                                         break;
525                                 }
526
527                                 case TypeCode.UInt64: {
528                                         ulong[] arr = new ulong [length];
529                                         if (length > 2)
530                                                 BlockRead (reader, arr, 8);
531                                         else
532                                                 for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt64();
533                                         val = arr;
534                                         break;
535                                 }
536
537                                 case TypeCode.String: {
538                                         string[] arr = new string [length];
539                                         for (int n = 0; n < length; n++) arr [n] = reader.ReadString();
540                                         val = arr;
541                                         break;
542                                 }
543
544                                 default: {
545                                         if (elementType == typeof(TimeSpan)) {
546                                                 TimeSpan[] arr = new TimeSpan [length];
547                                                 for (int n = 0; n < length; n++) arr [n] = new TimeSpan (reader.ReadInt64 ());
548                                                 val = arr;
549                                         }
550                                         else
551                                                 throw new NotSupportedException ("Unsupported primitive type: " + elementType.FullName);
552                                         break;
553                                 }
554                         }                       
555                 }
556
557                 private void BlockRead (BinaryReader reader, Array array, int dataSize)
558                 {
559                         int totalSize = Buffer.ByteLength (array);
560                         
561                         if (arrayBuffer == null || (totalSize > arrayBuffer.Length && arrayBuffer.Length != ArrayBufferLength))
562                                 arrayBuffer = new byte [totalSize <= ArrayBufferLength ? totalSize : ArrayBufferLength];
563                         
564                         int pos = 0;
565                         while (totalSize > 0) {
566                                 int size = totalSize < arrayBuffer.Length ? totalSize : arrayBuffer.Length;
567                                 int ap = 0;
568                                 do {
569                                         int nr = reader.Read (arrayBuffer, ap, size - ap);
570                                         if (nr == 0) break;
571                                         ap += nr;
572                                 } while (ap < size);
573                                 
574                                 if (!BitConverter.IsLittleEndian && dataSize > 1)
575                                         BinaryCommon.SwapBytes (arrayBuffer, size, dataSize);
576
577                                 Buffer.BlockCopy (arrayBuffer, 0, array, pos, size);
578                                 totalSize -= size;
579                                 pos += size;
580                         }
581                 }
582                 
583
584                 private void ReadArrayOfObject (BinaryReader reader, out long objectId, out object array)
585                 {
586                         ReadSimpleArray (reader, typeof (object), out objectId, out array);
587                 }
588                 
589                 private void ReadArrayOfString (BinaryReader reader, out long objectId, out object array)
590                 {
591                         ReadSimpleArray (reader, typeof (string), out objectId, out array);
592                 }
593
594                 private void ReadSimpleArray (BinaryReader reader, Type elementType, out long objectId, out object val)
595                 {
596                         objectId = (long) reader.ReadUInt32 ();
597                         int length = reader.ReadInt32 ();
598                         int[] indices = new int[1];
599
600                         Array array = Array.CreateInstance (elementType, length);
601                         for (int n = 0; n < length; n++)
602                         {
603                                 indices[0] = n;
604                                 ReadValue (reader, array, objectId, null, elementType, null, null, indices);
605                                 n = indices[0];
606                         }
607                         val = array;
608                 }
609
610                 private TypeMetadata ReadTypeMetadata (BinaryReader reader, bool isRuntimeObject, bool hasTypeInfo)
611                 {
612                         TypeMetadata metadata = new TypeMetadata();
613
614                         string className = reader.ReadString ();
615                         int fieldCount = reader.ReadInt32 ();
616
617                         Type[] types = new Type[fieldCount];
618                         string[] names = new string[fieldCount];
619
620                         for (int n=0; n<fieldCount; n++)
621                                 names [n] = reader.ReadString ();
622
623                         if (hasTypeInfo)
624                         {
625                                 TypeTag[] codes = new TypeTag[fieldCount];
626
627                                 for (int n=0; n<fieldCount; n++)
628                                         codes [n] = (TypeTag) reader.ReadByte ();
629         
630                                 for (int n=0; n<fieldCount; n++) {
631                                         Type t = ReadType (reader, codes[n], false);
632                                         // The field's type could not be resolved: assume it is an object.
633                                         if (t == null)
634                                                 t = typeof (object);
635                                         types [n] = t;
636                                 }
637                         }
638                         
639                         // Gets the type
640
641                         if (!isRuntimeObject) 
642                         {
643                                 long assemblyId = (long)reader.ReadUInt32();
644                                 metadata.Type = GetDeserializationType (assemblyId, className);
645                         }
646                         else
647                                 metadata.Type = Type.GetType (className, true);
648
649                         metadata.MemberTypes = types;
650                         metadata.MemberNames = names;
651                         metadata.FieldCount = names.Length;
652
653                         // Now check if this objects needs a SerializationInfo struct for deserialziation.
654                         // SerializationInfo is needed if the object has to be deserialized using
655                         // a serialization surrogate, or if it implements ISerializable.
656
657                         if (_surrogateSelector != null)
658                         {
659                                 // check if the surrogate selector handles objects of the given type. 
660                                 ISurrogateSelector selector;
661                                 ISerializationSurrogate surrogate = _surrogateSelector.GetSurrogate (metadata.Type, _context, out selector);
662                                 metadata.NeedsSerializationInfo = (surrogate != null);
663                         }
664
665                         if (!metadata.NeedsSerializationInfo)
666                         {
667                                 // Check if the object is marked with the Serializable attribute
668
669                                 if (!metadata.Type.IsSerializable)
670                                         throw new SerializationException("Serializable objects must be marked with the Serializable attribute");
671
672                                 metadata.NeedsSerializationInfo = typeof (ISerializable).IsAssignableFrom (metadata.Type);
673                                 if (!metadata.NeedsSerializationInfo)
674                                 {
675                                         metadata.MemberInfos = new MemberInfo [fieldCount];
676                                         for (int n=0; n<fieldCount; n++)
677                                         {
678                                                 FieldInfo field = null;
679                                                 string memberName = names[n];
680                                                 
681                                                 int i = memberName.IndexOf ('+');
682                                                 if (i != -1) {
683                                                         string baseTypeName = names[n].Substring (0,i);
684                                                         memberName = names[n].Substring (i+1);
685                                                         Type t = metadata.Type.BaseType;
686                                                         while (t != null) {
687                                                                 if (t.Name == baseTypeName) {
688                                                                         field = t.GetField (memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
689                                                                         break;
690                                                                 }
691                                                                 else
692                                                                         t = t.BaseType;
693                                                         }
694                                                 }
695                                                 else
696                                                         field = metadata.Type.GetField (memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
697                                                         
698                                                 if (field != null)
699                                                         metadata.MemberInfos [n] = field;
700                                                 
701                                                 if (!hasTypeInfo) {
702                                                         types [n] = field.FieldType;
703                                                 }
704                                         }
705                                         metadata.MemberNames = null;    // Info now in MemberInfos
706                                 }
707                         }
708
709                         // Registers the type's metadata so it can be reused later if
710                         // a RefTypeObject element is found
711
712                         if (!_typeMetadataCache.ContainsKey (metadata.Type))
713                                 _typeMetadataCache [metadata.Type] = metadata;
714
715                         return metadata;
716                 }
717
718                 // Called for primitive types
719                 static bool IsGeneric (MemberInfo minfo)
720                 {
721                         if (minfo == null)
722                                 return false;
723
724                         Type mtype = null;
725                         switch (minfo.MemberType) {
726                         case MemberTypes.Field:
727                                 mtype = ((FieldInfo) minfo).FieldType;
728                                 break;
729                         default:
730                                 throw new NotSupportedException ("Not supported: " + minfo.MemberType);
731                         }
732                         return (mtype != null && mtype.IsGenericType);
733                 }
734
735                 private void ReadValue (BinaryReader reader, object parentObject, long parentObjectId, SerializationInfo info, Type valueType, string fieldName, MemberInfo memberInfo, int[] indices)
736                 {
737                         // Reads a value from the stream and assigns it to the member of an object
738
739                         object val;
740
741                         if (BinaryCommon.IsPrimitive (valueType) && !IsGeneric (memberInfo))
742                         {
743                                 val = ReadPrimitiveTypeValue (reader, valueType);
744                                 SetObjectValue (parentObject, fieldName, memberInfo, info, val, valueType, indices);
745                                 return;
746                         }
747
748                         // Gets the object
749
750                         BinaryElement element = (BinaryElement)reader.ReadByte ();
751
752                         if (element == BinaryElement.ObjectReference)
753                         {
754                                 // Just read the id of the referred object and record a fixup
755                                 long childObjectId = (long) reader.ReadUInt32();
756                                 RecordFixup (parentObjectId, childObjectId, parentObject, info, fieldName, memberInfo, indices);
757                                 return;
758                         }
759
760                         long objectId;
761                         SerializationInfo objectInfo;
762
763                         ReadObject (element, reader, out objectId, out val, out objectInfo);
764
765                         // There are two cases where the object cannot be assigned to the parent
766                         // and a fixup must be used:
767                         //  1) When what has been read is not an object, but an id of an object that
768                         //     has not been read yet (an object reference). This is managed in the
769                         //     previous block of code.
770                         //  2) When the read object is a value type object. Value type fields hold
771                         //     copies of objects, not references. Thus, if the value object that
772                         //     has been read has pending fixups, those fixups would be made to the
773                         //     boxed copy in the ObjectManager, and not in the required object instance
774
775                         // First of all register the fixup, and then the object. ObjectManager is more
776                         // efficient if done in this order
777
778                         bool hasFixup = false;
779                         if (objectId != 0)
780                         {
781                                 if (val.GetType().IsValueType)
782                                 {
783                                         RecordFixup (parentObjectId, objectId, parentObject, info, fieldName, memberInfo, indices);
784                                         hasFixup = true;
785                                 }
786
787                                 // Register the value
788
789                                 if (info == null && !(parentObject is Array))
790                                         RegisterObject (objectId, val, objectInfo, parentObjectId, memberInfo, null);
791                                 else
792                                         RegisterObject (objectId, val, objectInfo, parentObjectId, null, indices);
793                         }
794                         // Assign the value to the parent object, unless there is a fixup
795                         
796                         if (!hasFixup) 
797                                 SetObjectValue (parentObject, fieldName, memberInfo, info, val, valueType, indices);
798                 }
799
800                 private void SetObjectValue (object parentObject, string fieldName, MemberInfo memberInfo, SerializationInfo info, object value, Type valueType, int[] indices)
801                 {
802                         if (value is IObjectReference)
803                                 value = ((IObjectReference)value).GetRealObject (_context);
804
805                         if (parentObject is Array) 
806                         {
807                                 if (value is ArrayNullFiller) 
808                                 {
809                                         // It must be a single dimension array of objects.
810                                         // Just increase the index. Elements are null by default.
811                                         int count = ((ArrayNullFiller)value).NullCount;
812                                         indices[0] += count - 1;
813                                 }
814                                 else
815                                         ((Array)parentObject).SetValue (value, indices);
816                         }
817                         else if (info != null) {
818                                 info.AddValue (fieldName, value, valueType);
819                         }
820                         else {
821                                 if (memberInfo is FieldInfo)
822                                         ((FieldInfo)memberInfo).SetValue (parentObject, value);
823                                 else
824                                         ((PropertyInfo)memberInfo).SetValue (parentObject, value, null);
825                         }
826                 }
827
828                 private void RecordFixup (long parentObjectId, long childObjectId, object parentObject, SerializationInfo info, string fieldName, MemberInfo memberInfo, int[] indices)
829                 {
830                         if (info != null) {
831                                 _manager.RecordDelayedFixup (parentObjectId, fieldName, childObjectId);
832                         }
833                         else if (parentObject is Array) {
834                                 if (indices.Length == 1)
835                                         _manager.RecordArrayElementFixup (parentObjectId, indices[0], childObjectId);
836                                 else
837                                         _manager.RecordArrayElementFixup (parentObjectId, (int[])indices.Clone(), childObjectId);
838                         }
839                         else {
840                                 _manager.RecordFixup (parentObjectId, memberInfo, childObjectId);
841                         }
842                 }
843
844                 private Type GetDeserializationType (long assemblyId, string className)
845                 {
846                         return GetDeserializationType (assemblyId, className, true);
847                 }
848                 
849                 private Type GetDeserializationType (long assemblyId, string className, bool throwOnError)
850                 {
851                         Type t;
852                         string assemblyName = (string)_registeredAssemblies[assemblyId];
853
854                         if (_binder != null) {
855                                 t = _binder.BindToType (assemblyName, className);
856                                 if (t != null)
857                                         return t;
858                         }
859
860                         Assembly assembly;
861                         try {
862                                 assembly = Assembly.Load (assemblyName);
863                         } catch (Exception ex) {
864                                 if (!throwOnError)
865                                         return null;
866                                 throw new SerializationException (String.Format ("Couldn't find assembly '{0}'", assemblyName), ex);
867                         }
868
869                         t = assembly.GetType (className);
870                         if (t != null)
871                                 return t;
872
873                         if (!throwOnError)
874                                 return null;
875
876                         throw new SerializationException (String.Format ("Couldn't find type '{0}' in assembly '{1}'", className, assemblyName));
877                 }
878
879                 public Type ReadType (BinaryReader reader, TypeTag code)
880                 {
881                         return ReadType (reader, code, true);
882                 }
883                 
884                 public Type ReadType (BinaryReader reader, TypeTag code, bool throwOnError)
885                 {
886                         switch (code)
887                         {
888                                 case TypeTag.PrimitiveType:
889                                         return BinaryCommon.GetTypeFromCode (reader.ReadByte());
890
891                                 case TypeTag.String:
892                                         return typeof(string);
893
894                                 case TypeTag.ObjectType:
895                                         return typeof(object);
896
897                                 case TypeTag.RuntimeType:
898                                 {
899                                         string name = reader.ReadString ();
900                                         // map MS.NET's System.RuntimeType to System.MonoType
901                                         if (_context.State == StreamingContextStates.Remoting)
902                                                 if (name == "System.RuntimeType")
903                                                         return typeof (MonoType);
904                                                 else if (name == "System.RuntimeType[]")
905                                                         return typeof (MonoType[]);
906                                         Type t = Type.GetType (name);
907                                         if (t != null)
908                                                 return t;
909
910                                         throw new SerializationException (String.Format ("Could not find type '{0}'.", name));
911                                 }
912
913                                 case TypeTag.GenericType:
914                                 {
915                                         string name = reader.ReadString ();
916                                         long asmid = (long) reader.ReadUInt32();
917                                         return GetDeserializationType (asmid, name, throwOnError);
918                                 }
919
920                                 case TypeTag.ArrayOfObject:
921                                         return typeof(object[]);
922
923                                 case TypeTag.ArrayOfString:
924                                         return typeof(string[]);
925
926                                 case TypeTag.ArrayOfPrimitiveType:
927                                         Type elementType = BinaryCommon.GetTypeFromCode (reader.ReadByte());
928                                         return Type.GetType(elementType.FullName + "[]");
929
930                                 default:
931                                         throw new NotSupportedException ("Unknow type tag");
932                         }
933                 }
934                 
935                 public static object ReadPrimitiveTypeValue (BinaryReader reader, Type type)
936                 {
937                         if (type == null) return null;
938
939                         switch (Type.GetTypeCode (type))
940                         {
941                                 case TypeCode.Boolean:
942                                         return reader.ReadBoolean();
943
944                                 case TypeCode.Byte:
945                                         return reader.ReadByte();
946
947                                 case TypeCode.Char:
948                                         return reader.ReadChar();
949
950                                 case TypeCode.DateTime: 
951                                         return DateTime.FromBinary (reader.ReadInt64());
952
953                                 case TypeCode.Decimal:
954                                         return Decimal.Parse (reader.ReadString(), CultureInfo.InvariantCulture);
955
956                                 case TypeCode.Double:
957                                         return reader.ReadDouble();
958
959                                 case TypeCode.Int16:
960                                         return reader.ReadInt16();
961
962                                 case TypeCode.Int32:
963                                         return reader.ReadInt32();
964
965                                 case TypeCode.Int64:
966                                         return reader.ReadInt64();
967
968                                 case TypeCode.SByte:
969                                         return reader.ReadSByte();
970
971                                 case TypeCode.Single:
972                                         return reader.ReadSingle();
973
974                                 case TypeCode.UInt16:
975                                         return reader.ReadUInt16();
976
977                                 case TypeCode.UInt32:
978                                         return reader.ReadUInt32();
979
980                                 case TypeCode.UInt64:
981                                         return reader.ReadUInt64();
982
983                                 case TypeCode.String:
984                                         return reader.ReadString();
985
986                                 default:
987                                         if (type == typeof(TimeSpan))
988                                                 return new TimeSpan (reader.ReadInt64 ());
989                                         else
990                                                 throw new NotSupportedException ("Unsupported primitive type: " + type.FullName);
991                         }
992                 }
993         }
994 }