* ObjectReader.cs: Changed signature of ReadObjectGraph, so now it returns the
[mono.git] / mcs / class / corlib / System.Runtime.Serialization.Formatters.Binary / ObjectReader.cs
index cf3195d56f0c4be0fa1dafd53099bb568f78ce3a..6f065f92170f9d6ea8a081c8043d9b4c0c073699 100644 (file)
@@ -1,9 +1,10 @@
-// ObjectReader.cs
-//
-// Author:
-//   Lluis Sanchez Gual (lsg@ctv.es)
-//
-// (C) 2003 Lluis Sanchez Gual
+// ObjectReader.cs\r
+//\r
+// Author:\r
+//   Lluis Sanchez Gual (lluis@ideary.com)\r
+//   Patrik Torstensson\r
+//\r
+// (C) 2003 Lluis Sanchez Gual\r
 \r
 // FIXME: Implement the missing binary elements\r
 \r
@@ -12,19 +13,23 @@ using System.Runtime.Serialization;
 using System.IO;\r
 using System.Collections;\r
 using System.Reflection;\r
+using System.Runtime.Remoting.Messaging;\r
 \r
 namespace System.Runtime.Serialization.Formatters.Binary\r
 {\r
-       public class ObjectReader\r
+       internal class ObjectReader\r
        {\r
                ISurrogateSelector _surrogateSelector;\r
                StreamingContext _context;\r
+               SerializationBinder _binder;\r
 \r
                ObjectManager _manager;\r
                Hashtable _registeredAssemblies = new Hashtable();\r
                Hashtable _typeMetadataCache = new Hashtable();\r
 \r
-               static Type[] _typeCodes;\r
+               object _lastObject = null;\r
+               long _lastObjectID = 0;\r
+               long _rootObjectID = 0;\r
 \r
                class TypeMetadata\r
                {\r
@@ -41,59 +46,58 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        public int NullCount;\r
                }\r
 \r
-               static ObjectReader()\r
-               {\r
-                       _typeCodes = new Type [30];\r
-                       _typeCodes[(int) TypeCode.Boolean] = typeof (Boolean);\r
-                       _typeCodes[(int)TypeCode.Byte] = typeof (Byte);\r
-                       _typeCodes[(int)TypeCode.Char] = typeof (Char);\r
-                       _typeCodes[(int)TypeCode.DateTime] = typeof (DateTime);\r
-                       _typeCodes[(int)TypeCode.Decimal] = typeof (Decimal);\r
-                       _typeCodes[(int)TypeCode.Double] = typeof (Double);\r
-                       _typeCodes[(int)TypeCode.Int16] = typeof (Int16);\r
-                       _typeCodes[(int)TypeCode.Int32] = typeof (Int32);\r
-                       _typeCodes[(int)TypeCode.Int64] = typeof (Int64);\r
-                       _typeCodes[(int)TypeCode.SByte] = typeof (SByte);\r
-                       _typeCodes[(int)TypeCode.Single] = typeof (Single);\r
-                       _typeCodes[(int)TypeCode.UInt16] = typeof (UInt16);\r
-                       _typeCodes[(int)TypeCode.UInt32] = typeof (UInt32);\r
-                       _typeCodes[(int)TypeCode.UInt64] = typeof (UInt64);\r
-               }\r
-\r
-               public ObjectReader(ISurrogateSelector surrogateSelector, StreamingContext context)\r
+               public ObjectReader(ISurrogateSelector surrogateSelector, StreamingContext context, SerializationBinder binder)\r
                {\r
                        _manager = new ObjectManager (surrogateSelector, context);\r
                        _surrogateSelector = surrogateSelector;\r
                        _context = context;\r
+                       _binder = binder;\r
                }\r
 \r
-               public object ReadObjectGraph (BinaryReader reader)\r
+               public void ReadObjectGraph (BinaryReader reader, bool readHeaders, out object result, out Header[] headers)\r
                {\r
-                       object rootObject = null;\r
-                       object tmpObject;\r
-                       SerializationInfo info;\r
-                       long objectId;\r
-\r
-                       // Reads the header\r
-\r
-                       int headerLen = BinaryCommon.BinaryHeader.Length;\r
-                       reader.ReadBytes (headerLen);\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
-                       while (element != BinaryElement.End)\r
+                       if (element == BinaryElement.End)\r
                        {\r
-                               ReadObject (element, reader, out objectId, out tmpObject, out info);\r
-                               if (objectId != 0) RegisterObject (objectId, tmpObject, info, 0, null, null);\r
-                               if (rootObject == null && tmpObject != null) rootObject = tmpObject;\r
-                               element = (BinaryElement)reader.ReadByte ();\r
+                               _manager.DoFixups();\r
+                               _manager.RaiseDeserializationEvent();\r
+                               return false;\r
                        }\r
 \r
-                       _manager.DoFixups();\r
+                       SerializationInfo info;\r
+                       long objectId;\r
+\r
+                       ReadObject (element, reader, out objectId, out _lastObject, out info);\r
 \r
-                       return rootObject;\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
@@ -180,8 +184,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
                {\r
                        long id = (long) reader.ReadUInt32 ();\r
                        string assemblyName = reader.ReadString ();\r
-                       Assembly assembly = Assembly.Load (assemblyName);\r
-                       _registeredAssemblies [id] = assembly;\r
+                       _registeredAssemblies [id] = assemblyName;\r
                }\r
 \r
                private void ReadObjectInstance (BinaryReader reader, bool isRuntimeObject, out long objectId, out object value, out SerializationInfo info)\r
@@ -217,10 +220,15 @@ namespace System.Runtime.Serialization.Formatters.Binary
 \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, indices);\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
@@ -235,15 +243,26 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        ArrayStructure structure = (ArrayStructure) 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
@@ -344,8 +363,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        if (!isRuntimeObject) \r
                        {\r
                                long assemblyId = (long)reader.ReadUInt32();\r
-                               Assembly asm = (Assembly)_registeredAssemblies[assemblyId];\r
-                               metadata.Type = asm.GetType (className, true);\r
+                               metadata.Type = GetDeserializationType (assemblyId, className);\r
                        }\r
                        else\r
                                metadata.Type = Type.GetType (className, true);\r
@@ -504,12 +522,25 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        return members[0];\r
                }\r
 \r
-               private Type ReadType (BinaryReader reader, TypeTag code)\r
+               private Type GetDeserializationType (long assemblyId, string className)\r
+               {\r
+                       string assemblyName = (string)_registeredAssemblies[assemblyId];\r
+\r
+                       if (_binder == null)\r
+                       {\r
+                               Assembly assembly = Assembly.Load (assemblyName);\r
+                               return assembly.GetType (className, true);\r
+                       }\r
+                       else\r
+                               return _binder.BindToType (assemblyName, className);\r
+               }\r
+\r
+               public Type ReadType (BinaryReader reader, TypeTag code)\r
                {\r
                        switch (code)\r
                        {\r
                                case TypeTag.PrimitiveType:\r
-                                       return _typeCodes [reader.ReadByte() + 1];\r
+                                       return BinaryCommon.GetTypeFromCode (reader.ReadByte());\r
 \r
                                case TypeTag.String:\r
                                        return typeof(string);\r
@@ -527,8 +558,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                {\r
                                        string name = reader.ReadString ();\r
                                        long asmid = (long) reader.ReadUInt32();\r
-                                       Assembly asm = (Assembly)_registeredAssemblies[asmid];\r
-                                       return asm.GetType (name, true);\r
+                                       return GetDeserializationType (asmid, name);\r
                                }\r
 \r
                                case TypeTag.ArrayOfObject:\r
@@ -538,7 +568,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                        return typeof(string[]);\r
 \r
                                case TypeTag.ArrayOfPrimitiveType:\r
-                                       Type elementType = _typeCodes [reader.ReadByte()+1];\r
+                                       Type elementType = BinaryCommon.GetTypeFromCode (reader.ReadByte());\r
                                        return Type.GetType(elementType.FullName + "[]");\r
 \r
                                default:\r
@@ -546,8 +576,10 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        }\r
                }\r
                \r
-               private object ReadPrimitiveTypeValue (BinaryReader reader, Type type)\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
@@ -593,6 +625,9 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                case TypeCode.UInt64:\r
                                        return reader.ReadUInt64();\r
 \r
+                               case TypeCode.String:\r
+                                       return reader.ReadString();\r
+\r
                                default:\r
                                        throw new NotSupportedException ("Unsupported primitive type: " + type.FullName);\r
                        }\r