2004-12-08 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / corlib / System.Runtime.Serialization.Formatters.Binary / ObjectWriter.cs
index 376b7fc1fce34e4c0cb88a99f68bb9817a02c465..b21a617bb341c0dcd41457df68ac35331eb246be 100644 (file)
@@ -4,8 +4,29 @@
 //   Lluis Sanchez Gual (lluis@ideary.com)\r
 //\r
 // (C) 2003 Lluis Sanchez Gual\r
-\r
-// FIXME: Implement the missing binary elements\r
+
+//
+// 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.
+//
 \r
 using System;\r
 using System.IO;\r
@@ -13,51 +34,196 @@ using System.Collections;
 using System.Runtime.Serialization;\r
 using System.Runtime.Remoting.Messaging;\r
 using System.Reflection;\r
+using System.Globalization;\r
 \r
 namespace System.Runtime.Serialization.Formatters.Binary\r
 {\r
+       abstract class TypeMetadata\r
+       {\r
+               public TypeMetadata (Type instanceType)\r
+               {\r
+                       InstanceType = instanceType;\r
+                       TypeAssembly = instanceType.Assembly;\r
+               }\r
+               \r
+               public Assembly TypeAssembly;\r
+               public Type InstanceType;\r
+               \r
+               public abstract void WriteAssemblies (ObjectWriter ow, BinaryWriter writer);\r
+               public abstract void WriteTypeData (ObjectWriter ow, BinaryWriter writer);\r
+               public abstract void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data);\r
+               \r
+               public virtual bool IsCompatible (TypeMetadata other)\r
+               {\r
+                       return true;\r
+               }\r
+       }\r
+       \r
+       class SerializableTypeMetadata: TypeMetadata\r
+       {\r
+               Type[] types;\r
+               string[] names;\r
+               \r
+               public SerializableTypeMetadata (Type itype, SerializationInfo info): base (itype)\r
+               {\r
+                       types = new Type [info.MemberCount];\r
+                       names = new string [info.MemberCount];\r
+\r
+                       SerializationInfoEnumerator e = info.GetEnumerator ();\r
+\r
+                       int n = 0;\r
+                       while (e.MoveNext ())\r
+                       {\r
+                               types[n] = e.ObjectType;\r
+                               names[n] = e.Name;\r
+                               n++;\r
+                       }\r
+\r
+                       if (info.FullTypeName != InstanceType.FullName || info.AssemblyName != TypeAssembly.FullName) \r
+                       {\r
+                               TypeAssembly = Assembly.Load (info.AssemblyName);\r
+                               InstanceType = TypeAssembly.GetType (info.FullTypeName);\r
+                       }\r
+               }\r
+               \r
+               public override bool IsCompatible (TypeMetadata other)\r
+               {\r
+                       if (!(other is SerializableTypeMetadata)) return false;\r
+                       \r
+                       SerializableTypeMetadata tm = (SerializableTypeMetadata)other;\r
+                       if (types.Length != tm.types.Length) return false;\r
+                       if (TypeAssembly != tm.TypeAssembly) return false;\r
+                       if (InstanceType != tm.InstanceType) return false;\r
+                       for (int n=0; n<types.Length; n++)\r
+                       {\r
+                               if (types[n] != tm.types[n]) return false;\r
+                               if (names[n] != tm.names[n]) return false;\r
+                       }\r
+                       return true;\r
+               }\r
+               \r
+               public override void WriteAssemblies (ObjectWriter ow, BinaryWriter writer)\r
+               {\r
+                       foreach (Type mtype in types)\r
+                       {\r
+                               Type type = mtype;\r
+                               while (type.IsArray) \r
+                                       type = type.GetElementType();\r
+                                       \r
+                               ow.WriteAssembly (writer, type.Assembly);\r
+                       }\r
+               }\r
+               \r
+               public override void WriteTypeData (ObjectWriter ow, BinaryWriter writer)\r
+               {\r
+                       writer.Write (types.Length);\r
+\r
+                       // Names of fields\r
+                       foreach (string name in names)\r
+                               writer.Write (name);\r
+\r
+                       // Types of fields\r
+                       foreach (Type type in types)\r
+                               ObjectWriter.WriteTypeCode (writer, type);\r
+\r
+                       // Type specs of fields\r
+                       foreach (Type type in types)\r
+                               ow.WriteTypeSpec (writer, type);\r
+               }\r
+               \r
+               public override void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data)\r
+               {\r
+                       SerializationInfo info = (SerializationInfo) data;\r
+                       SerializationInfoEnumerator e = info.GetEnumerator ();\r
+\r
+                       while (e.MoveNext ())\r
+                               ow.WriteValue (writer, e.ObjectType, e.Value);\r
+               }\r
+       }\r
+       \r
+       class MemberTypeMetadata: TypeMetadata\r
+       {\r
+               MemberInfo[] members;\r
+               \r
+               public MemberTypeMetadata (Type type, StreamingContext context): base (type)\r
+               {\r
+                       members = FormatterServices.GetSerializableMembers (type, context);\r
+               }\r
+\r
+               public override void WriteAssemblies (ObjectWriter ow, BinaryWriter writer)\r
+               {\r
+                       foreach (FieldInfo field in members)\r
+                       {\r
+                               Type type = field.FieldType;\r
+                               while (type.IsArray) \r
+                                       type = type.GetElementType();\r
+                                       \r
+                               ow.WriteAssembly (writer, type.Assembly);\r
+                       }\r
+               }\r
+               \r
+               public override void WriteTypeData (ObjectWriter ow, BinaryWriter writer)\r
+               {\r
+                       writer.Write (members.Length);\r
+\r
+                       // Names of fields\r
+                       foreach (FieldInfo field in members) {\r
+                               if (field.DeclaringType == InstanceType)\r
+                                       writer.Write (field.Name);\r
+                               else\r
+                                       writer.Write (field.DeclaringType.Name + "+" + field.Name);\r
+                       }\r
+\r
+                       // Types of fields\r
+                       foreach (FieldInfo field in members)\r
+                               ObjectWriter.WriteTypeCode (writer, field.FieldType);\r
+\r
+                       // Type specs of fields\r
+                       foreach (FieldInfo field in members)\r
+                               ow.WriteTypeSpec (writer, field.FieldType);\r
+               }\r
+               \r
+               public override void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data)\r
+               {\r
+                       object[] values = FormatterServices.GetObjectData (data, members);\r
+                       for (int n=0; n<values.Length; n++)\r
+                               ow.WriteValue (writer, ((FieldInfo)members[n]).FieldType, values[n]);\r
+               }\r
+       }\r
+       \r
        internal class ObjectWriter\r
        {\r
                ObjectIDGenerator _idGenerator = new ObjectIDGenerator();\r
-               Hashtable _cachedTypes = new Hashtable();\r
+               Hashtable _cachedMetadata = new Hashtable();\r
                Queue _pendingObjects = new Queue();\r
                Hashtable _assemblyCache = new Hashtable();\r
+               \r
+               // Type metadata that can be shared with all serializers\r
+               static Hashtable _cachedTypes = new Hashtable();\r
 \r
-               static Assembly _corlibAssembly = typeof(string).Assembly;\r
+               internal static Assembly CorlibAssembly = typeof(string).Assembly;\r
 \r
                ISurrogateSelector _surrogateSelector;\r
                StreamingContext _context;\r
-\r
-               class TypeMetadata\r
+               FormatterAssemblyStyle _assemblyFormat;\r
+               \r
+               class MetadataReference\r
                {\r
-                       public Type[] Types;\r
-                       public string[] Names;\r
-                       public Assembly TypeAssembly;\r
-                       public Type InstanceType;\r
+                       public TypeMetadata Metadata;\r
                        public long ObjectID;\r
-                       public bool CustomSerialization;\r
-\r
-                       public bool Equals (TypeMetadata other)\r
+                       \r
+                       public MetadataReference (TypeMetadata metadata, long id)\r
                        {\r
-                               if (!CustomSerialization) return true;\r
-\r
-                               TypeMetadata tm = (TypeMetadata)other;\r
-                               if (Types.Length != tm.Types.Length) return false;\r
-                               if (TypeAssembly != other.TypeAssembly) return false;\r
-                               if (InstanceType != other.InstanceType) return false;\r
-                               for (int n=0; n<Types.Length; n++)\r
-                               {\r
-                                       if (Types[n] != tm.Types[n]) return false;\r
-                                       if (Names[n] != tm.Names[n]) return false;\r
-                               }\r
-                               return true;\r
+                               Metadata = metadata;\r
+                               ObjectID = id;\r
                        }\r
                }\r
-\r
-               public ObjectWriter(ISurrogateSelector surrogateSelector, StreamingContext context)\r
+               \r
+               public ObjectWriter (ISurrogateSelector surrogateSelector, StreamingContext context, FormatterAssemblyStyle assemblyFormat)\r
                {\r
                        _surrogateSelector = surrogateSelector;\r
                        _context = context;\r
+                       _assemblyFormat = assemblyFormat;\r
                }\r
 \r
                public void WriteObjectGraph (BinaryWriter writer, object obj, Header[] headers)\r
@@ -110,14 +276,13 @@ namespace System.Runtime.Serialization.Formatters.Binary
 \r
                private void WriteObject (BinaryWriter writer, long id, object obj)\r
                {\r
-                       object[] values;\r
+                       object data;\r
                        TypeMetadata metadata;\r
 \r
-                       GetObjectData (obj, out metadata, out values);\r
+                       GetObjectData (obj, out metadata, out data);\r
+                       MetadataReference metadataReference = (MetadataReference)_cachedMetadata [metadata.InstanceType];\r
 \r
-                       TypeMetadata chachedMetadata = (TypeMetadata)_cachedTypes[metadata.InstanceType];\r
-\r
-                       if (chachedMetadata != null && metadata.Equals(chachedMetadata))\r
+                       if (metadataReference != null && metadata.IsCompatible (metadataReference.Metadata))\r
                        {\r
                                // An object of the same type has already been serialized\r
                                // It is not necessary to write again type metadata\r
@@ -125,24 +290,21 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                writer.Write ((byte) BinaryElement.RefTypeObject);\r
                                writer.Write ((int)id);\r
 \r
-                               // Get the id of the object that has the same type as this\r
-                               long refId = chachedMetadata.ObjectID;\r
-\r
-                               writer.Write ((int)refId);\r
-                               WriteObjectContent (writer, metadata.Types, values);\r
+                               writer.Write ((int)metadataReference.ObjectID);\r
+                               metadata.WriteObjectData (this, writer, data);\r
                                return;\r
                        }\r
 \r
-                       if (chachedMetadata == null)\r
+                       if (metadataReference == null)\r
                        {\r
-                               metadata.ObjectID = id;\r
-                               _cachedTypes [metadata.InstanceType] = metadata;\r
+                               metadataReference = new MetadataReference (metadata, id);\r
+                               _cachedMetadata [metadata.InstanceType] = metadataReference;\r
                        }\r
 \r
                        BinaryElement objectTag;\r
 \r
                        int assemblyId;\r
-                       if (metadata.TypeAssembly == _corlibAssembly)\r
+                       if (metadata.TypeAssembly == CorlibAssembly)\r
                        {\r
                                // A corlib type\r
                                objectTag = BinaryElement.RuntimeObject;\r
@@ -151,74 +313,30 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        else\r
                        {\r
                                objectTag = BinaryElement.ExternalObject;\r
-\r
-                               bool firstTime;\r
-                               assemblyId = RegisterAssembly (metadata.TypeAssembly, out firstTime);\r
-                               if (firstTime) WriteAssembly (writer, assemblyId, metadata.TypeAssembly);\r
+                               assemblyId = WriteAssembly (writer, metadata.TypeAssembly);\r
                        }\r
 \r
                        // Registers the assemblies needed for each field\r
                        // If there are assemblies that where not registered before this object,\r
                        // write them now\r
 \r
-                       foreach (object value in values)\r
-                       {\r
-                               if (value == null) continue;\r
-\r
-                               Type memberType = value.GetType();\r
-                               while (memberType.IsArray) \r
-                                       memberType = memberType.GetElementType();\r
-\r
-                               if (memberType.Assembly != _corlibAssembly)\r
-                               {\r
-                                       bool firstTime;\r
-                                       int aid = RegisterAssembly (memberType.Assembly, out firstTime);\r
-                                       if (firstTime) WriteAssembly (writer, aid, memberType.Assembly);\r
-                               }\r
-                       }\r
+                       metadata.WriteAssemblies (this, writer);\r
 \r
                        // Writes the object\r
 \r
                        writer.Write ((byte) objectTag);\r
                        writer.Write ((int)id);\r
                        writer.Write (metadata.InstanceType.FullName);\r
-                       WriteObjectMetadata (writer, metadata, assemblyId);\r
-                       WriteObjectContent (writer, metadata.Types, values);\r
-               }\r
-\r
-               private void WriteObjectMetadata (BinaryWriter writer, TypeMetadata metadata, int assemblyId)\r
-               {\r
-                       Type[] types = metadata.Types;\r
-                       string[] names = metadata.Names;\r
-\r
-                       writer.Write (types.Length);\r
-\r
-                       // Names of fields\r
-                       foreach (string name in names)\r
-                               writer.Write (name);\r
-\r
-                       // Types of fields\r
-                       foreach (Type type in types)\r
-                               WriteTypeCode (writer, type);\r
-\r
-                       // Type specs of fields\r
-                       foreach (Type type in types)\r
-                               WriteTypeSpec (writer, type);\r
-\r
+                       \r
+                       metadata.WriteTypeData (this, writer);\r
                        if (assemblyId != -1) writer.Write (assemblyId);\r
+                       \r
+                       metadata.WriteObjectData (this, writer, data);\r
                }\r
 \r
-               private void WriteObjectContent (BinaryWriter writer, Type[] types, object[] values)\r
-               {\r
-                       for (int n=0; n<values.Length; n++)\r
-                               WriteValue (writer, types[n], values[n]);\r
-               }\r
-\r
-               private void GetObjectData (object obj, out TypeMetadata metadata, out object[] values)\r
+               private void GetObjectData (object obj, out TypeMetadata metadata, out object data)\r
                {\r
-                       metadata = new TypeMetadata();\r
-                       metadata.InstanceType = obj.GetType();\r
-                       metadata.TypeAssembly = metadata.InstanceType.Assembly;\r
+                       Type instanceType = obj.GetType();\r
 \r
                        // Check if the formatter has a surrogate selector \96 if it does, \r
                        // check if the surrogate selector handles objects of the given type. \r
@@ -226,85 +344,75 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        if (_surrogateSelector != null)\r
                        {\r
                                ISurrogateSelector selector;\r
-                               ISerializationSurrogate surrogate = _surrogateSelector.GetSurrogate (metadata.InstanceType, _context, out selector);\r
+                               ISerializationSurrogate surrogate = _surrogateSelector.GetSurrogate (instanceType, _context, out selector);\r
                                if (surrogate != null)\r
                                {\r
-                                       SerializationInfo info = new SerializationInfo (metadata.InstanceType, new FormatterConverter ());\r
-                                       surrogate.GetObjectData(obj, info, _context);\r
-                                       GetDataFromSerializationInfo (info, ref metadata, out values);\r
+                                       SerializationInfo info = new SerializationInfo (instanceType, new FormatterConverter ());\r
+                                       surrogate.GetObjectData (obj, info, _context);\r
+                                       metadata = new SerializableTypeMetadata (instanceType, info);\r
+                                       data = info;\r
                                        return;\r
                                }\r
                        }\r
 \r
                        // Check if the object is marked with the Serializable attribute\r
 \r
-                       if (!metadata.InstanceType.IsSerializable)\r
-                               throw new SerializationException ("Type " + metadata.InstanceType +\r
-                                                                 " is not marked as Serializable " + \r
-                                                                 "and does not implement ISerializable.");\r
+                       BinaryCommon.CheckSerializable (instanceType, _surrogateSelector, _context);\r
 \r
                        ISerializable ser = obj as ISerializable;\r
 \r
                        if (ser != null) \r
                        {\r
-                               SerializationInfo info = new SerializationInfo (metadata.InstanceType, new FormatterConverter ());\r
+                               SerializationInfo info = new SerializationInfo (instanceType, new FormatterConverter ());\r
                                ser.GetObjectData (info, _context);\r
-                               GetDataFromSerializationInfo (info, ref metadata, out values);\r
+                               metadata = new SerializableTypeMetadata (instanceType, info);\r
+                               data = info;\r
                        } \r
                        else \r
-                               GetDataFromObjectFields (obj, ref metadata, out values);\r
-               }\r
-\r
-               private void GetDataFromSerializationInfo (SerializationInfo info, ref TypeMetadata metadata, out object[] values)\r
-               {\r
-                       Type[] types = types = new Type [info.MemberCount];\r
-                       string[] names = new string [info.MemberCount];\r
-                       values = new object [info.MemberCount];\r
+                       {\r
+                               data = obj;\r
+                               if (_context.Context != null)\r
+                               {\r
+                                       // Don't cache metadata info when the Context property is not null sice\r
+                                       // we can't control the number of possible contexts in this case\r
+                                       metadata = new MemberTypeMetadata (instanceType, _context);\r
+                                       return;\r
+                               }\r
+                               \r
+                               Hashtable typesTable;\r
+                               bool isNew = false;\r
+                               lock (_cachedTypes) {\r
+                                       typesTable = (Hashtable) _cachedTypes [_context.State];\r
+                                       if (typesTable == null) {\r
+                                               typesTable = new Hashtable ();\r
+                                               _cachedTypes [_context.State] = typesTable;\r
+                                               isNew = true;\r
+                                       }\r
+                               }\r
 \r
-                       SerializationInfoEnumerator e = info.GetEnumerator ();\r
+                               metadata = null;\r
+                               lock (typesTable) {\r
+                                       if (!isNew) {\r
+                                               metadata = (TypeMetadata) typesTable [instanceType];\r
+                                       }\r
 \r
-                       int n = 0;\r
-                       while (e.MoveNext ())\r
-                       {\r
-                               values[n] = e.Value;\r
-                               types[n] = e.ObjectType;\r
-                               names[n] = e.Name;\r
-                               n++;\r
-                       }\r
+                                       if (metadata == null) {\r
+                                               metadata = CreateMemberTypeMetadata (instanceType);\r
+                                       }\r
 \r
-                       if (info.FullTypeName != metadata.InstanceType.FullName || info.AssemblyName != metadata.TypeAssembly.FullName) \r
-                       {\r
-                               metadata.TypeAssembly = Assembly.Load (info.AssemblyName);\r
-                               metadata.InstanceType = metadata.TypeAssembly.GetType (info.FullTypeName);\r
+                                       typesTable [instanceType] = metadata;\r
+                               }\r
                        }\r
-\r
-                       metadata.Types = types;\r
-                       metadata.Names = names;\r
-                       metadata.CustomSerialization = true;\r
                }\r
-\r
-               private void GetDataFromObjectFields (object obj, ref TypeMetadata metadata, out object[] values)\r
+               \r
+               TypeMetadata CreateMemberTypeMetadata (Type type)\r
                {\r
-                       MemberInfo[] members = FormatterServices.GetSerializableMembers (obj.GetType(), _context);\r
-                       values = FormatterServices.GetObjectData (obj, members);\r
-\r
-                       Type[] types = new Type [members.Length];\r
-                       string[] names = new string [members.Length];\r
-\r
-                       for (int n=0; n<members.Length; n++)\r
-                       {\r
-                               MemberInfo member = members[n];\r
-                               names[n] = member.Name;\r
-                               if (member is FieldInfo)\r
-                                       types[n] = ((FieldInfo)member).FieldType;\r
-                               else if (member is PropertyInfo)\r
-                                       types[n] = ((PropertyInfo)member).PropertyType;\r
+                       if (!BinaryCommon.UseReflectionSerialization) {\r
+                               Type metaType = CodeGenerator.GenerateMetadataType (type, _context);\r
+                               return (TypeMetadata) Activator.CreateInstance (metaType);\r
                        }\r
-\r
-                       metadata.Types = types;\r
-                       metadata.Names = names;\r
-\r
-                       metadata.CustomSerialization = false;\r
+                       else\r
+                               return new MemberTypeMetadata (type, _context);\r
                }\r
 \r
                private void WriteArray (BinaryWriter writer, long id, Array array)\r
@@ -337,12 +445,8 @@ namespace System.Runtime.Serialization.Formatters.Binary
 \r
                        // Registers and writes the assembly of the array element type if needed\r
 \r
-                       if (!elementType.IsArray && elementType.Assembly != _corlibAssembly)\r
-                       {\r
-                               bool firstTime;\r
-                               int aid = RegisterAssembly (elementType.Assembly, out firstTime);\r
-                               if (firstTime) WriteAssembly (writer, aid, elementType.Assembly);\r
-                       }\r
+                       if (!elementType.IsArray)\r
+                               WriteAssembly (writer, elementType.Assembly);\r
 \r
                        // Writes the array\r
 \r
@@ -379,31 +483,8 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        }\r
                        else\r
                        {\r
-                               int[] indices = new int[array.Rank];\r
-\r
-                               // Initialize indexes\r
-                               for (int dim = array.Rank-1; dim >= 0; dim--)\r
-                                       indices[dim] = array.GetLowerBound (dim);\r
-\r
-                               bool end = false;\r
-                               while (!end)\r
-                               {\r
-                                       WriteValue (writer, elementType, array.GetValue (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
-                                                               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
+                               foreach (object item in array)\r
+                                       WriteValue (writer, elementType, item);\r
                        }\r
                }\r
 \r
@@ -432,16 +513,98 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        Type elementType = array.GetType().GetElementType();\r
                        WriteTypeSpec (writer, elementType);\r
 \r
-                       for (int n=0; n<array.Length; n++)\r
-                               WritePrimitiveValue (writer, array.GetValue (n));\r
+                       switch (Type.GetTypeCode (elementType))\r
+                       {\r
+                               case TypeCode.Boolean:\r
+                                       foreach (bool item in (bool[]) array)\r
+                                               writer.Write (item);\r
+                                       break;\r
+\r
+                               case TypeCode.Byte:\r
+                                       writer.Write ((byte[]) array);\r
+                                       break;\r
+\r
+                               case TypeCode.Char:\r
+                                       foreach (char item in (char[]) array)\r
+                                               writer.Write (item);\r
+                                       break;\r
+\r
+                               case TypeCode.DateTime: \r
+                                       foreach (DateTime item in (DateTime[]) array)\r
+                                               writer.Write (item.Ticks);\r
+                                       break;\r
+\r
+                               case TypeCode.Decimal:\r
+                                       foreach (decimal item in (decimal[]) array)\r
+                                               writer.Write (item);\r
+                                       break;\r
+\r
+                               case TypeCode.Double:\r
+                                       foreach (double item in (double[]) array)\r
+                                               writer.Write (item);\r
+                                       break;\r
+\r
+                               case TypeCode.Int16:\r
+                                       foreach (short item in (short[]) array)\r
+                                               writer.Write (item);\r
+                                       break;\r
+\r
+                               case TypeCode.Int32:\r
+                                       foreach (int item in (int[]) array)\r
+                                               writer.Write (item);\r
+                                       break;\r
+\r
+                               case TypeCode.Int64:\r
+                                       foreach (long item in (long[]) array)\r
+                                               writer.Write (item);\r
+                                       break;\r
+\r
+                               case TypeCode.SByte:\r
+                                       foreach (sbyte item in (sbyte[]) array)\r
+                                               writer.Write (item);\r
+                                       break;\r
+\r
+                               case TypeCode.Single:\r
+                                       foreach (float item in (float[]) array)\r
+                                               writer.Write (item);\r
+                                       break;\r
+\r
+                               case TypeCode.UInt16:\r
+                                       foreach (ushort item in (ushort[]) array)\r
+                                               writer.Write (item);\r
+                                       break;\r
+\r
+                               case TypeCode.UInt32:\r
+                                       foreach (uint item in (uint[]) array)\r
+                                               writer.Write (item);\r
+                                       break;\r
+\r
+                               case TypeCode.UInt64:\r
+                                       foreach (ulong item in (ulong[]) array)\r
+                                               writer.Write (item);\r
+                                       break;\r
+\r
+                               case TypeCode.String:\r
+                                       foreach (string item in (string[]) array)\r
+                                               writer.Write (item);\r
+                                       break;\r
+\r
+                               default:\r
+                                       if (elementType == typeof (TimeSpan)) {\r
+                                               foreach (TimeSpan item in (TimeSpan[]) array)\r
+                                                       writer.Write (item.Ticks);\r
+                                       }\r
+                                       else\r
+                                               throw new NotSupportedException ("Unsupported primitive type: " + elementType.FullName);\r
+                                       break;\r
+                       }                       \r
                }\r
 \r
                private void WriteSingleDimensionArrayElements (BinaryWriter writer, Array array, Type elementType)\r
                {\r
                        int numNulls = 0;\r
-                       for (int n = array.GetLowerBound (0); n<=array.GetUpperBound(0); n++)\r
+                       foreach (object val in array)\r
                        {\r
-                               object val = array.GetValue (n);\r
                                if (val != null && numNulls > 0)\r
                                {\r
                                        WriteNullFiller (writer, numNulls);\r
@@ -483,10 +646,11 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        writer.Write ((int)id);\r
                }\r
 \r
-               private void WriteValue (BinaryWriter writer, Type valueType, object val)\r
+               public void WriteValue (BinaryWriter writer, Type valueType, object val)\r
                {\r
                        if (val == null) \r
                        {\r
+                               BinaryCommon.CheckSerializable (valueType, _surrogateSelector, _context);\r
                                writer.Write ((byte) BinaryElement.NullValue);\r
                        }\r
                        else if (BinaryCommon.IsPrimitive(val.GetType()))\r
@@ -533,14 +697,25 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        writer.Write (str);\r
                }\r
 \r
-               private void WriteAssembly (BinaryWriter writer, int id, Assembly assembly)\r
+               public int WriteAssembly (BinaryWriter writer, Assembly assembly)\r
                {\r
+                       if (assembly == ObjectWriter.CorlibAssembly) return -1;\r
+                       \r
+                       bool firstTime;\r
+                       int id = RegisterAssembly (assembly, out firstTime);\r
+                       if (!firstTime) return id;\r
+                                       \r
                        writer.Write ((byte) BinaryElement.Assembly);\r
                        writer.Write (id);\r
-                       writer.Write (assembly.GetName ().FullName);\r
+                       if (_assemblyFormat == FormatterAssemblyStyle.Full)\r
+                               writer.Write (assembly.GetName ().FullName);\r
+                       else\r
+                               writer.Write (assembly.GetName ().Name);\r
+                               \r
+                       return id;\r
                }\r
 \r
-               private int GetAssemblyId (Assembly assembly)\r
+               public int GetAssemblyId (Assembly assembly)\r
                {\r
                        return (int)_assemblyCache[assembly];\r
                }\r
@@ -583,7 +758,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
                                        break;\r
 \r
                                case TypeCode.Decimal:\r
-                                       writer.Write ((decimal) value);\r
+                                       writer.Write (((decimal) value).ToString (CultureInfo.InvariantCulture));\r
                                        break;\r
 \r
                                case TypeCode.Double:\r
@@ -660,7 +835,7 @@ namespace System.Runtime.Serialization.Formatters.Binary
                        else if (type.IsArray && type.GetArrayRank() == 1 && BinaryCommon.IsPrimitive(type.GetElementType())) {\r
                                return TypeTag.ArrayOfPrimitiveType;\r
                        }\r
-                       else if (type.Assembly == _corlibAssembly) {\r
+                       else if (type.Assembly == CorlibAssembly) {\r
                                return TypeTag.RuntimeType;\r
                        }\r
                        else\r
@@ -669,6 +844,8 @@ namespace System.Runtime.Serialization.Formatters.Binary
 \r
                public void WriteTypeSpec (BinaryWriter writer, Type type)\r
                {\r
+                       // WARNING Keep in sync with EmitWriteTypeSpec\r
+                       \r
                        switch (GetTypeTag (type))\r
                        {\r
                                case TypeTag.PrimitiveType:\r