Merge pull request #347 from JamesB7/master
[mono.git] / mcs / class / corlib / System.Runtime.Serialization.Formatters.Binary / ObjectReader.cs
index 12820b896c164fc0278c43f45566c7929afdee3a..e3962a3b7157a19bab06b7a1a89c3ddf9315fd61 100644 (file)
-// ObjectReader.cs\r
-//\r
-// Author:\r
-//   Lluis Sanchez Gual (lluis@ideary.com)\r
-//   Patrik Torstensson\r
-//\r
-// (C) 2003 Lluis Sanchez Gual\r
-\r
-//\r
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)\r
-//\r
-// Permission is hereby granted, free of charge, to any person obtaining\r
-// a copy of this software and associated documentation files (the\r
-// "Software"), to deal in the Software without restriction, including\r
-// without limitation the rights to use, copy, modify, merge, publish,\r
-// distribute, sublicense, and/or sell copies of the Software, and to\r
-// permit persons to whom the Software is furnished to do so, subject to\r
-// the following conditions:\r
-// \r
-// The above copyright notice and this permission notice shall be\r
-// included in all copies or substantial portions of the Software.\r
-// \r
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
-//\r
-\r
-using System;\r
-using System.Runtime.Serialization;\r
-using System.IO;\r
-using System.Collections;\r
-using System.Reflection;\r
-using System.Runtime.Remoting.Messaging;\r
-using System.Globalization;\r
-\r
-namespace System.Runtime.Serialization.Formatters.Binary\r
-{\r
-       internal class ObjectReader\r
-       {\r
-               BinaryFormatter _formatter;\r
-               ISurrogateSelector _surrogateSelector;\r
-               StreamingContext _context;\r
-               SerializationBinder _binder;\r
-               \r
-#if NET_1_1\r
-               TypeFilterLevel _filterLevel;\r
-#endif\r
-\r
-               ObjectManager _manager;\r
-               Hashtable _registeredAssemblies = new Hashtable();\r
-               Hashtable _typeMetadataCache = new Hashtable();\r
-\r
-               object _lastObject = null;\r
-               long _lastObjectID = 0;\r
-               long _rootObjectID = 0;\r
-               byte[] arrayBuffer;\r
-               int ArrayBufferLength = 4096;\r
-\r
-               class TypeMetadata\r
-               {\r
-                       public Type Type;\r
-                       public Type[] MemberTypes;\r
-                       public string[] MemberNames;\r
-                       public MemberInfo[] MemberInfos;\r
-                       public int FieldCount;\r
-                       public bool NeedsSerializationInfo;\r
-               }\r
-\r
-               class ArrayNullFiller\r
-               {\r
-                       public ArrayNullFiller(int count) { NullCount = count; }\r
-                       public int NullCount;\r
-               }\r
-\r
-               public ObjectReader (BinaryFormatter formatter)\r
-               {\r
-                       _formatter = formatter;\r
-                       _surrogateSelector = formatter.SurrogateSelector;\r
-                       _context = formatter.Context;\r
-                       _binder = formatter.Binder;\r
-                       _manager = new ObjectManager (_surrogateSelector, _context);\r
-                       \r
-#if NET_1_1\r
-                       _filterLevel = formatter.FilterLevel;\r
-#endif\r
-               }\r
-\r
-               public void ReadObjectGraph (BinaryReader reader, bool readHeaders, out object result, out Header[] headers)\r
-               {\r
-                       headers = null;\r
-\r
-                       // Reads the objects. The first object in the stream is the\r
-                       // root object.\r
-\r
-                       while (ReadNextObject (reader))\r
-                       {\r
-                               if (readHeaders && (headers == null))\r
-                                       headers = (Header[])CurrentObject;\r
-                               else\r
-                                       if (_rootObjectID == 0) _rootObjectID = _lastObjectID;\r
-                       }\r
-\r
-                       result = _manager.GetObject (_rootObjectID);\r
-               }\r
-\r
-               public bool ReadNextObject (BinaryReader reader)\r
-               {\r
-                       BinaryElement element = (BinaryElement)reader.ReadByte ();\r
-                       if (element == BinaryElement.End)\r
-                       {\r
-                               _manager.DoFixups();\r
-\r
-                               _manager.RaiseDeserializationEvent();\r
-                               return false;\r
-                       }\r
-\r
-                       SerializationInfo info;\r
-                       long objectId;\r
-\r
-                       ReadObject (element, reader, out objectId, out _lastObject, out info);\r
-\r
-                       if (objectId != 0) {\r
-                               RegisterObject (objectId, _lastObject, info, 0, null, null);\r
-                               _lastObjectID = objectId;               \r
-                       }\r
-       \r
-                       return true;\r
-               }\r
-\r
-               public object CurrentObject\r
-               {\r
-                       get { return _lastObject; }\r
-               }\r
-\r
-               // Reads an object from the stream. The object is registered in the ObjectManager.\r
-               // The result can be either the object instance\r
-               // or the id of the object (when what is found in the stream is an object reference).\r
-               // If an object instance is read, the objectId is set to 0.\r
-               \r
-               private void ReadObject (BinaryElement element, BinaryReader reader, out long objectId, out object value, out SerializationInfo info)\r
-               {\r
-                       switch (element)\r
-                       {\r
-                               case BinaryElement.RefTypeObject:\r
-                                       ReadRefTypeObjectInstance (reader, out objectId, out value, out info);\r
-                                       break;\r
-\r
-                               case BinaryElement.UntypedRuntimeObject:\r
-                                       ReadObjectInstance (reader, true, false, out objectId, out value, out info);\r
-                                       break;\r
-\r
-                               case BinaryElement.UntypedExternalObject:\r
-                                       ReadObjectInstance (reader, false, false, out objectId, out value, out info);\r
-                                       break;\r
-\r
-                               case BinaryElement.RuntimeObject:\r
-                                       ReadObjectInstance (reader, true, true, out objectId, out value, out info);\r
-                                       break;\r
-\r
-                               case BinaryElement.ExternalObject:\r
-                                       ReadObjectInstance (reader, false, true, out objectId, out value, out info);\r
-                                       break;\r
-\r
-                               case BinaryElement.String:\r
-                                       info = null;\r
-                                       ReadStringIntance (reader, out objectId, out value);\r
-                                       break;\r
-\r
-                               case BinaryElement.GenericArray:\r
-                                       info = null;\r
-                                       ReadGenericArray (reader, out objectId, out value);\r
-                                       break;\r
-\r
-\r
-                               case BinaryElement.BoxedPrimitiveTypeValue:\r
-                                       value = ReadBoxedPrimitiveTypeValue (reader);\r
-                                       objectId = 0;\r
-                                       info = null;\r
-                                       break;\r
-\r
-                               case BinaryElement.NullValue:\r
-                                       value = null;\r
-                                       objectId = 0;\r
-                                       info = null;\r
-                                       break;\r
-\r
-                               case BinaryElement.Assembly:\r
-                                       ReadAssembly (reader);\r
-                                       ReadObject ((BinaryElement)reader.ReadByte (), reader, out objectId, out value, out info);\r
-                                       break;\r
-\r
-                               case BinaryElement.ArrayFiller8b:\r
-                                       value = new ArrayNullFiller(reader.ReadByte());\r
-                                       objectId = 0;\r
-                                       info = null;\r
-                                       break;\r
-\r
-                               case BinaryElement.ArrayFiller32b:\r
-                                       value = new ArrayNullFiller(reader.ReadInt32());\r
-                                       objectId = 0;\r
-                                       info = null;\r
-                                       break;\r
-\r
-                               case BinaryElement.ArrayOfPrimitiveType:\r
-                                       ReadArrayOfPrimitiveType (reader, out objectId, out value);\r
-                                       info = null;\r
-                                       break;\r
-\r
-                               case BinaryElement.ArrayOfObject:\r
-                                       ReadArrayOfObject (reader, out objectId, out value);\r
-                                       info = null;\r
-                                       break;\r
-\r
-                               case BinaryElement.ArrayOfString:\r
-                                       ReadArrayOfString (reader, out objectId, out value);\r
-                                       info = null;\r
-                                       break;\r
-\r
-                               default:\r
-                                       throw new SerializationException ("Unexpected binary element: " + (int)element);\r
-                       }\r
-               }\r
-\r
-               private void ReadAssembly (BinaryReader reader)\r
-               {\r
-                       long id = (long) reader.ReadUInt32 ();\r
-                       string assemblyName = reader.ReadString ();\r
-                       _registeredAssemblies [id] = assemblyName;\r
-               }\r
-\r
-               private void ReadObjectInstance (BinaryReader reader, bool isRuntimeObject, bool hasTypeInfo, out long objectId, out object value, out SerializationInfo info)\r
-               {\r
-                       objectId = (long) reader.ReadUInt32 ();\r
-\r
-                       TypeMetadata metadata = ReadTypeMetadata (reader, isRuntimeObject, hasTypeInfo);\r
-                       ReadObjectContent (reader, metadata, objectId, out value, out info);\r
-               }\r
-\r
-               private void ReadRefTypeObjectInstance (BinaryReader reader, out long objectId, out object value, out SerializationInfo info)\r
-               {\r
-                       objectId = (long) reader.ReadUInt32 ();\r
-                       long refTypeObjectId = (long) reader.ReadUInt32 ();\r
-\r
-                       // Gets the type of the referred object and its metadata\r
-\r
-                       object refObj = _manager.GetObject (refTypeObjectId);\r
-                       if (refObj == null) throw new SerializationException ("Invalid binary format");\r
-                       TypeMetadata metadata = (TypeMetadata)_typeMetadataCache [refObj.GetType()];\r
-\r
-                       ReadObjectContent (reader, metadata, objectId, out value, out info);\r
-               }\r
-\r
-               private void ReadObjectContent (BinaryReader reader, TypeMetadata metadata, long objectId, out object objectInstance, out SerializationInfo info)\r
-               {\r
-#if NET_1_1\r
-                       if (_filterLevel == TypeFilterLevel.Low)\r
-                               objectInstance = FormatterServices.GetSafeUninitializedObject (metadata.Type);\r
-                       else\r
-#endif\r
-                               objectInstance = FormatterServices.GetUninitializedObject (metadata.Type);\r
-#if NET_2_0
+// ObjectReader.cs
+//
+// Author:
+//   Lluis Sanchez Gual (lluis@ideary.com)
+//   Patrik Torstensson
+//
+// (C) 2003 Lluis Sanchez Gual
+
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Runtime.Serialization;
+using System.IO;
+using System.Collections;
+using System.Reflection;
+using System.Runtime.Remoting.Messaging;
+using System.Globalization;
+
+namespace System.Runtime.Serialization.Formatters.Binary
+{
+       internal class ObjectReader
+       {
+//             BinaryFormatter _formatter;
+               ISurrogateSelector _surrogateSelector;
+               StreamingContext _context;
+               SerializationBinder _binder;
+               
+               TypeFilterLevel _filterLevel;
+
+               ObjectManager _manager;
+               Hashtable _registeredAssemblies = new Hashtable();
+               Hashtable _typeMetadataCache = new Hashtable();
+
+               object _lastObject = null;
+               long _lastObjectID = 0;
+               long _rootObjectID = 0;
+               byte[] arrayBuffer;
+               int ArrayBufferLength = 4096;
+
+               class TypeMetadata
+               {
+                       public Type Type;
+                       public Type[] MemberTypes;
+                       public string[] MemberNames;
+                       public MemberInfo[] MemberInfos;
+                       public int FieldCount;
+                       public bool NeedsSerializationInfo;
+               }
+
+               class ArrayNullFiller
+               {
+                       public ArrayNullFiller(int count) { NullCount = count; }
+                       public int NullCount;
+               }
+
+               public ObjectReader (BinaryFormatter formatter)
+               {
+//                     _formatter = formatter;
+                       _surrogateSelector = formatter.SurrogateSelector;
+                       _context = formatter.Context;
+                       _binder = formatter.Binder;
+                       _manager = new ObjectManager (_surrogateSelector, _context);
+                       
+                       _filterLevel = formatter.FilterLevel;
+               }
+
+               public void ReadObjectGraph (BinaryReader reader, bool readHeaders, out object result, out Header[] headers)
+               {
+                       BinaryElement elem = (BinaryElement)reader.ReadByte ();
+                       ReadObjectGraph (elem, reader, readHeaders, out result, out headers);
+               }
+
+               public void ReadObjectGraph (BinaryElement elem, BinaryReader reader, bool readHeaders, out object result, out Header[] headers)
+               {
+                       headers = null;
+
+                       // Reads the objects. The first object in the stream is the
+                       // root object.
+                       bool next = ReadNextObject (elem, reader);
+                       if (next) {
+                               do {
+                                       if (readHeaders && (headers == null))
+                                               headers = (Header[])CurrentObject;
+                                       else
+                                               if (_rootObjectID == 0) _rootObjectID = _lastObjectID;
+                               } while (ReadNextObject (reader));
+                       }
+
+                       result = _manager.GetObject (_rootObjectID);
+               }
+
+               bool ReadNextObject (BinaryElement element, BinaryReader reader)
+               {
+                       if (element == BinaryElement.End)
+                       {
+                               _manager.DoFixups();
+
+                               _manager.RaiseDeserializationEvent();
+                               return false;
+                       }
+
+                       SerializationInfo info;
+                       long objectId;
+
+                       ReadObject (element, reader, out objectId, out _lastObject, out info);
+
+                       if (objectId != 0) {
+                               RegisterObject (objectId, _lastObject, info, 0, null, null);
+                               _lastObjectID = objectId;               
+                       }
+       
+                       return true;
+               }
+
+               public bool ReadNextObject (BinaryReader reader)
+               {
+                       BinaryElement element = (BinaryElement)reader.ReadByte ();
+                       if (element == BinaryElement.End)
+                       {
+                               _manager.DoFixups();
+
+                               _manager.RaiseDeserializationEvent();
+                               return false;
+                       }
+
+                       SerializationInfo info;
+                       long objectId;
+
+                       ReadObject (element, reader, out objectId, out _lastObject, out info);
+
+                       if (objectId != 0) {
+                               RegisterObject (objectId, _lastObject, info, 0, null, null);
+                               _lastObjectID = objectId;               
+                       }
+       
+                       return true;
+               }
+
+               public object CurrentObject
+               {
+                       get { return _lastObject; }
+               }
+
+               // Reads an object from the stream. The object is registered in the ObjectManager.
+               // The result can be either the object instance
+               // or the id of the object (when what is found in the stream is an object reference).
+               // If an object instance is read, the objectId is set to 0.
+               
+               private void ReadObject (BinaryElement element, BinaryReader reader, out long objectId, out object value, out SerializationInfo info)
+               {
+                       switch (element)
+                       {
+                               case BinaryElement.RefTypeObject:
+                                       ReadRefTypeObjectInstance (reader, out objectId, out value, out info);
+                                       break;
+
+                               case BinaryElement.UntypedRuntimeObject:
+                                       ReadObjectInstance (reader, true, false, out objectId, out value, out info);
+                                       break;
+
+                               case BinaryElement.UntypedExternalObject:
+                                       ReadObjectInstance (reader, false, false, out objectId, out value, out info);
+                                       break;
+
+                               case BinaryElement.RuntimeObject:
+                                       ReadObjectInstance (reader, true, true, out objectId, out value, out info);
+                                       break;
+
+                               case BinaryElement.ExternalObject:
+                                       ReadObjectInstance (reader, false, true, out objectId, out value, out info);
+                                       break;
+
+                               case BinaryElement.String:
+                                       info = null;
+                                       ReadStringIntance (reader, out objectId, out value);
+                                       break;
+
+                               case BinaryElement.GenericArray:
+                                       info = null;
+                                       ReadGenericArray (reader, out objectId, out value);
+                                       break;
+
+
+                               case BinaryElement.BoxedPrimitiveTypeValue:
+                                       value = ReadBoxedPrimitiveTypeValue (reader);
+                                       objectId = 0;
+                                       info = null;
+                                       break;
+
+                               case BinaryElement.NullValue:
+                                       value = null;
+                                       objectId = 0;
+                                       info = null;
+                                       break;
+
+                               case BinaryElement.Assembly:
+                                       ReadAssembly (reader);
+                                       ReadObject ((BinaryElement)reader.ReadByte (), reader, out objectId, out value, out info);
+                                       break;
+
+                               case BinaryElement.ArrayFiller8b:
+                                       value = new ArrayNullFiller(reader.ReadByte());
+                                       objectId = 0;
+                                       info = null;
+                                       break;
+
+                               case BinaryElement.ArrayFiller32b:
+                                       value = new ArrayNullFiller(reader.ReadInt32());
+                                       objectId = 0;
+                                       info = null;
+                                       break;
+
+                               case BinaryElement.ArrayOfPrimitiveType:
+                                       ReadArrayOfPrimitiveType (reader, out objectId, out value);
+                                       info = null;
+                                       break;
+
+                               case BinaryElement.ArrayOfObject:
+                                       ReadArrayOfObject (reader, out objectId, out value);
+                                       info = null;
+                                       break;
+
+                               case BinaryElement.ArrayOfString:
+                                       ReadArrayOfString (reader, out objectId, out value);
+                                       info = null;
+                                       break;
+
+                               default:
+                                       throw new SerializationException ("Unexpected binary element: " + (int)element);
+                       }
+               }
+
+               private void ReadAssembly (BinaryReader reader)
+               {
+                       long id = (long) reader.ReadUInt32 ();
+                       string assemblyName = reader.ReadString ();
+                       _registeredAssemblies [id] = assemblyName;
+               }
+
+               private void ReadObjectInstance (BinaryReader reader, bool isRuntimeObject, bool hasTypeInfo, out long objectId, out object value, out SerializationInfo info)
+               {
+                       objectId = (long) reader.ReadUInt32 ();
+
+                       TypeMetadata metadata = ReadTypeMetadata (reader, isRuntimeObject, hasTypeInfo);
+                       ReadObjectContent (reader, metadata, objectId, out value, out info);
+               }
+
+               private void ReadRefTypeObjectInstance (BinaryReader reader, out long objectId, out object value, out SerializationInfo info)
+               {
+                       objectId = (long) reader.ReadUInt32 ();
+                       long refTypeObjectId = (long) reader.ReadUInt32 ();
+
+                       // Gets the type of the referred object and its metadata
+
+                       object refObj = _manager.GetObject (refTypeObjectId);
+                       if (refObj == null) throw new SerializationException ("Invalid binary format");
+                       TypeMetadata metadata = (TypeMetadata)_typeMetadataCache [refObj.GetType()];
+
+                       ReadObjectContent (reader, metadata, objectId, out value, out info);
+               }
+
+               private void ReadObjectContent (BinaryReader reader, TypeMetadata metadata, long objectId, out object objectInstance, out SerializationInfo info)
+               {
+                       if (_filterLevel == TypeFilterLevel.Low)
+                               objectInstance = FormatterServices.GetSafeUninitializedObject (metadata.Type);
+                       else
+                               objectInstance = FormatterServices.GetUninitializedObject (metadata.Type);
                        _manager.RaiseOnDeserializingEvent (objectInstance);
-#endif
-                               \r
-                       info = metadata.NeedsSerializationInfo ? new SerializationInfo(metadata.Type, new FormatterConverter()) : null;\r
-\r
-                       if (metadata.MemberNames != null)\r
-                               for (int n=0; n<metadata.FieldCount; n++)\r
-                                       ReadValue (reader, objectInstance, objectId, info, metadata.MemberTypes[n], metadata.MemberNames[n], null, null);\r
-                       else\r
-                               for (int n=0; n<metadata.FieldCount; n++)\r
-                                       ReadValue (reader, objectInstance, objectId, info, metadata.MemberTypes[n], metadata.MemberInfos[n].Name, metadata.MemberInfos[n], null);\r
-               }\r
-\r
-               private void RegisterObject (long objectId, object objectInstance, SerializationInfo info, long parentObjectId, MemberInfo parentObjectMemeber, int[] indices)\r
-               {\r
-                       if (parentObjectId == 0) indices = null;\r
-\r
-                       if (!objectInstance.GetType().IsValueType || parentObjectId == 0)\r
-                               _manager.RegisterObject (objectInstance, objectId, info, 0, null, null);\r
-                       else\r
-                       {\r
-                               if (indices != null) indices = (int[])indices.Clone();\r
-                               _manager.RegisterObject (objectInstance, objectId, info, parentObjectId, parentObjectMemeber, indices);\r
-                       }\r
-               }\r
-\r
-               private void ReadStringIntance (BinaryReader reader, out long objectId, out object value)\r
-               {\r
-                       objectId = (long) reader.ReadUInt32 ();\r
-                       value = reader.ReadString ();\r
-               }\r
-\r
-               private void ReadGenericArray (BinaryReader reader, out long objectId, out object val)\r
-               {\r
-                       objectId = (long) reader.ReadUInt32 ();\r
-                       // Array structure\r
-                       reader.ReadByte();\r
-\r
-                       int rank = reader.ReadInt32();\r
-\r
-                       bool emptyDim = false;\r
-                       int[] lengths = new int[rank];\r
-                       for (int n=0; n<rank; n++)\r
-                       {\r
-                               lengths[n] = reader.ReadInt32();\r
-                               if (lengths[n] == 0) emptyDim = true;\r
-                       }\r
-\r
-                       TypeTag code = (TypeTag) reader.ReadByte ();\r
-                       Type elementType = ReadType (reader, code);\r
-\r
-                       Array array = Array.CreateInstance (elementType, lengths);\r
-\r
-                       if (emptyDim) \r
-                       { \r
-                               val = array;\r
-                               return;\r
-                       }\r
-\r
-                       int[] indices = new int[rank];\r
-\r
-                       // Initialize indexes\r
-                       for (int dim = rank-1; dim >= 0; dim--)\r
-                               indices[dim] = array.GetLowerBound (dim);\r
-\r
-                       bool end = false;\r
-                       while (!end)\r
-                       {\r
-                               ReadValue (reader, array, objectId, null, elementType, null, null, indices);\r
-\r
-                               for (int dim = array.Rank-1; dim >= 0; dim--)\r
-                               {\r
-                                       indices[dim]++;\r
-                                       if (indices[dim] > array.GetUpperBound (dim))\r
-                                       {\r
-                                               if (dim > 0) \r
-                                               {\r
-                                                       indices[dim] = array.GetLowerBound (dim);\r
-                                                       continue;       // Increment the next dimension's index\r
-                                               }\r
-                                               end = true;     // That was the last dimension. Finished.\r
-                                       }\r
-                                       break;\r
-                               }\r
-                       }\r
-                       val = array;\r
-               }\r
-\r
-               private object ReadBoxedPrimitiveTypeValue (BinaryReader reader)\r
-               {\r
-                       Type type = ReadType (reader, TypeTag.PrimitiveType);\r
-                       return ReadPrimitiveTypeValue (reader, type);\r
-               }\r
-\r
-               private void ReadArrayOfPrimitiveType (BinaryReader reader, out long objectId, out object val)\r
-               {\r
-                       objectId = (long) reader.ReadUInt32 ();\r
-                       int length = reader.ReadInt32 ();\r
-                       Type elementType = ReadType (reader, TypeTag.PrimitiveType);\r
-\r
-                       switch (Type.GetTypeCode (elementType))\r
-                       {\r
-                               case TypeCode.Boolean: {\r
-                                       bool[] arr = new bool [length];\r
-                                       for (int n = 0; n < length; n++) arr [n] = reader.ReadBoolean();\r
-                                       val = arr;\r
-                                       break;\r
-                               }\r
-\r
-                               case TypeCode.Byte: {\r
-                                       byte[] arr = new byte [length];\r
-                                       int pos = 0;\r
-                                       while (pos < length) {\r
-                                               int nr = reader.Read (arr, pos, length - pos);\r
-                                               if (nr == 0) break;\r
-                                               pos += nr;\r
-                                       }\r
-                                       val = arr;\r
-                                       break;\r
-                               }\r
-\r
-                               case TypeCode.Char: {\r
-                                       char[] arr = new char [length];\r
-                                       int pos = 0;\r
-                                       while (pos < length) {\r
-                                               int nr = reader.Read (arr, pos, length - pos);\r
-                                               if (nr == 0) break;\r
-                                               pos += nr;\r
-                                       }\r
-                                       val = arr;\r
-                                       break;\r
-                               }\r
-\r
-                               case TypeCode.DateTime: {\r
-                                       DateTime[] arr = new DateTime [length];\r
-                                       for (int n = 0; n < length; n++) {\r
-                                               ulong nr = reader.ReadUInt64 ();\r
-                                               const ulong mask = (1ul << 62) - 1;\r
-                                               long ticks = (long) (nr & mask);\r
-#if NET_2_0\r
-                                               DateTimeKind kind = (DateTimeKind) (nr >> 62);\r
-                                               arr [n] = new DateTime (ticks, kind);\r
-#else\r
-                                               arr [n] = new DateTime (ticks);\r
-#endif\r
-                                       }\r
-                                       val = arr;\r
-                                       break;\r
-                               }\r
-\r
-                               case TypeCode.Decimal: {\r
-                                       Decimal[] arr = new Decimal [length];\r
-                                       for (int n = 0; n < length; n++) arr [n] = reader.ReadDecimal();\r
-                                       val = arr;\r
-                                       break;\r
-                               }\r
-\r
-                               case TypeCode.Double: {\r
-                                       Double[] arr = new Double [length];\r
-                                       if (length > 2)\r
-                                               BlockRead (reader, arr, 8);\r
-                                       else\r
-                                               for (int n = 0; n < length; n++) arr [n] = reader.ReadDouble();\r
-                                       val = arr;\r
-                                       break;\r
-                               }\r
-\r
-                               case TypeCode.Int16: {\r
-                                       short[] arr = new short [length];\r
-                                       if (length > 2)\r
-                                               BlockRead (reader, arr, 2);\r
-                                       else\r
-                                               for (int n = 0; n < length; n++) arr [n] = reader.ReadInt16();\r
-                                       val = arr;\r
-                                       break;\r
-                               }\r
-\r
-                               case TypeCode.Int32: {\r
-                                       int[] arr = new int [length];\r
-                                       if (length > 2)\r
-                                               BlockRead (reader, arr, 4);\r
-                                       else\r
-                                               for (int n = 0; n < length; n++) arr [n] = reader.ReadInt32();\r
-                                       val = arr;\r
-                                       break;\r
-                               }\r
-\r
-                               case TypeCode.Int64: {\r
-                                       long[] arr = new long [length];\r
-                                       if (length > 2)\r
-                                               BlockRead (reader, arr, 8);\r
-                                       else\r
-                                               for (int n = 0; n < length; n++) arr [n] = reader.ReadInt64();\r
-                                       val = arr;\r
-                                       break;\r
-                               }\r
-\r
-                               case TypeCode.SByte: {\r
-                                       sbyte[] arr = new sbyte [length];\r
-                                       if (length > 2)\r
-                                               BlockRead (reader, arr, 1);\r
-                                       else\r
-                                               for (int n = 0; n < length; n++) arr [n] = reader.ReadSByte();\r
-                                       val = arr;\r
-                                       break;\r
-                               }\r
-\r
-                               case TypeCode.Single: {\r
-                                       float[] arr = new float [length];\r
-                                       if (length > 2)\r
-                                               BlockRead (reader, arr, 4);\r
-                                       else\r
-                                               for (int n = 0; n < length; n++) arr [n] = reader.ReadSingle();\r
-                                       val = arr;\r
-                                       break;\r
-                               }\r
-\r
-                               case TypeCode.UInt16: {\r
-                                       ushort[] arr = new ushort [length];\r
-                                       if (length > 2)\r
-                                               BlockRead (reader, arr, 2);\r
-                                       else\r
-                                               for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt16();\r
-                                       val = arr;\r
-                                       break;\r
-                               }\r
-\r
-                               case TypeCode.UInt32: {\r
-                                       uint[] arr = new uint [length];\r
-                                       if (length > 2)\r
-                                               BlockRead (reader, arr, 4);\r
-                                       else\r
-                                               for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt32();\r
-                                       val = arr;\r
-                                       break;\r
-                               }\r
-\r
-                               case TypeCode.UInt64: {\r
-                                       ulong[] arr = new ulong [length];\r
-                                       if (length > 2)\r
-                                               BlockRead (reader, arr, 8);\r
-                                       else\r
-                                               for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt64();\r
-                                       val = arr;\r
-                                       break;\r
-                               }\r
-\r
-                               case TypeCode.String: {\r
-                                       string[] arr = new string [length];\r
-                                       for (int n = 0; n < length; n++) arr [n] = reader.ReadString();\r
-                                       val = arr;\r
-                                       break;\r
-                               }\r
-\r
-                               default: {\r
-                                       if (elementType == typeof(TimeSpan)) {\r
-                                               TimeSpan[] arr = new TimeSpan [length];\r
-                                               for (int n = 0; n < length; n++) arr [n] = new TimeSpan (reader.ReadInt64 ());\r
-                                               val = arr;\r
-                                       }\r
-                                       else\r
-                                               throw new NotSupportedException ("Unsupported primitive type: " + elementType.FullName);\r
-                                       break;\r
-                               }\r
-                       }                       \r
-               }\r
-\r
-               private void BlockRead (BinaryReader reader, Array array, int dataSize)\r
-               {\r
-                       int totalSize = Buffer.ByteLength (array);\r
-                       \r
-                       if (arrayBuffer == null || (totalSize > arrayBuffer.Length && arrayBuffer.Length != ArrayBufferLength))\r
-                               arrayBuffer = new byte [totalSize <= ArrayBufferLength ? totalSize : ArrayBufferLength];\r
-                       \r
-                       int pos = 0;\r
-                       while (totalSize > 0) {\r
-                               int size = totalSize < arrayBuffer.Length ? totalSize : arrayBuffer.Length;\r
-                               int ap = 0;\r
-                               do {\r
-                                       int nr = reader.Read (arrayBuffer, ap, size - ap);\r
-                                       if (nr == 0) break;\r
-                                       ap += nr;\r
-                               } while (ap < size);\r
-                               \r
-                               if (!BitConverter.IsLittleEndian && dataSize > 1)\r
-                                       BinaryCommon.SwapBytes (arrayBuffer, size, dataSize);\r
-\r
-                               Buffer.BlockCopy (arrayBuffer, 0, array, pos, size);\r
-                               totalSize -= size;\r
-                               pos += size;\r
-                       }\r
-               }\r
-               \r
-\r
-               private void ReadArrayOfObject (BinaryReader reader, out long objectId, out object array)\r
-               {\r
-                       ReadSimpleArray (reader, typeof (object), out objectId, out array);\r
-               }\r
-               \r
-               private void ReadArrayOfString (BinaryReader reader, out long objectId, out object array)\r
-               {\r
-                       ReadSimpleArray (reader, typeof (string), out objectId, out array);\r
-               }\r
-\r
-               private void ReadSimpleArray (BinaryReader reader, Type elementType, out long objectId, out object val)\r
-               {\r
-                       objectId = (long) reader.ReadUInt32 ();\r
-                       int length = reader.ReadInt32 ();\r
-                       int[] indices = new int[1];\r
-\r
-                       Array array = Array.CreateInstance (elementType, length);\r
-                       for (int n = 0; n < length; n++)\r
-                       {\r
-                               indices[0] = n;\r
-                               ReadValue (reader, array, objectId, null, elementType, null, null, indices);\r
-                               n = indices[0];\r
-                       }\r
-                       val = array;\r
-               }\r
-\r
-               private TypeMetadata ReadTypeMetadata (BinaryReader reader, bool isRuntimeObject, bool hasTypeInfo)\r
-               {\r
-                       TypeMetadata metadata = new TypeMetadata();\r
-\r
-                       string className = reader.ReadString ();\r
-                       int fieldCount = reader.ReadInt32 ();\r
-\r
-                       Type[] types = new Type[fieldCount];\r
-                       string[] names = new string[fieldCount];\r
-\r
-                       for (int n=0; n<fieldCount; n++)\r
-                               names [n] = reader.ReadString ();\r
-\r
-                       if (hasTypeInfo)\r
-                       {\r
-                               TypeTag[] codes = new TypeTag[fieldCount];\r
-\r
-                               for (int n=0; n<fieldCount; n++)\r
-                                       codes [n] = (TypeTag) reader.ReadByte ();\r
-       \r
-                               for (int n=0; n<fieldCount; n++)\r
-                                       types [n] = ReadType (reader, codes[n]);\r
-                       }\r
-                       \r
-                       // Gets the type\r
-\r
-                       if (!isRuntimeObject) \r
-                       {\r
-                               long assemblyId = (long)reader.ReadUInt32();\r
-                               metadata.Type = GetDeserializationType (assemblyId, className);\r
-                       }\r
-                       else\r
-                               metadata.Type = Type.GetType (className, true);\r
-\r
-                       metadata.MemberTypes = types;\r
-                       metadata.MemberNames = names;\r
-                       metadata.FieldCount = names.Length;\r
-\r
-                       // Now check if this objects needs a SerializationInfo struct for deserialziation.\r
-                       // SerializationInfo is needed if the object has to be deserialized using\r
-                       // a serialization surrogate, or if it implements ISerializable.\r
-\r
-                       if (_surrogateSelector != null)\r
-                       {\r
-                               // check if the surrogate selector handles objects of the given type. \r
-                               ISurrogateSelector selector;\r
-                               ISerializationSurrogate surrogate = _surrogateSelector.GetSurrogate (metadata.Type, _context, out selector);\r
-                               metadata.NeedsSerializationInfo = (surrogate != null);\r
-                       }\r
-\r
-                       if (!metadata.NeedsSerializationInfo)\r
-                       {\r
-                               // Check if the object is marked with the Serializable attribute\r
-\r
-                               if (!metadata.Type.IsSerializable)\r
-                                       throw new SerializationException("Serializable objects must be marked with the Serializable attribute");\r
-\r
-                               metadata.NeedsSerializationInfo = (metadata.Type.GetInterface ("ISerializable") != null);\r
-                               if (!metadata.NeedsSerializationInfo)\r
-                               {\r
-                                       metadata.MemberInfos = new MemberInfo [fieldCount];\r
-                                       for (int n=0; n<fieldCount; n++)\r
-                                       {\r
-                                               FieldInfo field = null;\r
-                                               string memberName = names[n];\r
-                                               \r
-                                               int i = memberName.IndexOf ('+');\r
-                                               if (i != -1) {\r
-                                                       string baseTypeName = names[n].Substring (0,i);\r
-                                                       memberName = names[n].Substring (i+1);\r
-                                                       Type t = metadata.Type.BaseType;\r
-                                                       while (t != null) {\r
-                                                               if (t.Name == baseTypeName) {\r
-                                                                       field = t.GetField (memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\r
-                                                                       break;\r
-                                                               }\r
-                                                               else\r
-                                                                       t = t.BaseType;\r
-                                                       }\r
-                                               }\r
-                                               else\r
-                                                       field = metadata.Type.GetField (memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\r
-                                                       \r
-                                               if (field == null) throw new SerializationException ("Field \"" + names[n] + "\" not found in class " + metadata.Type.FullName);\r
-                                               metadata.MemberInfos [n] = field;\r
-                                               \r
-                                               if (!hasTypeInfo) {\r
-                                                       types [n] = field.FieldType;\r
-                                               }\r
-                                       }\r
-                                       metadata.MemberNames = null;    // Info now in MemberInfos\r
-                               }\r
-                       }\r
-\r
-                       // Registers the type's metadata so it can be reused later if\r
-                       // a RefTypeObject element is found\r
-\r
-                       if (!_typeMetadataCache.ContainsKey (metadata.Type))\r
-                               _typeMetadataCache [metadata.Type] = metadata;\r
-\r
-                       return metadata;\r
-               }\r
-\r
-\r
-               private void ReadValue (BinaryReader reader, object parentObject, long parentObjectId, SerializationInfo info, Type valueType, string fieldName, MemberInfo memberInfo, int[] indices)\r
-               {\r
-                       // Reads a value from the stream and assigns it to the member of an object\r
-\r
-                       object val;\r
-\r
-                       if (BinaryCommon.IsPrimitive (valueType))\r
-                       {\r
-                               val = ReadPrimitiveTypeValue (reader, valueType);\r
-                               SetObjectValue (parentObject, fieldName, memberInfo, info, val, valueType, indices);\r
-                               return;\r
-                       }\r
-\r
-                       // Gets the object\r
-\r
-                       BinaryElement element = (BinaryElement)reader.ReadByte ();\r
-\r
-                       if (element == BinaryElement.ObjectReference)\r
-                       {\r
-                               // Just read the id of the referred object and record a fixup\r
-                               long childObjectId = (long) reader.ReadUInt32();\r
-                               RecordFixup (parentObjectId, childObjectId, parentObject, info, fieldName, memberInfo, indices);\r
-                               return;\r
-                       }\r
-\r
-                       long objectId;\r
-                       SerializationInfo objectInfo;\r
-\r
-                       ReadObject (element, reader, out objectId, out val, out objectInfo);\r
-\r
-                       // There are two cases where the object cannot be assigned to the parent\r
-                       // and a fixup must be used:\r
-                       //  1) When what has been read is not an object, but an id of an object that\r
-                       //     has not been read yet (an object reference). This is managed in the\r
-                       //     previous block of code.\r
-                       //  2) When the read object is a value type object. Value type fields hold\r
-                       //     copies of objects, not references. Thus, if the value object that\r
-                       //     has been read has pending fixups, those fixups would be made to the\r
-                       //     boxed copy in the ObjectManager, and not in the required object instance\r
-\r
-                       // First of all register the fixup, and then the object. ObjectManager is more\r
-                       // efficient if done in this order\r
-\r
-                       bool hasFixup = false;\r
-                       if (objectId != 0)\r
-                       {\r
-                               if (val.GetType().IsValueType)\r
-                               {\r
-                                       RecordFixup (parentObjectId, objectId, parentObject, info, fieldName, memberInfo, indices);\r
-                                       hasFixup = true;\r
-                               }\r
-\r
-                               // Register the value\r
-\r
-                               if (info == null && !(parentObject is Array))\r
-                                       RegisterObject (objectId, val, objectInfo, parentObjectId, memberInfo, null);\r
-                               else\r
-                                       RegisterObject (objectId, val, objectInfo, parentObjectId, null, indices);\r
-                       }\r
-                       // Assign the value to the parent object, unless there is a fixup\r
-                       \r
-                       if (!hasFixup) \r
-                               SetObjectValue (parentObject, fieldName, memberInfo, info, val, valueType, indices);\r
-               }\r
-\r
-               private void SetObjectValue (object parentObject, string fieldName, MemberInfo memberInfo, SerializationInfo info, object value, Type valueType, int[] indices)\r
-               {\r
-                       if (value is IObjectReference)\r
-                               value = ((IObjectReference)value).GetRealObject (_context);\r
-\r
-                       if (parentObject is Array) \r
-                       {\r
-                               if (value is ArrayNullFiller) \r
-                               {\r
-                                       // It must be a single dimension array of objects.\r
-                                       // Just increase the index. Elements are null by default.\r
-                                       int count = ((ArrayNullFiller)value).NullCount;\r
-                                       indices[0] += count - 1;\r
-                               }\r
-                               else\r
-                                       ((Array)parentObject).SetValue (value, indices);\r
-                       }\r
-                       else if (info != null) {\r
-                               info.AddValue (fieldName, value, valueType);\r
-                       }\r
-                       else {\r
-                               if (memberInfo is FieldInfo)\r
-                                       ((FieldInfo)memberInfo).SetValue (parentObject, value);\r
-                               else\r
-                                       ((PropertyInfo)memberInfo).SetValue (parentObject, value, null);\r
-                       }\r
-               }\r
-\r
-               private void RecordFixup (long parentObjectId, long childObjectId, object parentObject, SerializationInfo info, string fieldName, MemberInfo memberInfo, int[] indices)\r
-               {\r
-                       if (info != null) {\r
-                               _manager.RecordDelayedFixup (parentObjectId, fieldName, childObjectId);\r
-                       }\r
-                       else if (parentObject is Array) {\r
-                               if (indices.Length == 1)\r
-                                       _manager.RecordArrayElementFixup (parentObjectId, indices[0], childObjectId);\r
-                               else\r
-                                       _manager.RecordArrayElementFixup (parentObjectId, (int[])indices.Clone(), childObjectId);\r
-                       }\r
-                       else {\r
-                               _manager.RecordFixup (parentObjectId, memberInfo, childObjectId);\r
-                       }\r
-               }\r
-\r
-               private Type GetDeserializationType (long assemblyId, string className)\r
-               {\r
-                       Type t;\r
-                       string assemblyName = (string)_registeredAssemblies[assemblyId];\r
-\r
-                       if (_binder != null) {\r
-                               t = _binder.BindToType (assemblyName, className);\r
-                               if (t != null)\r
-                                       return t;\r
-                       }\r
-                               \r
-                       Assembly assembly = Assembly.Load (assemblyName);\r
-                       t = assembly.GetType (className, true);\r
-                       if (t != null)\r
-                               return t;\r
-                       throw new SerializationException ("Couldn't find type '" + className + "'.");\r
-               }\r
-\r
-               public Type ReadType (BinaryReader reader, TypeTag code)\r
-               {\r
-                       switch (code)\r
-                       {\r
-                               case TypeTag.PrimitiveType:\r
-                                       return BinaryCommon.GetTypeFromCode (reader.ReadByte());\r
-\r
-                               case TypeTag.String:\r
-                                       return typeof(string);\r
-\r
-                               case TypeTag.ObjectType:\r
-                                       return typeof(object);\r
-\r
-                               case TypeTag.RuntimeType:\r
-                               {\r
-                                       string name = reader.ReadString ();\r
-                                       return Type.GetType (name, true);\r
-                               }\r
-\r
-                               case TypeTag.GenericType:\r
-                               {\r
-                                       string name = reader.ReadString ();\r
-                                       long asmid = (long) reader.ReadUInt32();\r
-                                       return GetDeserializationType (asmid, name);\r
-                               }\r
-\r
-                               case TypeTag.ArrayOfObject:\r
-                                       return typeof(object[]);\r
-\r
-                               case TypeTag.ArrayOfString:\r
-                                       return typeof(string[]);\r
-\r
-                               case TypeTag.ArrayOfPrimitiveType:\r
-                                       Type elementType = BinaryCommon.GetTypeFromCode (reader.ReadByte());\r
-                                       return Type.GetType(elementType.FullName + "[]");\r
-\r
-                               default:\r
-                                       throw new NotSupportedException ("Unknow type tag");\r
-                       }\r
-               }\r
-               \r
-               public static object ReadPrimitiveTypeValue (BinaryReader reader, Type type)\r
-               {\r
-                       if (type == null) return null;\r
-\r
-                       switch (Type.GetTypeCode (type))\r
-                       {\r
-                               case TypeCode.Boolean:\r
-                                       return reader.ReadBoolean();\r
-\r
-                               case TypeCode.Byte:\r
-                                       return reader.ReadByte();\r
-\r
-                               case TypeCode.Char:\r
-                                       return reader.ReadChar();\r
-\r
-                               case TypeCode.DateTime: \r
-                                       return new DateTime (reader.ReadInt64());\r
-\r
-                               case TypeCode.Decimal:\r
-                                       return Decimal.Parse (reader.ReadString(), CultureInfo.InvariantCulture);\r
-\r
-                               case TypeCode.Double:\r
-                                       return reader.ReadDouble();\r
-\r
-                               case TypeCode.Int16:\r
-                                       return reader.ReadInt16();\r
-\r
-                               case TypeCode.Int32:\r
-                                       return reader.ReadInt32();\r
-\r
-                               case TypeCode.Int64:\r
-                                       return reader.ReadInt64();\r
-\r
-                               case TypeCode.SByte:\r
-                                       return reader.ReadSByte();\r
-\r
-                               case TypeCode.Single:\r
-                                       return reader.ReadSingle();\r
-\r
-                               case TypeCode.UInt16:\r
-                                       return reader.ReadUInt16();\r
-\r
-                               case TypeCode.UInt32:\r
-                                       return reader.ReadUInt32();\r
-\r
-                               case TypeCode.UInt64:\r
-                                       return reader.ReadUInt64();\r
-\r
-                               case TypeCode.String:\r
-                                       return reader.ReadString();\r
-\r
-                               default:\r
-                                       if (type == typeof(TimeSpan))\r
-                                               return new TimeSpan (reader.ReadInt64 ());\r
-                                       else\r
-                                               throw new NotSupportedException ("Unsupported primitive type: " + type.FullName);\r
-                       }\r
-               }\r
-       }\r
-}\r
+                               
+                       info = metadata.NeedsSerializationInfo ? new SerializationInfo(metadata.Type, new FormatterConverter()) : null;
+
+                       if (metadata.MemberNames != null) {
+                               for (int n=0; n<metadata.FieldCount; n++)
+                                       ReadValue (reader, objectInstance, objectId, info, metadata.MemberTypes[n], metadata.MemberNames[n], null, null);
+                       } else
+                               for (int n=0; n<metadata.FieldCount; n++) {
+                                       if (metadata.MemberInfos [n] != null)
+                                               ReadValue (reader, objectInstance, objectId, info, metadata.MemberTypes[n], metadata.MemberInfos[n].Name, metadata.MemberInfos[n], null);
+                                       else if (BinaryCommon.IsPrimitive(metadata.MemberTypes[n])) {
+                                               // Since the member info is null, the type in this
+                                               // domain does not have this type. Even though we
+                                               // are not going to store the value, we will read
+                                               // it from the stream so that we can advance to the
+                                               // next block.
+                                               ReadPrimitiveTypeValue (reader, metadata.MemberTypes[n]);
+                                       }
+                               }
+               }
+
+               private void RegisterObject (long objectId, object objectInstance, SerializationInfo info, long parentObjectId, MemberInfo parentObjectMemeber, int[] indices)
+               {
+                       if (parentObjectId == 0) indices = null;
+
+                       if (!objectInstance.GetType().IsValueType || parentObjectId == 0)
+                               _manager.RegisterObject (objectInstance, objectId, info, 0, null, null);
+                       else
+                       {
+                               if (indices != null) indices = (int[])indices.Clone();
+                               _manager.RegisterObject (objectInstance, objectId, info, parentObjectId, parentObjectMemeber, indices);
+                       }
+               }
+
+               private void ReadStringIntance (BinaryReader reader, out long objectId, out object value)
+               {
+                       objectId = (long) reader.ReadUInt32 ();
+                       value = reader.ReadString ();
+               }
+
+               private void ReadGenericArray (BinaryReader reader, out long objectId, out object val)
+               {
+                       objectId = (long) reader.ReadUInt32 ();
+                       // Array structure
+                       reader.ReadByte();
+
+                       int rank = reader.ReadInt32();
+
+                       bool emptyDim = false;
+                       int[] lengths = new int[rank];
+                       for (int n=0; n<rank; n++)
+                       {
+                               lengths[n] = reader.ReadInt32();
+                               if (lengths[n] == 0) emptyDim = true;
+                       }
+
+                       TypeTag code = (TypeTag) reader.ReadByte ();
+                       Type elementType = ReadType (reader, code);
+
+                       Array array = Array.CreateInstance (elementType, lengths);
+
+                       if (emptyDim) 
+                       { 
+                               val = array;
+                               return;
+                       }
+
+                       int[] indices = new int[rank];
+
+                       // Initialize indexes
+                       for (int dim = rank-1; dim >= 0; dim--)
+                               indices[dim] = array.GetLowerBound (dim);
+
+                       bool end = false;
+                       while (!end)
+                       {
+                               ReadValue (reader, array, objectId, null, elementType, null, null, indices);
+
+                               for (int dim = array.Rank-1; dim >= 0; dim--)
+                               {
+                                       indices[dim]++;
+                                       if (indices[dim] > array.GetUpperBound (dim))
+                                       {
+                                               if (dim > 0) 
+                                               {
+                                                       indices[dim] = array.GetLowerBound (dim);
+                                                       continue;       // Increment the next dimension's index
+                                               }
+                                               end = true;     // That was the last dimension. Finished.
+                                       }
+                                       break;
+                               }
+                       }
+                       val = array;
+               }
+
+               private object ReadBoxedPrimitiveTypeValue (BinaryReader reader)
+               {
+                       Type type = ReadType (reader, TypeTag.PrimitiveType);
+                       return ReadPrimitiveTypeValue (reader, type);
+               }
+
+               private void ReadArrayOfPrimitiveType (BinaryReader reader, out long objectId, out object val)
+               {
+                       objectId = (long) reader.ReadUInt32 ();
+                       int length = reader.ReadInt32 ();
+                       Type elementType = ReadType (reader, TypeTag.PrimitiveType);
+
+                       switch (Type.GetTypeCode (elementType))
+                       {
+                               case TypeCode.Boolean: {
+                                       bool[] arr = new bool [length];
+                                       for (int n = 0; n < length; n++) arr [n] = reader.ReadBoolean();
+                                       val = arr;
+                                       break;
+                               }
+
+                               case TypeCode.Byte: {
+                                       byte[] arr = new byte [length];
+                                       int pos = 0;
+                                       while (pos < length) {
+                                               int nr = reader.Read (arr, pos, length - pos);
+                                               if (nr == 0) break;
+                                               pos += nr;
+                                       }
+                                       val = arr;
+                                       break;
+                               }
+
+                               case TypeCode.Char: {
+                                       char[] arr = new char [length];
+                                       int pos = 0;
+                                       while (pos < length) {
+                                               int nr = reader.Read (arr, pos, length - pos);
+                                               if (nr == 0) break;
+                                               pos += nr;
+                                       }
+                                       val = arr;
+                                       break;
+                               }
+
+                               case TypeCode.DateTime: {
+                                       DateTime[] arr = new DateTime [length];
+                                       for (int n = 0; n < length; n++) {
+                                               arr [n] = DateTime.FromBinary (reader.ReadInt64 ());
+                                       }
+                                       val = arr;
+                                       break;
+                               }
+
+                               case TypeCode.Decimal: {
+                                       Decimal[] arr = new Decimal [length];
+                                       for (int n = 0; n < length; n++) arr [n] = reader.ReadDecimal();
+                                       val = arr;
+                                       break;
+                               }
+
+                               case TypeCode.Double: {
+                                       Double[] arr = new Double [length];
+                                       if (length > 2)
+                                               BlockRead (reader, arr, 8);
+                                       else
+                                               for (int n = 0; n < length; n++) arr [n] = reader.ReadDouble();
+                                       val = arr;
+                                       break;
+                               }
+
+                               case TypeCode.Int16: {
+                                       short[] arr = new short [length];
+                                       if (length > 2)
+                                               BlockRead (reader, arr, 2);
+                                       else
+                                               for (int n = 0; n < length; n++) arr [n] = reader.ReadInt16();
+                                       val = arr;
+                                       break;
+                               }
+
+                               case TypeCode.Int32: {
+                                       int[] arr = new int [length];
+                                       if (length > 2)
+                                               BlockRead (reader, arr, 4);
+                                       else
+                                               for (int n = 0; n < length; n++) arr [n] = reader.ReadInt32();
+                                       val = arr;
+                                       break;
+                               }
+
+                               case TypeCode.Int64: {
+                                       long[] arr = new long [length];
+                                       if (length > 2)
+                                               BlockRead (reader, arr, 8);
+                                       else
+                                               for (int n = 0; n < length; n++) arr [n] = reader.ReadInt64();
+                                       val = arr;
+                                       break;
+                               }
+
+                               case TypeCode.SByte: {
+                                       sbyte[] arr = new sbyte [length];
+                                       if (length > 2)
+                                               BlockRead (reader, arr, 1);
+                                       else
+                                               for (int n = 0; n < length; n++) arr [n] = reader.ReadSByte();
+                                       val = arr;
+                                       break;
+                               }
+
+                               case TypeCode.Single: {
+                                       float[] arr = new float [length];
+                                       if (length > 2)
+                                               BlockRead (reader, arr, 4);
+                                       else
+                                               for (int n = 0; n < length; n++) arr [n] = reader.ReadSingle();
+                                       val = arr;
+                                       break;
+                               }
+
+                               case TypeCode.UInt16: {
+                                       ushort[] arr = new ushort [length];
+                                       if (length > 2)
+                                               BlockRead (reader, arr, 2);
+                                       else
+                                               for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt16();
+                                       val = arr;
+                                       break;
+                               }
+
+                               case TypeCode.UInt32: {
+                                       uint[] arr = new uint [length];
+                                       if (length > 2)
+                                               BlockRead (reader, arr, 4);
+                                       else
+                                               for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt32();
+                                       val = arr;
+                                       break;
+                               }
+
+                               case TypeCode.UInt64: {
+                                       ulong[] arr = new ulong [length];
+                                       if (length > 2)
+                                               BlockRead (reader, arr, 8);
+                                       else
+                                               for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt64();
+                                       val = arr;
+                                       break;
+                               }
+
+                               case TypeCode.String: {
+                                       string[] arr = new string [length];
+                                       for (int n = 0; n < length; n++) arr [n] = reader.ReadString();
+                                       val = arr;
+                                       break;
+                               }
+
+                               default: {
+                                       if (elementType == typeof(TimeSpan)) {
+                                               TimeSpan[] arr = new TimeSpan [length];
+                                               for (int n = 0; n < length; n++) arr [n] = new TimeSpan (reader.ReadInt64 ());
+                                               val = arr;
+                                       }
+                                       else
+                                               throw new NotSupportedException ("Unsupported primitive type: " + elementType.FullName);
+                                       break;
+                               }
+                       }                       
+               }
+
+               private void BlockRead (BinaryReader reader, Array array, int dataSize)
+               {
+                       int totalSize = Buffer.ByteLength (array);
+                       
+                       if (arrayBuffer == null || (totalSize > arrayBuffer.Length && arrayBuffer.Length != ArrayBufferLength))
+                               arrayBuffer = new byte [totalSize <= ArrayBufferLength ? totalSize : ArrayBufferLength];
+                       
+                       int pos = 0;
+                       while (totalSize > 0) {
+                               int size = totalSize < arrayBuffer.Length ? totalSize : arrayBuffer.Length;
+                               int ap = 0;
+                               do {
+                                       int nr = reader.Read (arrayBuffer, ap, size - ap);
+                                       if (nr == 0) break;
+                                       ap += nr;
+                               } while (ap < size);
+                               
+                               if (!BitConverter.IsLittleEndian && dataSize > 1)
+                                       BinaryCommon.SwapBytes (arrayBuffer, size, dataSize);
+
+                               Buffer.BlockCopy (arrayBuffer, 0, array, pos, size);
+                               totalSize -= size;
+                               pos += size;
+                       }
+               }
+               
+
+               private void ReadArrayOfObject (BinaryReader reader, out long objectId, out object array)
+               {
+                       ReadSimpleArray (reader, typeof (object), out objectId, out array);
+               }
+               
+               private void ReadArrayOfString (BinaryReader reader, out long objectId, out object array)
+               {
+                       ReadSimpleArray (reader, typeof (string), out objectId, out array);
+               }
+
+               private void ReadSimpleArray (BinaryReader reader, Type elementType, out long objectId, out object val)
+               {
+                       objectId = (long) reader.ReadUInt32 ();
+                       int length = reader.ReadInt32 ();
+                       int[] indices = new int[1];
+
+                       Array array = Array.CreateInstance (elementType, length);
+                       for (int n = 0; n < length; n++)
+                       {
+                               indices[0] = n;
+                               ReadValue (reader, array, objectId, null, elementType, null, null, indices);
+                               n = indices[0];
+                       }
+                       val = array;
+               }
+
+               private TypeMetadata ReadTypeMetadata (BinaryReader reader, bool isRuntimeObject, bool hasTypeInfo)
+               {
+                       TypeMetadata metadata = new TypeMetadata();
+
+                       string className = reader.ReadString ();
+                       int fieldCount = reader.ReadInt32 ();
+
+                       Type[] types = new Type[fieldCount];
+                       string[] names = new string[fieldCount];
+
+                       for (int n=0; n<fieldCount; n++)
+                               names [n] = reader.ReadString ();
+
+                       if (hasTypeInfo)
+                       {
+                               TypeTag[] codes = new TypeTag[fieldCount];
+
+                               for (int n=0; n<fieldCount; n++)
+                                       codes [n] = (TypeTag) reader.ReadByte ();
+       
+                               for (int n=0; n<fieldCount; n++) {
+                                       Type t = ReadType (reader, codes[n], false);
+                                       // The field's type could not be resolved: assume it is an object.
+                                       if (t == null)
+                                               t = typeof (object);
+                                       types [n] = t;
+                               }
+                       }
+                       
+                       // Gets the type
+
+                       if (!isRuntimeObject) 
+                       {
+                               long assemblyId = (long)reader.ReadUInt32();
+                               metadata.Type = GetDeserializationType (assemblyId, className);
+                       }
+                       else
+                               metadata.Type = Type.GetType (className, true);
+
+                       metadata.MemberTypes = types;
+                       metadata.MemberNames = names;
+                       metadata.FieldCount = names.Length;
+
+                       // Now check if this objects needs a SerializationInfo struct for deserialziation.
+                       // SerializationInfo is needed if the object has to be deserialized using
+                       // a serialization surrogate, or if it implements ISerializable.
+
+                       if (_surrogateSelector != null)
+                       {
+                               // check if the surrogate selector handles objects of the given type. 
+                               ISurrogateSelector selector;
+                               ISerializationSurrogate surrogate = _surrogateSelector.GetSurrogate (metadata.Type, _context, out selector);
+                               metadata.NeedsSerializationInfo = (surrogate != null);
+                       }
+
+                       if (!metadata.NeedsSerializationInfo)
+                       {
+                               // Check if the object is marked with the Serializable attribute
+
+                               if (!metadata.Type.IsSerializable)
+                                       throw new SerializationException("Serializable objects must be marked with the Serializable attribute");
+
+                               metadata.NeedsSerializationInfo = typeof (ISerializable).IsAssignableFrom (metadata.Type);
+                               if (!metadata.NeedsSerializationInfo)
+                               {
+                                       metadata.MemberInfos = new MemberInfo [fieldCount];
+                                       for (int n=0; n<fieldCount; n++)
+                                       {
+                                               FieldInfo field = null;
+                                               string memberName = names[n];
+                                               
+                                               int i = memberName.IndexOf ('+');
+                                               if (i != -1) {
+                                                       string baseTypeName = names[n].Substring (0,i);
+                                                       memberName = names[n].Substring (i+1);
+                                                       Type t = metadata.Type.BaseType;
+                                                       while (t != null) {
+                                                               if (t.Name == baseTypeName) {
+                                                                       field = t.GetField (memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
+                                                                       break;
+                                                               }
+                                                               else
+                                                                       t = t.BaseType;
+                                                       }
+                                               }
+                                               else
+                                                       field = metadata.Type.GetField (memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
+                                                       
+                                               if (field != null)
+                                                       metadata.MemberInfos [n] = field;
+                                               
+                                               if (!hasTypeInfo) {
+                                                       types [n] = field.FieldType;
+                                               }
+                                       }
+                                       metadata.MemberNames = null;    // Info now in MemberInfos
+                               }
+                       }
+
+                       // Registers the type's metadata so it can be reused later if
+                       // a RefTypeObject element is found
+
+                       if (!_typeMetadataCache.ContainsKey (metadata.Type))
+                               _typeMetadataCache [metadata.Type] = metadata;
+
+                       return metadata;
+               }
+
+               // Called for primitive types
+               static bool IsGeneric (MemberInfo minfo)
+               {
+                       if (minfo == null)
+                               return false;
+
+                       Type mtype = null;
+                       switch (minfo.MemberType) {
+                       case MemberTypes.Field:
+                               mtype = ((FieldInfo) minfo).FieldType;
+                               break;
+                       default:
+                               throw new NotSupportedException ("Not supported: " + minfo.MemberType);
+                       }
+                       return (mtype != null && mtype.IsGenericType);
+               }
+
+               private void ReadValue (BinaryReader reader, object parentObject, long parentObjectId, SerializationInfo info, Type valueType, string fieldName, MemberInfo memberInfo, int[] indices)
+               {
+                       // Reads a value from the stream and assigns it to the member of an object
+
+                       object val;
+
+                       if (BinaryCommon.IsPrimitive (valueType) && !IsGeneric (memberInfo))
+                       {
+                               val = ReadPrimitiveTypeValue (reader, valueType);
+                               SetObjectValue (parentObject, fieldName, memberInfo, info, val, valueType, indices);
+                               return;
+                       }
+
+                       // Gets the object
+
+                       BinaryElement element = (BinaryElement)reader.ReadByte ();
+
+                       if (element == BinaryElement.ObjectReference)
+                       {
+                               // Just read the id of the referred object and record a fixup
+                               long childObjectId = (long) reader.ReadUInt32();
+                               RecordFixup (parentObjectId, childObjectId, parentObject, info, fieldName, memberInfo, indices);
+                               return;
+                       }
+
+                       long objectId;
+                       SerializationInfo objectInfo;
+
+                       ReadObject (element, reader, out objectId, out val, out objectInfo);
+
+                       // There are two cases where the object cannot be assigned to the parent
+                       // and a fixup must be used:
+                       //  1) When what has been read is not an object, but an id of an object that
+                       //     has not been read yet (an object reference). This is managed in the
+                       //     previous block of code.
+                       //  2) When the read object is a value type object. Value type fields hold
+                       //     copies of objects, not references. Thus, if the value object that
+                       //     has been read has pending fixups, those fixups would be made to the
+                       //     boxed copy in the ObjectManager, and not in the required object instance
+
+                       // First of all register the fixup, and then the object. ObjectManager is more
+                       // efficient if done in this order
+
+                       bool hasFixup = false;
+                       if (objectId != 0)
+                       {
+                               if (val.GetType().IsValueType)
+                               {
+                                       RecordFixup (parentObjectId, objectId, parentObject, info, fieldName, memberInfo, indices);
+                                       hasFixup = true;
+                               }
+
+                               // Register the value
+
+                               if (info == null && !(parentObject is Array))
+                                       RegisterObject (objectId, val, objectInfo, parentObjectId, memberInfo, null);
+                               else
+                                       RegisterObject (objectId, val, objectInfo, parentObjectId, null, indices);
+                       }
+                       // Assign the value to the parent object, unless there is a fixup
+                       
+                       if (!hasFixup) 
+                               SetObjectValue (parentObject, fieldName, memberInfo, info, val, valueType, indices);
+               }
+
+               private void SetObjectValue (object parentObject, string fieldName, MemberInfo memberInfo, SerializationInfo info, object value, Type valueType, int[] indices)
+               {
+                       if (value is IObjectReference)
+                               value = ((IObjectReference)value).GetRealObject (_context);
+
+                       if (parentObject is Array) 
+                       {
+                               if (value is ArrayNullFiller) 
+                               {
+                                       // It must be a single dimension array of objects.
+                                       // Just increase the index. Elements are null by default.
+                                       int count = ((ArrayNullFiller)value).NullCount;
+                                       indices[0] += count - 1;
+                               }
+                               else
+                                       ((Array)parentObject).SetValue (value, indices);
+                       }
+                       else if (info != null) {
+                               info.AddValue (fieldName, value, valueType);
+                       }
+                       else {
+                               if (memberInfo is FieldInfo)
+                                       ((FieldInfo)memberInfo).SetValue (parentObject, value);
+                               else
+                                       ((PropertyInfo)memberInfo).SetValue (parentObject, value, null);
+                       }
+               }
+
+               private void RecordFixup (long parentObjectId, long childObjectId, object parentObject, SerializationInfo info, string fieldName, MemberInfo memberInfo, int[] indices)
+               {
+                       if (info != null) {
+                               _manager.RecordDelayedFixup (parentObjectId, fieldName, childObjectId);
+                       }
+                       else if (parentObject is Array) {
+                               if (indices.Length == 1)
+                                       _manager.RecordArrayElementFixup (parentObjectId, indices[0], childObjectId);
+                               else
+                                       _manager.RecordArrayElementFixup (parentObjectId, (int[])indices.Clone(), childObjectId);
+                       }
+                       else {
+                               _manager.RecordFixup (parentObjectId, memberInfo, childObjectId);
+                       }
+               }
+
+               private Type GetDeserializationType (long assemblyId, string className)
+               {
+                       return GetDeserializationType (assemblyId, className, true);
+               }
+               
+               private Type GetDeserializationType (long assemblyId, string className, bool throwOnError)
+               {
+                       Type t;
+                       string assemblyName = (string)_registeredAssemblies[assemblyId];
+
+                       if (_binder != null) {
+                               t = _binder.BindToType (assemblyName, className);
+                               if (t != null)
+                                       return t;
+                       }
+
+                       Assembly assembly;
+                       try {
+                               assembly = Assembly.Load (assemblyName);
+                       } catch (Exception ex) {
+                               if (!throwOnError)
+                                       return null;
+                               throw new SerializationException (String.Format ("Couldn't find assembly '{0}'", assemblyName), ex);
+                       }
+
+                       t = assembly.GetType (className);
+                       if (t != null)
+                               return t;
+
+                       if (!throwOnError)
+                               return null;
+
+                       throw new SerializationException (String.Format ("Couldn't find type '{0}' in assembly '{1}'", className, assemblyName));
+               }
+
+               public Type ReadType (BinaryReader reader, TypeTag code)
+               {
+                       return ReadType (reader, code, true);
+               }
+               
+               public Type ReadType (BinaryReader reader, TypeTag code, bool throwOnError)
+               {
+                       switch (code)
+                       {
+                               case TypeTag.PrimitiveType:
+                                       return BinaryCommon.GetTypeFromCode (reader.ReadByte());
+
+                               case TypeTag.String:
+                                       return typeof(string);
+
+                               case TypeTag.ObjectType:
+                                       return typeof(object);
+
+                               case TypeTag.RuntimeType:
+                               {
+                                       string name = reader.ReadString ();
+                                       // map MS.NET's System.RuntimeType to System.MonoType
+                                       if (_context.State == StreamingContextStates.Remoting)
+                                               if (name == "System.RuntimeType")
+                                                       return typeof (MonoType);
+                                               else if (name == "System.RuntimeType[]")
+                                                       return typeof (MonoType[]);
+                                       Type t = Type.GetType (name);
+                                       if (t != null)
+                                               return t;
+
+                                       throw new SerializationException (String.Format ("Could not find type '{0}'.", name));
+                               }
+
+                               case TypeTag.GenericType:
+                               {
+                                       string name = reader.ReadString ();
+                                       long asmid = (long) reader.ReadUInt32();
+                                       return GetDeserializationType (asmid, name, throwOnError);
+                               }
+
+                               case TypeTag.ArrayOfObject:
+                                       return typeof(object[]);
+
+                               case TypeTag.ArrayOfString:
+                                       return typeof(string[]);
+
+                               case TypeTag.ArrayOfPrimitiveType:
+                                       Type elementType = BinaryCommon.GetTypeFromCode (reader.ReadByte());
+                                       return Type.GetType(elementType.FullName + "[]");
+
+                               default:
+                                       throw new NotSupportedException ("Unknow type tag");
+                       }
+               }
+               
+               public static object ReadPrimitiveTypeValue (BinaryReader reader, Type type)
+               {
+                       if (type == null) return null;
+
+                       switch (Type.GetTypeCode (type))
+                       {
+                               case TypeCode.Boolean:
+                                       return reader.ReadBoolean();
+
+                               case TypeCode.Byte:
+                                       return reader.ReadByte();
+
+                               case TypeCode.Char:
+                                       return reader.ReadChar();
+
+                               case TypeCode.DateTime: 
+                                       return DateTime.FromBinary (reader.ReadInt64());
+
+                               case TypeCode.Decimal:
+                                       return Decimal.Parse (reader.ReadString(), CultureInfo.InvariantCulture);
+
+                               case TypeCode.Double:
+                                       return reader.ReadDouble();
+
+                               case TypeCode.Int16:
+                                       return reader.ReadInt16();
+
+                               case TypeCode.Int32:
+                                       return reader.ReadInt32();
+
+                               case TypeCode.Int64:
+                                       return reader.ReadInt64();
+
+                               case TypeCode.SByte:
+                                       return reader.ReadSByte();
+
+                               case TypeCode.Single:
+                                       return reader.ReadSingle();
+
+                               case TypeCode.UInt16:
+                                       return reader.ReadUInt16();
+
+                               case TypeCode.UInt32:
+                                       return reader.ReadUInt32();
+
+                               case TypeCode.UInt64:
+                                       return reader.ReadUInt64();
+
+                               case TypeCode.String:
+                                       return reader.ReadString();
+
+                               default:
+                                       if (type == typeof(TimeSpan))
+                                               return new TimeSpan (reader.ReadInt64 ());
+                                       else
+                                               throw new NotSupportedException ("Unsupported primitive type: " + type.FullName);
+                       }
+               }
+       }
+}