Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

995 lines
28 KiB
C#

// ObjectReader.cs
//
// Author:
// Lluis Sanchez Gual (lluis@ideary.com)
// Patrik Torstensson
//
// (C) 2003 Lluis Sanchez Gual
//
// 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.
//
using System;
using System.Runtime.Serialization;
using System.IO;
using System.Collections;
using System.Reflection;
using System.Runtime.Remoting.Messaging;
using System.Globalization;
namespace System.Runtime.Serialization.Formatters.Binary
{
internal class ObjectReader
{
// BinaryFormatter _formatter;
ISurrogateSelector _surrogateSelector;
StreamingContext _context;
SerializationBinder _binder;
TypeFilterLevel _filterLevel;
ObjectManager _manager;
Hashtable _registeredAssemblies = new Hashtable();
Hashtable _typeMetadataCache = new Hashtable();
object _lastObject = null;
long _lastObjectID = 0;
long _rootObjectID = 0;
byte[] arrayBuffer;
int ArrayBufferLength = 4096;
class TypeMetadata
{
public Type Type;
public Type[] MemberTypes;
public string[] MemberNames;
public MemberInfo[] MemberInfos;
public int FieldCount;
public bool NeedsSerializationInfo;
}
class ArrayNullFiller
{
public ArrayNullFiller(int count) { NullCount = count; }
public int NullCount;
}
public ObjectReader (BinaryFormatter formatter)
{
// _formatter = formatter;
_surrogateSelector = formatter.SurrogateSelector;
_context = formatter.Context;
_binder = formatter.Binder;
_manager = new ObjectManager (_surrogateSelector, _context);
_filterLevel = formatter.FilterLevel;
}
public void ReadObjectGraph (BinaryReader reader, bool readHeaders, out object result, out Header[] headers)
{
BinaryElement elem = (BinaryElement)reader.ReadByte ();
ReadObjectGraph (elem, reader, readHeaders, out result, out headers);
}
public void ReadObjectGraph (BinaryElement elem, BinaryReader reader, bool readHeaders, out object result, out Header[] headers)
{
headers = null;
// Reads the objects. The first object in the stream is the
// root object.
bool next = ReadNextObject (elem, reader);
if (next) {
do {
if (readHeaders && (headers == null))
headers = (Header[])CurrentObject;
else
if (_rootObjectID == 0) _rootObjectID = _lastObjectID;
} while (ReadNextObject (reader));
}
result = _manager.GetObject (_rootObjectID);
}
bool ReadNextObject (BinaryElement element, BinaryReader reader)
{
if (element == BinaryElement.End)
{
_manager.DoFixups();
_manager.RaiseDeserializationEvent();
return false;
}
SerializationInfo info;
long objectId;
ReadObject (element, reader, out objectId, out _lastObject, out info);
if (objectId != 0) {
RegisterObject (objectId, _lastObject, info, 0, null, null);
_lastObjectID = objectId;
}
return true;
}
public bool ReadNextObject (BinaryReader reader)
{
BinaryElement element = (BinaryElement)reader.ReadByte ();
if (element == BinaryElement.End)
{
_manager.DoFixups();
_manager.RaiseDeserializationEvent();
return false;
}
SerializationInfo info;
long objectId;
ReadObject (element, reader, out objectId, out _lastObject, out info);
if (objectId != 0) {
RegisterObject (objectId, _lastObject, info, 0, null, null);
_lastObjectID = objectId;
}
return true;
}
public object CurrentObject
{
get { return _lastObject; }
}
// Reads an object from the stream. The object is registered in the ObjectManager.
// The result can be either the object instance
// or the id of the object (when what is found in the stream is an object reference).
// If an object instance is read, the objectId is set to 0.
private void ReadObject (BinaryElement element, BinaryReader reader, out long objectId, out object value, out SerializationInfo info)
{
switch (element)
{
case BinaryElement.RefTypeObject:
ReadRefTypeObjectInstance (reader, out objectId, out value, out info);
break;
case BinaryElement.UntypedRuntimeObject:
ReadObjectInstance (reader, true, false, out objectId, out value, out info);
break;
case BinaryElement.UntypedExternalObject:
ReadObjectInstance (reader, false, false, out objectId, out value, out info);
break;
case BinaryElement.RuntimeObject:
ReadObjectInstance (reader, true, true, out objectId, out value, out info);
break;
case BinaryElement.ExternalObject:
ReadObjectInstance (reader, false, true, out objectId, out value, out info);
break;
case BinaryElement.String:
info = null;
ReadStringIntance (reader, out objectId, out value);
break;
case BinaryElement.GenericArray:
info = null;
ReadGenericArray (reader, out objectId, out value);
break;
case BinaryElement.BoxedPrimitiveTypeValue:
value = ReadBoxedPrimitiveTypeValue (reader);
objectId = 0;
info = null;
break;
case BinaryElement.NullValue:
value = null;
objectId = 0;
info = null;
break;
case BinaryElement.Assembly:
ReadAssembly (reader);
ReadObject ((BinaryElement)reader.ReadByte (), reader, out objectId, out value, out info);
break;
case BinaryElement.ArrayFiller8b:
value = new ArrayNullFiller(reader.ReadByte());
objectId = 0;
info = null;
break;
case BinaryElement.ArrayFiller32b:
value = new ArrayNullFiller(reader.ReadInt32());
objectId = 0;
info = null;
break;
case BinaryElement.ArrayOfPrimitiveType:
ReadArrayOfPrimitiveType (reader, out objectId, out value);
info = null;
break;
case BinaryElement.ArrayOfObject:
ReadArrayOfObject (reader, out objectId, out value);
info = null;
break;
case BinaryElement.ArrayOfString:
ReadArrayOfString (reader, out objectId, out value);
info = null;
break;
default:
throw new SerializationException ("Unexpected binary element: " + (int)element);
}
}
private void ReadAssembly (BinaryReader reader)
{
long id = (long) reader.ReadUInt32 ();
string assemblyName = reader.ReadString ();
_registeredAssemblies [id] = assemblyName;
}
private void ReadObjectInstance (BinaryReader reader, bool isRuntimeObject, bool hasTypeInfo, out long objectId, out object value, out SerializationInfo info)
{
objectId = (long) reader.ReadUInt32 ();
TypeMetadata metadata = ReadTypeMetadata (reader, isRuntimeObject, hasTypeInfo);
ReadObjectContent (reader, metadata, objectId, out value, out info);
}
private void ReadRefTypeObjectInstance (BinaryReader reader, out long objectId, out object value, out SerializationInfo info)
{
objectId = (long) reader.ReadUInt32 ();
long refTypeObjectId = (long) reader.ReadUInt32 ();
// Gets the type of the referred object and its metadata
object refObj = _manager.GetObject (refTypeObjectId);
if (refObj == null) throw new SerializationException ("Invalid binary format");
TypeMetadata metadata = (TypeMetadata)_typeMetadataCache [refObj.GetType()];
ReadObjectContent (reader, metadata, objectId, out value, out info);
}
private void ReadObjectContent (BinaryReader reader, TypeMetadata metadata, long objectId, out object objectInstance, out SerializationInfo info)
{
if (_filterLevel == TypeFilterLevel.Low)
objectInstance = FormatterServices.GetSafeUninitializedObject (metadata.Type);
else
objectInstance = FormatterServices.GetUninitializedObject (metadata.Type);
_manager.RaiseOnDeserializingEvent (objectInstance);
info = metadata.NeedsSerializationInfo ? new SerializationInfo(metadata.Type, new FormatterConverter()) : null;
if (metadata.MemberNames != null) {
for (int n=0; n<metadata.FieldCount; n++)
ReadValue (reader, objectInstance, objectId, info, metadata.MemberTypes[n], metadata.MemberNames[n], null, null);
} else
for (int n=0; n<metadata.FieldCount; n++) {
if (metadata.MemberInfos [n] != null)
ReadValue (reader, objectInstance, objectId, info, metadata.MemberTypes[n], metadata.MemberInfos[n].Name, metadata.MemberInfos[n], null);
else if (BinaryCommon.IsPrimitive(metadata.MemberTypes[n])) {
// Since the member info is null, the type in this
// domain does not have this type. Even though we
// are not going to store the value, we will read
// it from the stream so that we can advance to the
// next block.
ReadPrimitiveTypeValue (reader, metadata.MemberTypes[n]);
}
}
}
private void RegisterObject (long objectId, object objectInstance, SerializationInfo info, long parentObjectId, MemberInfo parentObjectMemeber, int[] indices)
{
if (parentObjectId == 0) indices = null;
if (!objectInstance.GetType().IsValueType || parentObjectId == 0)
_manager.RegisterObject (objectInstance, objectId, info, 0, null, null);
else
{
if (indices != null) indices = (int[])indices.Clone();
_manager.RegisterObject (objectInstance, objectId, info, parentObjectId, parentObjectMemeber, indices);
}
}
private void ReadStringIntance (BinaryReader reader, out long objectId, out object value)
{
objectId = (long) reader.ReadUInt32 ();
value = reader.ReadString ();
}
private void ReadGenericArray (BinaryReader reader, out long objectId, out object val)
{
objectId = (long) reader.ReadUInt32 ();
// Array structure
reader.ReadByte();
int rank = reader.ReadInt32();
bool emptyDim = false;
int[] lengths = new int[rank];
for (int n=0; n<rank; n++)
{
lengths[n] = reader.ReadInt32();
if (lengths[n] == 0) emptyDim = true;
}
TypeTag code = (TypeTag) reader.ReadByte ();
Type elementType = ReadType (reader, code);
Array array = Array.CreateInstance (elementType, lengths);
if (emptyDim)
{
val = array;
return;
}
int[] indices = new int[rank];
// Initialize indexes
for (int dim = rank-1; dim >= 0; dim--)
indices[dim] = array.GetLowerBound (dim);
bool end = false;
while (!end)
{
ReadValue (reader, array, objectId, null, elementType, null, null, 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;
}
}
val = array;
}
private object ReadBoxedPrimitiveTypeValue (BinaryReader reader)
{
Type type = ReadType (reader, TypeTag.PrimitiveType);
return ReadPrimitiveTypeValue (reader, type);
}
private void ReadArrayOfPrimitiveType (BinaryReader reader, out long objectId, out object val)
{
objectId = (long) reader.ReadUInt32 ();
int length = reader.ReadInt32 ();
Type elementType = ReadType (reader, TypeTag.PrimitiveType);
switch (Type.GetTypeCode (elementType))
{
case TypeCode.Boolean: {
bool[] arr = new bool [length];
for (int n = 0; n < length; n++) arr [n] = reader.ReadBoolean();
val = arr;
break;
}
case TypeCode.Byte: {
byte[] arr = new byte [length];
int pos = 0;
while (pos < length) {
int nr = reader.Read (arr, pos, length - pos);
if (nr == 0) break;
pos += nr;
}
val = arr;
break;
}
case TypeCode.Char: {
char[] arr = new char [length];
int pos = 0;
while (pos < length) {
int nr = reader.Read (arr, pos, length - pos);
if (nr == 0) break;
pos += nr;
}
val = arr;
break;
}
case TypeCode.DateTime: {
DateTime[] arr = new DateTime [length];
for (int n = 0; n < length; n++) {
arr [n] = DateTime.FromBinary (reader.ReadInt64 ());
}
val = arr;
break;
}
case TypeCode.Decimal: {
Decimal[] arr = new Decimal [length];
for (int n = 0; n < length; n++) arr [n] = reader.ReadDecimal();
val = arr;
break;
}
case TypeCode.Double: {
Double[] arr = new Double [length];
if (length > 2)
BlockRead (reader, arr, 8);
else
for (int n = 0; n < length; n++) arr [n] = reader.ReadDouble();
val = arr;
break;
}
case TypeCode.Int16: {
short[] arr = new short [length];
if (length > 2)
BlockRead (reader, arr, 2);
else
for (int n = 0; n < length; n++) arr [n] = reader.ReadInt16();
val = arr;
break;
}
case TypeCode.Int32: {
int[] arr = new int [length];
if (length > 2)
BlockRead (reader, arr, 4);
else
for (int n = 0; n < length; n++) arr [n] = reader.ReadInt32();
val = arr;
break;
}
case TypeCode.Int64: {
long[] arr = new long [length];
if (length > 2)
BlockRead (reader, arr, 8);
else
for (int n = 0; n < length; n++) arr [n] = reader.ReadInt64();
val = arr;
break;
}
case TypeCode.SByte: {
sbyte[] arr = new sbyte [length];
if (length > 2)
BlockRead (reader, arr, 1);
else
for (int n = 0; n < length; n++) arr [n] = reader.ReadSByte();
val = arr;
break;
}
case TypeCode.Single: {
float[] arr = new float [length];
if (length > 2)
BlockRead (reader, arr, 4);
else
for (int n = 0; n < length; n++) arr [n] = reader.ReadSingle();
val = arr;
break;
}
case TypeCode.UInt16: {
ushort[] arr = new ushort [length];
if (length > 2)
BlockRead (reader, arr, 2);
else
for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt16();
val = arr;
break;
}
case TypeCode.UInt32: {
uint[] arr = new uint [length];
if (length > 2)
BlockRead (reader, arr, 4);
else
for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt32();
val = arr;
break;
}
case TypeCode.UInt64: {
ulong[] arr = new ulong [length];
if (length > 2)
BlockRead (reader, arr, 8);
else
for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt64();
val = arr;
break;
}
case TypeCode.String: {
string[] arr = new string [length];
for (int n = 0; n < length; n++) arr [n] = reader.ReadString();
val = arr;
break;
}
default: {
if (elementType == typeof(TimeSpan)) {
TimeSpan[] arr = new TimeSpan [length];
for (int n = 0; n < length; n++) arr [n] = new TimeSpan (reader.ReadInt64 ());
val = arr;
}
else
throw new NotSupportedException ("Unsupported primitive type: " + elementType.FullName);
break;
}
}
}
private void BlockRead (BinaryReader reader, Array array, int dataSize)
{
int totalSize = Buffer.ByteLength (array);
if (arrayBuffer == null || (totalSize > arrayBuffer.Length && arrayBuffer.Length != ArrayBufferLength))
arrayBuffer = new byte [totalSize <= ArrayBufferLength ? totalSize : ArrayBufferLength];
int pos = 0;
while (totalSize > 0) {
int size = totalSize < arrayBuffer.Length ? totalSize : arrayBuffer.Length;
int ap = 0;
do {
int nr = reader.Read (arrayBuffer, ap, size - ap);
if (nr == 0) break;
ap += nr;
} while (ap < size);
if (!BitConverter.IsLittleEndian && dataSize > 1)
BinaryCommon.SwapBytes (arrayBuffer, size, dataSize);
Buffer.BlockCopy (arrayBuffer, 0, array, pos, size);
totalSize -= size;
pos += size;
}
}
private void ReadArrayOfObject (BinaryReader reader, out long objectId, out object array)
{
ReadSimpleArray (reader, typeof (object), out objectId, out array);
}
private void ReadArrayOfString (BinaryReader reader, out long objectId, out object array)
{
ReadSimpleArray (reader, typeof (string), out objectId, out array);
}
private void ReadSimpleArray (BinaryReader reader, Type elementType, out long objectId, out object val)
{
objectId = (long) reader.ReadUInt32 ();
int length = reader.ReadInt32 ();
int[] indices = new int[1];
Array array = Array.CreateInstance (elementType, length);
for (int n = 0; n < length; n++)
{
indices[0] = n;
ReadValue (reader, array, objectId, null, elementType, null, null, indices);
n = indices[0];
}
val = array;
}
private TypeMetadata ReadTypeMetadata (BinaryReader reader, bool isRuntimeObject, bool hasTypeInfo)
{
TypeMetadata metadata = new TypeMetadata();
string className = reader.ReadString ();
int fieldCount = reader.ReadInt32 ();
Type[] types = new Type[fieldCount];
string[] names = new string[fieldCount];
for (int n=0; n<fieldCount; n++)
names [n] = reader.ReadString ();
if (hasTypeInfo)
{
TypeTag[] codes = new TypeTag[fieldCount];
for (int n=0; n<fieldCount; n++)
codes [n] = (TypeTag) reader.ReadByte ();
for (int n=0; n<fieldCount; n++) {
Type t = ReadType (reader, codes[n], false);
// The field's type could not be resolved: assume it is an object.
if (t == null)
t = typeof (object);
types [n] = t;
}
}
// Gets the type
if (!isRuntimeObject)
{
long assemblyId = (long)reader.ReadUInt32();
metadata.Type = GetDeserializationType (assemblyId, className);
}
else
metadata.Type = Type.GetType (className, true);
metadata.MemberTypes = types;
metadata.MemberNames = names;
metadata.FieldCount = names.Length;
// Now check if this objects needs a SerializationInfo struct for deserialziation.
// SerializationInfo is needed if the object has to be deserialized using
// a serialization surrogate, or if it implements ISerializable.
if (_surrogateSelector != null)
{
// check if the surrogate selector handles objects of the given type.
ISurrogateSelector selector;
ISerializationSurrogate surrogate = _surrogateSelector.GetSurrogate (metadata.Type, _context, out selector);
metadata.NeedsSerializationInfo = (surrogate != null);
}
if (!metadata.NeedsSerializationInfo)
{
// Check if the object is marked with the Serializable attribute
if (!metadata.Type.IsSerializable)
throw new SerializationException("Serializable objects must be marked with the Serializable attribute");
metadata.NeedsSerializationInfo = typeof (ISerializable).IsAssignableFrom (metadata.Type);
if (!metadata.NeedsSerializationInfo)
{
metadata.MemberInfos = new MemberInfo [fieldCount];
for (int n=0; n<fieldCount; n++)
{
FieldInfo field = null;
string memberName = names[n];
int i = memberName.IndexOf ('+');
if (i != -1) {
string baseTypeName = names[n].Substring (0,i);
memberName = names[n].Substring (i+1);
Type t = metadata.Type.BaseType;
while (t != null) {
if (t.Name == baseTypeName) {
field = t.GetField (memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
break;
}
else
t = t.BaseType;
}
}
else
field = metadata.Type.GetField (memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (field != null)
metadata.MemberInfos [n] = field;
if (!hasTypeInfo) {
types [n] = field.FieldType;
}
}
metadata.MemberNames = null; // Info now in MemberInfos
}
}
// Registers the type's metadata so it can be reused later if
// a RefTypeObject element is found
if (!_typeMetadataCache.ContainsKey (metadata.Type))
_typeMetadataCache [metadata.Type] = metadata;
return metadata;
}
// Called for primitive types
static bool IsGeneric (MemberInfo minfo)
{
if (minfo == null)
return false;
Type mtype = null;
switch (minfo.MemberType) {
case MemberTypes.Field:
mtype = ((FieldInfo) minfo).FieldType;
break;
default:
throw new NotSupportedException ("Not supported: " + minfo.MemberType);
}
return (mtype != null && mtype.IsGenericType);
}
private void ReadValue (BinaryReader reader, object parentObject, long parentObjectId, SerializationInfo info, Type valueType, string fieldName, MemberInfo memberInfo, int[] indices)
{
// Reads a value from the stream and assigns it to the member of an object
object val;
if (BinaryCommon.IsPrimitive (valueType) && !IsGeneric (memberInfo))
{
val = ReadPrimitiveTypeValue (reader, valueType);
SetObjectValue (parentObject, fieldName, memberInfo, info, val, valueType, indices);
return;
}
// Gets the object
BinaryElement element = (BinaryElement)reader.ReadByte ();
if (element == BinaryElement.ObjectReference)
{
// Just read the id of the referred object and record a fixup
long childObjectId = (long) reader.ReadUInt32();
RecordFixup (parentObjectId, childObjectId, parentObject, info, fieldName, memberInfo, indices);
return;
}
long objectId;
SerializationInfo objectInfo;
ReadObject (element, reader, out objectId, out val, out objectInfo);
// There are two cases where the object cannot be assigned to the parent
// and a fixup must be used:
// 1) When what has been read is not an object, but an id of an object that
// has not been read yet (an object reference). This is managed in the
// previous block of code.
// 2) When the read object is a value type object. Value type fields hold
// copies of objects, not references. Thus, if the value object that
// has been read has pending fixups, those fixups would be made to the
// boxed copy in the ObjectManager, and not in the required object instance
// First of all register the fixup, and then the object. ObjectManager is more
// efficient if done in this order
bool hasFixup = false;
if (objectId != 0)
{
if (val.GetType().IsValueType)
{
RecordFixup (parentObjectId, objectId, parentObject, info, fieldName, memberInfo, indices);
hasFixup = true;
}
// Register the value
if (info == null && !(parentObject is Array))
RegisterObject (objectId, val, objectInfo, parentObjectId, memberInfo, null);
else
RegisterObject (objectId, val, objectInfo, parentObjectId, null, indices);
}
// Assign the value to the parent object, unless there is a fixup
if (!hasFixup)
SetObjectValue (parentObject, fieldName, memberInfo, info, val, valueType, indices);
}
private void SetObjectValue (object parentObject, string fieldName, MemberInfo memberInfo, SerializationInfo info, object value, Type valueType, int[] indices)
{
if (value is IObjectReference)
value = ((IObjectReference)value).GetRealObject (_context);
if (parentObject is Array)
{
if (value is ArrayNullFiller)
{
// It must be a single dimension array of objects.
// Just increase the index. Elements are null by default.
int count = ((ArrayNullFiller)value).NullCount;
indices[0] += count - 1;
}
else
((Array)parentObject).SetValue (value, indices);
}
else if (info != null) {
info.AddValue (fieldName, value, valueType);
}
else {
if (memberInfo is FieldInfo)
((FieldInfo)memberInfo).SetValue (parentObject, value);
else
((PropertyInfo)memberInfo).SetValue (parentObject, value, null);
}
}
private void RecordFixup (long parentObjectId, long childObjectId, object parentObject, SerializationInfo info, string fieldName, MemberInfo memberInfo, int[] indices)
{
if (info != null) {
_manager.RecordDelayedFixup (parentObjectId, fieldName, childObjectId);
}
else if (parentObject is Array) {
if (indices.Length == 1)
_manager.RecordArrayElementFixup (parentObjectId, indices[0], childObjectId);
else
_manager.RecordArrayElementFixup (parentObjectId, (int[])indices.Clone(), childObjectId);
}
else {
_manager.RecordFixup (parentObjectId, memberInfo, childObjectId);
}
}
private Type GetDeserializationType (long assemblyId, string className)
{
return GetDeserializationType (assemblyId, className, true);
}
private Type GetDeserializationType (long assemblyId, string className, bool throwOnError)
{
Type t;
string assemblyName = (string)_registeredAssemblies[assemblyId];
if (_binder != null) {
t = _binder.BindToType (assemblyName, className);
if (t != null)
return t;
}
Assembly assembly;
try {
assembly = Assembly.Load (assemblyName);
} catch (Exception ex) {
if (!throwOnError)
return null;
throw new SerializationException (String.Format ("Couldn't find assembly '{0}'", assemblyName), ex);
}
t = assembly.GetType (className);
if (t != null)
return t;
if (!throwOnError)
return null;
throw new SerializationException (String.Format ("Couldn't find type '{0}' in assembly '{1}'", className, assemblyName));
}
public Type ReadType (BinaryReader reader, TypeTag code)
{
return ReadType (reader, code, true);
}
public Type ReadType (BinaryReader reader, TypeTag code, bool throwOnError)
{
switch (code)
{
case TypeTag.PrimitiveType:
return BinaryCommon.GetTypeFromCode (reader.ReadByte());
case TypeTag.String:
return typeof(string);
case TypeTag.ObjectType:
return typeof(object);
case TypeTag.RuntimeType:
{
string name = reader.ReadString ();
// map MS.NET's System.RuntimeType to System.MonoType
if (_context.State == StreamingContextStates.Remoting)
if (name == "System.RuntimeType")
return typeof (MonoType);
else if (name == "System.RuntimeType[]")
return typeof (MonoType[]);
Type t = Type.GetType (name);
if (t != null)
return t;
throw new SerializationException (String.Format ("Could not find type '{0}'.", name));
}
case TypeTag.GenericType:
{
string name = reader.ReadString ();
long asmid = (long) reader.ReadUInt32();
return GetDeserializationType (asmid, name, throwOnError);
}
case TypeTag.ArrayOfObject:
return typeof(object[]);
case TypeTag.ArrayOfString:
return typeof(string[]);
case TypeTag.ArrayOfPrimitiveType:
Type elementType = BinaryCommon.GetTypeFromCode (reader.ReadByte());
return Type.GetType(elementType.FullName + "[]");
default:
throw new NotSupportedException ("Unknow type tag");
}
}
public static object ReadPrimitiveTypeValue (BinaryReader reader, Type type)
{
if (type == null) return null;
switch (Type.GetTypeCode (type))
{
case TypeCode.Boolean:
return reader.ReadBoolean();
case TypeCode.Byte:
return reader.ReadByte();
case TypeCode.Char:
return reader.ReadChar();
case TypeCode.DateTime:
return DateTime.FromBinary (reader.ReadInt64());
case TypeCode.Decimal:
return Decimal.Parse (reader.ReadString(), CultureInfo.InvariantCulture);
case TypeCode.Double:
return reader.ReadDouble();
case TypeCode.Int16:
return reader.ReadInt16();
case TypeCode.Int32:
return reader.ReadInt32();
case TypeCode.Int64:
return reader.ReadInt64();
case TypeCode.SByte:
return reader.ReadSByte();
case TypeCode.Single:
return reader.ReadSingle();
case TypeCode.UInt16:
return reader.ReadUInt16();
case TypeCode.UInt32:
return reader.ReadUInt32();
case TypeCode.UInt64:
return reader.ReadUInt64();
case TypeCode.String:
return reader.ReadString();
default:
if (type == typeof(TimeSpan))
return new TimeSpan (reader.ReadInt64 ());
else
throw new NotSupportedException ("Unsupported primitive type: " + type.FullName);
}
}
}
}