* ObjectReader.cs, ObjectWriter.cs, BinaryCommon.cs: Fixed bug #45970.
[mono.git] / mcs / class / corlib / System.Runtime.Serialization.Formatters.Binary / ObjectWriter.cs
index 887b06158bd050cc3caa530f742100eb136b5755..73a03d2b4eb7a2a567b0db3a2cb6690de98f3b25 100644 (file)
@@ -1,9 +1,9 @@
-// ObjectWriter.cs
-//
-// Author:
-//   Lluis Sanchez Gual (lsg@ctv.es)
-//
-// (C) 2003 Lluis Sanchez Gual
+// ObjectWriter.cs\r
+//\r
+// Author:\r
+//   Lluis Sanchez Gual (lluis@ideary.com)\r
+//\r
+// (C) 2003 Lluis Sanchez Gual\r
 \r
 // FIXME: Implement the missing binary elements\r
 \r
@@ -11,6 +11,7 @@ using System;
 using System.IO;\r
 using System.Collections;\r
 using System.Runtime.Serialization;\r
+using System.Runtime.Remoting.Messaging;\r
 using System.Reflection;\r
 \r
 namespace System.Runtime.Serialization.Formatters.Binary\r
@@ -20,9 +21,10 @@ namespace System.Runtime.Serialization.Formatters.Binary
                ObjectIDGenerator _idGenerator = new ObjectIDGenerator();\r
                Hashtable _cachedTypes = new Hashtable();\r
                Queue _pendingObjects = new Queue();\r
-               Assembly _corlibAssembly;\r
                Hashtable _assemblyCache = new Hashtable();\r
 \r
+               static Assembly _corlibAssembly = typeof(string).Assembly;\r
+\r
                ISurrogateSelector _surrogateSelector;\r
                StreamingContext _context;\r
 \r
@@ -56,27 +58,40 @@ namespace System.Runtime.Serialization.Formatters.Binary
                {\r
                        _surrogateSelector = surrogateSelector;\r
                        _context = context;\r
-                       _corlibAssembly = GetType().Assembly;\r
                }\r
 \r
-               public void WriteObjectGraph (BinaryWriter writer, object obj)\r
+               public void WriteObjectGraph (BinaryWriter writer, object obj, Header[] headers)\r
                {\r
-                       writer.Write (BinaryCommon.BinaryHeader);\r
-\r
                        _pendingObjects.Clear();\r
+                       if (headers != null) QueueObject (headers);\r
+                       QueueObject (obj);\r
+                       WriteQueuedObjects (writer);\r
+                       WriteSerializationEnd (writer);\r
+               }\r
 \r
-                       WriteObjectInstance (writer, obj);\r
+               public void QueueObject (object obj)\r
+               {\r
+                       _pendingObjects.Enqueue (obj);\r
+               }\r
 \r
-                       while (_pendingObjects.Count > 0)\r
-                               WriteObjectInstance (writer, _pendingObjects.Dequeue());\r
+               public void WriteQueuedObjects (BinaryWriter writer)\r
+               {\r
 \r
-                       writer.Write ((byte) BinaryElement.End);\r
+                       while (_pendingObjects.Count > 0)\r
+                               WriteObjectInstance (writer, _pendingObjects.Dequeue(), false);\r
                }\r
 \r
