-// ObjectReader.cs
+// ObjectReader.cs\r
+//\r
+// Author:\r
+// Lluis Sanchez Gual (lluis@ideary.com)\r
+// Patrik Torstensson\r
+//\r
+// (C) 2003 Lluis Sanchez Gual\r
+
//
-// 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
-\r
-// FIXME: Implement the missing binary elements\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
- public class ObjectReader\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
- static Type[] _typeCodes;\r
+ object _lastObject = null;\r
+ long _lastObjectID = 0;\r
+ long _rootObjectID = 0;\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
public int NullCount;\r
}\r
\r
- static ObjectReader()\r
+ public ObjectReader (BinaryFormatter formatter)\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
+ _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 ObjectReader(ISurrogateSelector surrogateSelector, StreamingContext context)\r
+ public void ReadObjectGraph (BinaryReader reader, bool readHeaders, out object result, out Header[] headers)\r
{\r
- _manager = new ObjectManager (surrogateSelector, context);\r
- _surrogateSelector = surrogateSelector;\r
- _context = context;\r
- }\r
-\r
- public object ReadObjectGraph (BinaryReader reader)\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
+\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
ReadGenericArray (reader, out objectId, out value);\r
break;\r
\r
+\r
case BinaryElement.BoxedPrimitiveTypeValue:\r
value = ReadBoxedPrimitiveTypeValue (reader);\r
objectId = 0;\r
{\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
\r
private void ReadObjectContent (BinaryReader reader, TypeMetadata metadata, long objectId, out object objectInstance, out SerializationInfo info)\r
{\r
- objectInstance = FormatterServices.GetUninitializedObject (metadata.Type);\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
+ \r
info = metadata.NeedsSerializationInfo ? new SerializationInfo(metadata.Type, new FormatterConverter()) : null;\r
\r
- for (int n=0; n<metadata.FieldCount; n++)\r
- ReadValue (reader, objectInstance, objectId, info, metadata.MemberTypes[n], metadata.MemberNames[n], null);\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, 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
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
bool end = false;\r
while (!end)\r
{\r
- ReadValue (reader, array, objectId, null, elementType, null, indices);\r
+ ReadValue (reader, array, objectId, null, elementType, null, null, indices);\r
\r
for (int dim = array.Rank-1; dim >= 0; dim--)\r
{\r
for (int n = 0; n < length; n++)\r
{\r
indices[0] = n;\r
- ReadValue (reader, array, objectId, null, elementType, null, indices);\r
+ ReadValue (reader, array, objectId, null, elementType, null, null, indices);\r
n = indices[0];\r
}\r
val = array;\r
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
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
+ MemberInfo[] members = 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
+ members = t.GetMember (memberName, MemberTypes.Field | MemberTypes.Property, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\r
+ break;\r
+ }\r
+ else\r
+ t = t.BaseType;\r
+ }\r
+ }\r
+ else\r
+ members = metadata.Type.GetMember (memberName, MemberTypes.Field | MemberTypes.Property, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\r
+ \r
+ if (members == null || members.Length == 0) throw new SerializationException ("Field \"" + names[n] + "\" not found in class " + metadata.Type.FullName);\r
+ if (members.Length > 1) throw new SerializationException ("There are two public members named \"" + names[n] + "\" in the class hirearchy of " + metadata.Type.FullName);\r
+ metadata.MemberInfos [n] = members[0];\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
}\r
\r
\r
- private void ReadValue (BinaryReader reader, object parentObject, long parentObjectId, SerializationInfo info, Type valueType, string fieldName, int[] indices)\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
if (BinaryCommon.IsPrimitive (valueType))\r
{\r
val = ReadPrimitiveTypeValue (reader, valueType);\r
- SetObjectValue (parentObject, fieldName, info, val, valueType, indices);\r
+ SetObjectValue (parentObject, fieldName, memberInfo, info, val, valueType, indices);\r
return;\r
}\r
\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, indices);\r
+ RecordFixup (parentObjectId, childObjectId, parentObject, info, fieldName, memberInfo, indices);\r
return;\r
}\r
\r
{\r
if (val.GetType().IsValueType)\r
{\r
- RecordFixup (parentObjectId, objectId, parentObject, info, fieldName, indices);\r
+ RecordFixup (parentObjectId, objectId, parentObject, info, fieldName, memberInfo, indices);\r
hasFixup = true;\r
}\r
\r
// Register the value\r
\r
- if (info == null && !parentObject.GetType().IsArray)\r
- RegisterObject (objectId, val, objectInfo, parentObjectId, GetObjectMember(parentObject, fieldName), null);\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, info, val, valueType, indices);\r
+ SetObjectValue (parentObject, fieldName, memberInfo, info, val, valueType, indices);\r
}\r
\r
- private void SetObjectValue (object parentObject, string fieldName, SerializationInfo info, object value, Type valueType, int[] indices)\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.GetType().IsArray) \r
+ if (parentObject is Array) \r
{\r
if (value is ArrayNullFiller) \r
{\r
info.AddValue (fieldName, value, valueType);\r
}\r
else {\r
- MemberInfo member = GetObjectMember(parentObject, fieldName);\r
- if (member is FieldInfo)\r
- ((FieldInfo)member).SetValue (parentObject, value);\r
+ if (memberInfo is FieldInfo)\r
+ ((FieldInfo)memberInfo).SetValue (parentObject, value);\r
else\r
- ((PropertyInfo)member).SetValue (parentObject, value, null);\r
+ ((PropertyInfo)memberInfo).SetValue (parentObject, value, null);\r
}\r
}\r
\r
- private void RecordFixup (long parentObjectId, long childObjectId, object parentObject, SerializationInfo info, string fieldName, int[] indices)\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.GetType().IsArray) {\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, GetObjectMember(parentObject, fieldName), childObjectId);\r
+ _manager.RecordFixup (parentObjectId, memberInfo, childObjectId);\r
}\r
}\r
\r
- private MemberInfo GetObjectMember (object parentObject, string fieldName)\r
+ private Type GetDeserializationType (long assemblyId, string className)\r
{\r
- MemberInfo[] members = parentObject.GetType().GetMember (fieldName, MemberTypes.Field | MemberTypes.Property, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\r
- if (members.Length > 1) throw new SerializationException ("There are two public members named \"" + fieldName + "\" in the class hirearchy of " + parentObject.GetType().FullName);\r
- if (members.Length == 0) throw new SerializationException ("Field \"" + fieldName + "\" not found in class " + parentObject.GetType().FullName);\r
- return members[0];\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
- private Type ReadType (BinaryReader reader, TypeTag code)\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
{\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
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
}\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
return reader.ReadChar();\r
\r
case TypeCode.DateTime: \r
- long ticks = reader.ReadInt64();\r
- return new DateTime (ticks);\r
+ return new DateTime (reader.ReadInt64());\r
\r
case TypeCode.Decimal:\r
- return reader.ReadDecimal();\r
+ return Decimal.Parse (reader.ReadString(), CultureInfo.InvariantCulture);\r
\r
case TypeCode.Double:\r
return reader.ReadDouble();\r
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
+ 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
+}