X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2Fcorlib%2FSystem.Runtime.Serialization.Formatters.Binary%2FObjectWriter.cs;h=b21a617bb341c0dcd41457df68ac35331eb246be;hb=9e3370d3351358044231dd1f3df5fff3720bdcc2;hp=887b06158bd050cc3caa530f742100eb136b5755;hpb=23cb51f8602a619142604838ebf43877103a117b;p=mono.git diff --git a/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectWriter.cs b/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectWriter.cs index 887b06158bd..b21a617bb34 100644 --- a/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectWriter.cs +++ b/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectWriter.cs @@ -1,103 +1,288 @@ -// ObjectWriter.cs +// ObjectWriter.cs +// +// Author: +// Lluis Sanchez Gual (lluis@ideary.com) +// +// (C) 2003 Lluis Sanchez Gual + // -// Author: -// Lluis Sanchez Gual (lsg@ctv.es) +// 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. // -// (C) 2003 Lluis Sanchez Gual - -// FIXME: Implement the missing binary elements using System; using System.IO; using System.Collections; using System.Runtime.Serialization; +using System.Runtime.Remoting.Messaging; using System.Reflection; +using System.Globalization; namespace System.Runtime.Serialization.Formatters.Binary { + abstract class TypeMetadata + { + public TypeMetadata (Type instanceType) + { + InstanceType = instanceType; + TypeAssembly = instanceType.Assembly; + } + + public Assembly TypeAssembly; + public Type InstanceType; + + public abstract void WriteAssemblies (ObjectWriter ow, BinaryWriter writer); + public abstract void WriteTypeData (ObjectWriter ow, BinaryWriter writer); + public abstract void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data); + + public virtual bool IsCompatible (TypeMetadata other) + { + return true; + } + } + + class SerializableTypeMetadata: TypeMetadata + { + Type[] types; + string[] names; + + public SerializableTypeMetadata (Type itype, SerializationInfo info): base (itype) + { + types = new Type [info.MemberCount]; + names = new string [info.MemberCount]; + + SerializationInfoEnumerator e = info.GetEnumerator (); + + int n = 0; + while (e.MoveNext ()) + { + types[n] = e.ObjectType; + names[n] = e.Name; + n++; + } + + if (info.FullTypeName != InstanceType.FullName || info.AssemblyName != TypeAssembly.FullName) + { + TypeAssembly = Assembly.Load (info.AssemblyName); + InstanceType = TypeAssembly.GetType (info.FullTypeName); + } + } + + public override bool IsCompatible (TypeMetadata other) + { + if (!(other is SerializableTypeMetadata)) return false; + + SerializableTypeMetadata tm = (SerializableTypeMetadata)other; + if (types.Length != tm.types.Length) return false; + if (TypeAssembly != tm.TypeAssembly) return false; + if (InstanceType != tm.InstanceType) return false; + for (int n=0; n 0) - WriteObjectInstance (writer, _pendingObjects.Dequeue()); + public void WriteQueuedObjects (BinaryWriter writer) + { - writer.Write ((byte) BinaryElement.End); + while (_pendingObjects.Count > 0) + WriteObjectInstance (writer, _pendingObjects.Dequeue(), false); } - public void WriteObjectInstance (BinaryWriter writer, object obj) + public void WriteObjectInstance (BinaryWriter writer, object obj, bool isValueObject) { bool firstTime; - long id = _idGenerator.GetId (obj, out firstTime); + long id; + + // If the object is a value type (not boxed) then there is no need + // to register it in the id generator, because it won't have other + // references to it - if (obj.GetType() == typeof(string)) { + if (isValueObject) id = _idGenerator.NextId; + else id = _idGenerator.GetId (obj, out firstTime); + + if (obj is string) { WriteString (writer, id, (string)obj); } - else if (obj.GetType().IsArray) { + else if (obj is Array) { WriteArray (writer, id, (Array)obj); } else WriteObject (writer, id, obj); } + public static void WriteSerializationEnd (BinaryWriter writer) + { + writer.Write ((byte) BinaryElement.End); + } + private void WriteObject (BinaryWriter writer, long id, object obj) { - object[] values; + object data; TypeMetadata metadata; - GetObjectData (obj, out metadata, out values); - - TypeMetadata chachedMetadata = (TypeMetadata)_cachedTypes[metadata.InstanceType]; + GetObjectData (obj, out metadata, out data); + MetadataReference metadataReference = (MetadataReference)_cachedMetadata [metadata.InstanceType]; - if (chachedMetadata != null && metadata.Equals(chachedMetadata)) + if (metadataReference != null && metadata.IsCompatible (metadataReference.Metadata)) { // An object of the same type has already been serialized // It is not necessary to write again type metadata @@ -105,24 +290,21 @@ namespace System.Runtime.Serialization.Formatters.Binary writer.Write ((byte) BinaryElement.RefTypeObject); writer.Write ((int)id); - // Get the id of the object that has the same type as this - long refId = chachedMetadata.ObjectID; - - writer.Write ((int)refId); - WriteObjectContent (writer, metadata.Types, values); + writer.Write ((int)metadataReference.ObjectID); + metadata.WriteObjectData (this, writer, data); return; } - if (chachedMetadata == null) + if (metadataReference == null) { - metadata.ObjectID = id; - _cachedTypes [metadata.InstanceType] = metadata; + metadataReference = new MetadataReference (metadata, id); + _cachedMetadata [metadata.InstanceType] = metadataReference; } BinaryElement objectTag; int assemblyId; - if (metadata.TypeAssembly == _corlibAssembly) + if (metadata.TypeAssembly == CorlibAssembly) { // A corlib type objectTag = BinaryElement.RuntimeObject; @@ -131,74 +313,30 @@ namespace System.Runtime.Serialization.Formatters.Binary else { objectTag = BinaryElement.ExternalObject; - - bool firstTime; - assemblyId = RegisterAssembly (metadata.TypeAssembly, out firstTime); - if (firstTime) WriteAssembly (writer, assemblyId, metadata.TypeAssembly); + assemblyId = WriteAssembly (writer, metadata.TypeAssembly); } // Registers the assemblies needed for each field // If there are assemblies that where not registered before this object, // write them now - foreach (object value in values) - { - if (value == null) continue; - - Type memberType = value.GetType(); - while (memberType.IsArray) - memberType = memberType.GetElementType(); - - if (memberType.Assembly != _corlibAssembly) - { - bool firstTime; - int aid = RegisterAssembly (memberType.Assembly, out firstTime); - if (firstTime) WriteAssembly (writer, aid, memberType.Assembly); - } - } + metadata.WriteAssemblies (this, writer); // Writes the object writer.Write ((byte) objectTag); writer.Write ((int)id); writer.Write (metadata.InstanceType.FullName); - WriteObjectMetadata (writer, metadata, assemblyId); - WriteObjectContent (writer, metadata.Types, values); - } - - private void WriteObjectMetadata (BinaryWriter writer, TypeMetadata metadata, int assemblyId) - { - Type[] types = metadata.Types; - string[] names = metadata.Names; - - writer.Write (types.Length); - - // Names of fields - foreach (string name in names) - writer.Write (name); - - // Types of fields - foreach (Type type in types) - WriteTypeCode (writer, type); - - // Type specs of fields - foreach (Type type in types) - WriteTypeSpec (writer, type); - + + metadata.WriteTypeData (this, writer); if (assemblyId != -1) writer.Write (assemblyId); + + metadata.WriteObjectData (this, writer, data); } - private void WriteObjectContent (BinaryWriter writer, Type[] types, object[] values) - { - for (int n=0; n= 0; dim--) - indices[dim] = array.GetLowerBound (dim); - - bool end = false; - while (!end) - { - WriteValue (writer, elementType, array.GetValue (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; - } - } + foreach (object item in array) + WriteValue (writer, elementType, item); } } @@ -409,16 +513,98 @@ namespace System.Runtime.Serialization.Formatters.Binary Type elementType = array.GetType().GetElementType(); WriteTypeSpec (writer, elementType); - for (int n=0; n 0) { WriteNullFiller (writer, numNulls); @@ -455,14 +641,16 @@ namespace System.Runtime.Serialization.Formatters.Binary private void WriteObjectReference (BinaryWriter writer, long id) { + writer.Write ((byte) BinaryElement.ObjectReference); writer.Write ((int)id); } - private void WriteValue (BinaryWriter writer, Type valueType, object val) + public void WriteValue (BinaryWriter writer, Type valueType, object val) { if (val == null) { + BinaryCommon.CheckSerializable (valueType, _surrogateSelector, _context); writer.Write ((byte) BinaryElement.NullValue); } else if (BinaryCommon.IsPrimitive(val.GetType())) @@ -478,15 +666,15 @@ namespace System.Runtime.Serialization.Formatters.Binary else if (valueType.IsValueType) { // Value types are written embedded in the containing object - WriteObjectInstance (writer, val); + WriteObjectInstance (writer, val, true); } - else if (val.GetType() == typeof(string)) + else if (val is string) { // Strings are written embedded, unless already registered bool firstTime; long id = _idGenerator.GetId (val, out firstTime); - if (firstTime) WriteObjectInstance (writer, val); + if (firstTime) WriteObjectInstance (writer, val, false); else WriteObjectReference (writer, id); } else @@ -509,14 +697,25 @@ namespace System.Runtime.Serialization.Formatters.Binary writer.Write (str); } - private void WriteAssembly (BinaryWriter writer, int id, Assembly assembly) + public int WriteAssembly (BinaryWriter writer, Assembly assembly) { + if (assembly == ObjectWriter.CorlibAssembly) return -1; + + bool firstTime; + int id = RegisterAssembly (assembly, out firstTime); + if (!firstTime) return id; + writer.Write ((byte) BinaryElement.Assembly); writer.Write (id); - writer.Write (assembly.GetName ().FullName); + if (_assemblyFormat == FormatterAssemblyStyle.Full) + writer.Write (assembly.GetName ().FullName); + else + writer.Write (assembly.GetName ().Name); + + return id; } - private int GetAssemblyId (Assembly assembly) + public int GetAssemblyId (Assembly assembly) { return (int)_assemblyCache[assembly]; } @@ -536,9 +735,11 @@ namespace System.Runtime.Serialization.Formatters.Binary } } - private void WritePrimitiveValue (BinaryWriter writer, object value) + public static void WritePrimitiveValue (BinaryWriter writer, object value) { - switch (Type.GetTypeCode (value.GetType())) + Type type = value.GetType(); + + switch (Type.GetTypeCode (type)) { case TypeCode.Boolean: writer.Write ((bool)value); @@ -557,7 +758,7 @@ namespace System.Runtime.Serialization.Formatters.Binary break; case TypeCode.Decimal: - writer.Write ((decimal) value); + writer.Write (((decimal) value).ToString (CultureInfo.InvariantCulture)); break; case TypeCode.Double: @@ -595,15 +796,26 @@ namespace System.Runtime.Serialization.Formatters.Binary case TypeCode.UInt64: writer.Write ((ulong) value); break; + + case TypeCode.String: + writer.Write ((string) value); + break; + + default: + if (type == typeof (TimeSpan)) + writer.Write (((TimeSpan)value).Ticks); + else + throw new NotSupportedException ("Unsupported primitive type: " + value.GetType().FullName); + break; } } - private void WriteTypeCode (BinaryWriter writer, Type type) + public static void WriteTypeCode (BinaryWriter writer, Type type) { writer.Write ((byte) GetTypeTag (type)); } - private TypeTag GetTypeTag (Type type) + public static TypeTag GetTypeTag (Type type) { if (type == typeof (string)) { return TypeTag.String; @@ -623,19 +835,21 @@ namespace System.Runtime.Serialization.Formatters.Binary else if (type.IsArray && type.GetArrayRank() == 1 && BinaryCommon.IsPrimitive(type.GetElementType())) { return TypeTag.ArrayOfPrimitiveType; } - else if (type.Assembly == _corlibAssembly) { + else if (type.Assembly == CorlibAssembly) { return TypeTag.RuntimeType; } else return TypeTag.GenericType; } - private void WriteTypeSpec (BinaryWriter writer, Type type) + public void WriteTypeSpec (BinaryWriter writer, Type type) { + // WARNING Keep in sync with EmitWriteTypeSpec + switch (GetTypeTag (type)) { case TypeTag.PrimitiveType: - writer.Write ((byte) (Type.GetTypeCode (type) - 1)); + writer.Write (BinaryCommon.GetTypeCode (type)); break; case TypeTag.RuntimeType: @@ -648,7 +862,7 @@ namespace System.Runtime.Serialization.Formatters.Binary break; case TypeTag.ArrayOfPrimitiveType: - writer.Write ((byte) (Type.GetTypeCode (type.GetElementType()) - 1)); + writer.Write (BinaryCommon.GetTypeCode (type.GetElementType())); break; default: