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