-               public void WriteObjectInstance (BinaryWriter writer, object obj)\r
+               public void WriteObjectInstance (BinaryWriter writer, object obj, bool isValueObject)\r
                {\r
                        bool firstTime;\r
-                       long id = _idGenerator.GetId (obj, out firstTime);\r
+                       long id;\r
+\r
+                       // If the object is a value type (not boxed) then there is no need\r
+                       // to register it in the id generator, because it won't have other\r
+                       // references to it\r
+\r
+                       if (isValueObject) id = _idGenerator.NextId;\r
+                       else id = _idGenerator.GetId (obj, out firstTime);\r
 \r
                        if (obj.GetType() == typeof(string)) {\r
                                WriteString (writer, id, (string)obj);\r
@@ -88,6 +103,11 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                WriteObject (writer, id, obj);\r
                }\r
 \r
+               public static void WriteSerializationEnd (BinaryWriter writer)\r
+               {\r
+                       writer.Write ((byte) BinaryElement.End);\r
+               }\r
+\r
                private void WriteObject (BinaryWriter writer, long id, object obj)\r
                {\r
                        object[] values;\r
@@ -219,7 +239,9 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        // Check if the object is marked with the Serializable attribute\r
 \r
                        if (!metadata.InstanceType.IsSerializable)\r
-                               throw new SerializationException("Serializable objects must be marked with the Serializable attribute");\r
+                               throw new SerializationException ("Type " + metadata.InstanceType +\r
+                                                                 " is not marked as Serializable " + \r
+                                                                 "and does not implement ISerializable.");\r
 \r
                        ISerializable ser = obj as ISerializable;\r
 \r
@@ -281,6 +303,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
 \r
                        metadata.Types = types;\r
                        metadata.Names = names;\r
+\r
                        metadata.CustomSerialization = false;\r
                }\r
 \r
@@ -455,6 +478,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
 \r
                private void WriteObjectReference (BinaryWriter writer, long id)\r
                {\r
+\r
                        writer.Write ((byte) BinaryElement.ObjectReference);\r
                        writer.Write ((int)id);\r
                }\r
@@ -478,7 +502,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        else if (valueType.IsValueType)\r
                        {\r
                                // Value types are written embedded in the containing object\r
-                               WriteObjectInstance (writer, val);\r
+                               WriteObjectInstance (writer, val, true);\r
                        }\r
                        else if (val.GetType() == typeof(string))\r
                        {\r
@@ -486,7 +510,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                bool firstTime;\r
                                long id = _idGenerator.GetId (val, out firstTime);\r
 \r
-                               if (firstTime) WriteObjectInstance (writer, val);\r
+                               if (firstTime) WriteObjectInstance (writer, val, false);\r
                                else WriteObjectReference (writer, id);\r
                        }                       \r
                        else\r
@@ -536,9 +560,11 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        }\r
                }\r
 \r
-               private void WritePrimitiveValue (BinaryWriter writer, object value)\r
+               public static void WritePrimitiveValue (BinaryWriter writer, object value)\r
                {\r
-                       switch (Type.GetTypeCode (value.GetType()))\r
+                       Type type = value.GetType();\r
+\r
+                       switch (Type.GetTypeCode (type))\r
                        {\r
                                case TypeCode.Boolean:\r
                                        writer.Write ((bool)value);\r
@@ -595,15 +621,26 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                case TypeCode.UInt64:\r
                                        writer.Write ((ulong) value);\r
                                        break;\r
+\r
+                               case TypeCode.String:\r
+                                       writer.Write ((string) value);\r
+                                       break;\r
+\r
+                               default:\r
+                                       if (type == typeof (TimeSpan))\r
+                                               writer.Write (((TimeSpan)value).Ticks);\r
+                                       else\r
+                                               throw new NotSupportedException ("Unsupported primitive type: " + value.GetType().FullName);\r
+                                       break;\r
                        }\r
                }\r
 \r
-               private void WriteTypeCode (BinaryWriter writer, Type type)\r
+               public static void WriteTypeCode (BinaryWriter writer, Type type)\r
                {\r
                        writer.Write ((byte) GetTypeTag (type));\r
                }\r
 \r
-               private TypeTag GetTypeTag (Type type)\r
+               public static TypeTag GetTypeTag (Type type)\r
                {\r
                        if (type == typeof (string)) {\r
                                return TypeTag.String;\r
@@ -630,12 +667,12 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                return TypeTag.GenericType;\r
                }\r
 \r
-               private void WriteTypeSpec (BinaryWriter writer, Type type)\r
+               public void WriteTypeSpec (BinaryWriter writer, Type type)\r
                {\r
                        switch (GetTypeTag (type))\r
                        {\r
                                case TypeTag.PrimitiveType:\r
-                                       writer.Write ((byte) (Type.GetTypeCode (type) - 1));\r
+                                       writer.Write (BinaryCommon.GetTypeCode (type));\r
                                        break;\r
 \r
                                case TypeTag.RuntimeType:\r
@@ -648,7 +685,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                        break;\r
 \r
                                case TypeTag.ArrayOfPrimitiveType:\r
-                                       writer.Write ((byte) (Type.GetTypeCode (type.GetElementType()) - 1));\r
+                                       writer.Write (BinaryCommon.GetTypeCode (type.GetElementType()));\r
                                        break;\r
 \r
                                default:\r