e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
532 lines
23 KiB
C#
532 lines
23 KiB
C#
//------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//------------------------------------------------------------
|
|
|
|
namespace System.Runtime.Serialization
|
|
{
|
|
using System;
|
|
using System.Collections;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Xml;
|
|
using DataContractDictionary = System.Collections.Generic.Dictionary<System.Xml.XmlQualifiedName, DataContract>;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.Serialization.Diagnostics.Application;
|
|
using System.Runtime.Serialization.Formatters;
|
|
using System.Security;
|
|
using System.Security.Permissions;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
#if USE_REFEMIT
|
|
public class XmlObjectSerializerReadContextComplex : XmlObjectSerializerReadContext
|
|
#else
|
|
internal class XmlObjectSerializerReadContextComplex : XmlObjectSerializerReadContext
|
|
#endif
|
|
{
|
|
static Hashtable dataContractTypeCache = new Hashtable();
|
|
|
|
bool preserveObjectReferences;
|
|
protected IDataContractSurrogate dataContractSurrogate;
|
|
SerializationMode mode;
|
|
SerializationBinder binder;
|
|
ISurrogateSelector surrogateSelector;
|
|
FormatterAssemblyStyle assemblyFormat;
|
|
Hashtable surrogateDataContracts;
|
|
|
|
internal XmlObjectSerializerReadContextComplex(DataContractSerializer serializer, DataContract rootTypeDataContract, DataContractResolver dataContractResolver)
|
|
: base(serializer, rootTypeDataContract, dataContractResolver)
|
|
{
|
|
this.mode = SerializationMode.SharedContract;
|
|
this.preserveObjectReferences = serializer.PreserveObjectReferences;
|
|
this.dataContractSurrogate = serializer.DataContractSurrogate;
|
|
}
|
|
|
|
internal XmlObjectSerializerReadContextComplex(NetDataContractSerializer serializer)
|
|
: base(serializer)
|
|
{
|
|
this.mode = SerializationMode.SharedType;
|
|
this.preserveObjectReferences = true;
|
|
this.binder = serializer.Binder;
|
|
this.surrogateSelector = serializer.SurrogateSelector;
|
|
this.assemblyFormat = serializer.AssemblyFormat;
|
|
}
|
|
|
|
internal XmlObjectSerializerReadContextComplex(XmlObjectSerializer serializer, int maxItemsInObjectGraph, StreamingContext streamingContext, bool ignoreExtensionDataObject)
|
|
: base(serializer, maxItemsInObjectGraph, streamingContext, ignoreExtensionDataObject)
|
|
{
|
|
}
|
|
|
|
internal override SerializationMode Mode
|
|
{
|
|
get { return mode; }
|
|
}
|
|
|
|
internal override DataContract GetDataContract(int id, RuntimeTypeHandle typeHandle)
|
|
{
|
|
DataContract dataContract = null;
|
|
if (mode == SerializationMode.SharedType && surrogateSelector != null)
|
|
{
|
|
dataContract = NetDataContractSerializer.GetDataContractFromSurrogateSelector(surrogateSelector, GetStreamingContext(), typeHandle, null /*type*/, ref surrogateDataContracts);
|
|
}
|
|
|
|
if (dataContract != null)
|
|
{
|
|
if (this.IsGetOnlyCollection && dataContract is SurrogateDataContract)
|
|
{
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.SurrogatesWithGetOnlyCollectionsNotSupportedSerDeser,
|
|
DataContract.GetClrTypeFullName(dataContract.UnderlyingType))));
|
|
}
|
|
return dataContract;
|
|
}
|
|
|
|
return base.GetDataContract(id, typeHandle);
|
|
}
|
|
|
|
internal override DataContract GetDataContract(RuntimeTypeHandle typeHandle, Type type)
|
|
{
|
|
DataContract dataContract = null;
|
|
if (mode == SerializationMode.SharedType && surrogateSelector != null)
|
|
{
|
|
dataContract = NetDataContractSerializer.GetDataContractFromSurrogateSelector(surrogateSelector, GetStreamingContext(), typeHandle, type, ref surrogateDataContracts);
|
|
}
|
|
|
|
if (dataContract != null)
|
|
{
|
|
if (this.IsGetOnlyCollection && dataContract is SurrogateDataContract)
|
|
{
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.SurrogatesWithGetOnlyCollectionsNotSupportedSerDeser,
|
|
DataContract.GetClrTypeFullName(dataContract.UnderlyingType))));
|
|
}
|
|
return dataContract;
|
|
}
|
|
|
|
return base.GetDataContract(typeHandle, type);
|
|
}
|
|
|
|
public override object InternalDeserialize(XmlReaderDelegator xmlReader, int declaredTypeID, RuntimeTypeHandle declaredTypeHandle, string name, string ns)
|
|
{
|
|
if (mode == SerializationMode.SharedContract)
|
|
{
|
|
if (dataContractSurrogate == null)
|
|
return base.InternalDeserialize(xmlReader, declaredTypeID, declaredTypeHandle, name, ns);
|
|
else
|
|
return InternalDeserializeWithSurrogate(xmlReader, Type.GetTypeFromHandle(declaredTypeHandle), null /*surrogateDataContract*/, name, ns);
|
|
}
|
|
else
|
|
{
|
|
return InternalDeserializeInSharedTypeMode(xmlReader, declaredTypeID, Type.GetTypeFromHandle(declaredTypeHandle), name, ns);
|
|
}
|
|
}
|
|
|
|
internal override object InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, string name, string ns)
|
|
{
|
|
if (mode == SerializationMode.SharedContract)
|
|
{
|
|
if (dataContractSurrogate == null)
|
|
return base.InternalDeserialize(xmlReader, declaredType, name, ns);
|
|
else
|
|
return InternalDeserializeWithSurrogate(xmlReader, declaredType, null /*surrogateDataContract*/, name, ns);
|
|
}
|
|
else
|
|
{
|
|
return InternalDeserializeInSharedTypeMode(xmlReader, -1, declaredType, name, ns);
|
|
}
|
|
}
|
|
|
|
internal override object InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, DataContract dataContract, string name, string ns)
|
|
{
|
|
if (mode == SerializationMode.SharedContract)
|
|
{
|
|
if (dataContractSurrogate == null)
|
|
return base.InternalDeserialize(xmlReader, declaredType, dataContract, name, ns);
|
|
else
|
|
return InternalDeserializeWithSurrogate(xmlReader, declaredType, dataContract, name, ns);
|
|
}
|
|
else
|
|
{
|
|
return InternalDeserializeInSharedTypeMode(xmlReader, -1, declaredType, name, ns);
|
|
}
|
|
}
|
|
|
|
object InternalDeserializeInSharedTypeMode(XmlReaderDelegator xmlReader, int declaredTypeID, Type declaredType, string name, string ns)
|
|
{
|
|
object retObj = null;
|
|
if (TryHandleNullOrRef(xmlReader, declaredType, name, ns, ref retObj))
|
|
return retObj;
|
|
|
|
DataContract dataContract;
|
|
string assemblyName = attributes.ClrAssembly;
|
|
string typeName = attributes.ClrType;
|
|
if (assemblyName != null && typeName != null)
|
|
{
|
|
Assembly assembly;
|
|
Type type;
|
|
dataContract = ResolveDataContractInSharedTypeMode(assemblyName, typeName, out assembly, out type);
|
|
if (dataContract == null)
|
|
{
|
|
if (assembly == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.AssemblyNotFound, assemblyName)));
|
|
if (type == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.ClrTypeNotFound, assembly.FullName, typeName)));
|
|
}
|
|
//Array covariance is not supported in XSD. If declared type is array, data is sent in format of base array
|
|
if (declaredType != null && declaredType.IsArray)
|
|
dataContract = (declaredTypeID < 0) ? GetDataContract(declaredType) : GetDataContract(declaredTypeID, declaredType.TypeHandle);
|
|
}
|
|
else
|
|
{
|
|
if (assemblyName != null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(XmlObjectSerializer.TryAddLineInfo(xmlReader, SR.GetString(SR.AttributeNotFound, Globals.SerializationNamespace, Globals.ClrTypeLocalName, xmlReader.NodeType, xmlReader.NamespaceURI, xmlReader.LocalName))));
|
|
else if (typeName != null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(XmlObjectSerializer.TryAddLineInfo(xmlReader, SR.GetString(SR.AttributeNotFound, Globals.SerializationNamespace, Globals.ClrAssemblyLocalName, xmlReader.NodeType, xmlReader.NamespaceURI, xmlReader.LocalName))));
|
|
else if (declaredType == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(XmlObjectSerializer.TryAddLineInfo(xmlReader, SR.GetString(SR.AttributeNotFound, Globals.SerializationNamespace, Globals.ClrTypeLocalName, xmlReader.NodeType, xmlReader.NamespaceURI, xmlReader.LocalName))));
|
|
dataContract = (declaredTypeID < 0) ? GetDataContract(declaredType) : GetDataContract(declaredTypeID, declaredType.TypeHandle);
|
|
}
|
|
return ReadDataContractValue(dataContract, xmlReader);
|
|
}
|
|
|
|
object InternalDeserializeWithSurrogate(XmlReaderDelegator xmlReader, Type declaredType, DataContract surrogateDataContract, string name, string ns)
|
|
{
|
|
if (TD.DCDeserializeWithSurrogateStartIsEnabled())
|
|
{
|
|
TD.DCDeserializeWithSurrogateStart(declaredType.FullName);
|
|
}
|
|
|
|
DataContract dataContract = surrogateDataContract ??
|
|
GetDataContract(DataContractSurrogateCaller.GetDataContractType(dataContractSurrogate, declaredType));
|
|
if (this.IsGetOnlyCollection && dataContract.UnderlyingType != declaredType)
|
|
{
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.SurrogatesWithGetOnlyCollectionsNotSupportedSerDeser,
|
|
DataContract.GetClrTypeFullName(declaredType))));
|
|
}
|
|
ReadAttributes(xmlReader);
|
|
string objectId = GetObjectId();
|
|
object oldObj = InternalDeserialize(xmlReader, name, ns, declaredType, ref dataContract);
|
|
object obj = DataContractSurrogateCaller.GetDeserializedObject(dataContractSurrogate, oldObj, dataContract.UnderlyingType, declaredType);
|
|
ReplaceDeserializedObject(objectId, oldObj, obj);
|
|
|
|
if (TD.DCDeserializeWithSurrogateStopIsEnabled())
|
|
{
|
|
TD.DCDeserializeWithSurrogateStop();
|
|
}
|
|
|
|
return obj;
|
|
}
|
|
|
|
Type ResolveDataContractTypeInSharedTypeMode(string assemblyName, string typeName, out Assembly assembly)
|
|
{
|
|
assembly = null;
|
|
Type type = null;
|
|
|
|
if (binder != null)
|
|
type = binder.BindToType(assemblyName, typeName);
|
|
if (type == null)
|
|
{
|
|
XmlObjectDataContractTypeKey key = new XmlObjectDataContractTypeKey(assemblyName, typeName);
|
|
XmlObjectDataContractTypeInfo dataContractTypeInfo = (XmlObjectDataContractTypeInfo)dataContractTypeCache[key];
|
|
if (dataContractTypeInfo == null)
|
|
{
|
|
if (assemblyFormat == FormatterAssemblyStyle.Full)
|
|
{
|
|
if (assemblyName == Globals.MscorlibAssemblyName)
|
|
{
|
|
assembly = Globals.TypeOfInt.Assembly;
|
|
}
|
|
else
|
|
{
|
|
assembly = Assembly.Load(assemblyName);
|
|
}
|
|
if (assembly != null)
|
|
type = assembly.GetType(typeName);
|
|
}
|
|
else
|
|
{
|
|
assembly = XmlObjectSerializerReadContextComplex.ResolveSimpleAssemblyName(assemblyName);
|
|
if (assembly != null)
|
|
{
|
|
// Catching any exceptions that could be thrown from a failure on assembly load
|
|
// This is necessary, for example, if there are generic parameters that are qualified with a version of the assembly that predates the one available
|
|
try
|
|
{
|
|
type = assembly.GetType(typeName);
|
|
}
|
|
catch (TypeLoadException) { }
|
|
catch (FileNotFoundException) { }
|
|
catch (FileLoadException) { }
|
|
catch (BadImageFormatException) { }
|
|
|
|
if (type == null)
|
|
{
|
|
type = Type.GetType(typeName, XmlObjectSerializerReadContextComplex.ResolveSimpleAssemblyName, new TopLevelAssemblyTypeResolver(assembly).ResolveType, false /* throwOnError */);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (type != null)
|
|
{
|
|
CheckTypeForwardedTo(assembly, type.Assembly, type);
|
|
|
|
dataContractTypeInfo = new XmlObjectDataContractTypeInfo(assembly, type);
|
|
lock (dataContractTypeCache)
|
|
{
|
|
if (!dataContractTypeCache.ContainsKey(key))
|
|
{
|
|
dataContractTypeCache[key] = dataContractTypeInfo;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
assembly = dataContractTypeInfo.Assembly;
|
|
type = dataContractTypeInfo.Type;
|
|
}
|
|
}
|
|
|
|
return type;
|
|
}
|
|
|
|
DataContract ResolveDataContractInSharedTypeMode(string assemblyName, string typeName, out Assembly assembly, out Type type)
|
|
{
|
|
type = ResolveDataContractTypeInSharedTypeMode(assemblyName, typeName, out assembly);
|
|
if (type != null)
|
|
{
|
|
return GetDataContract(type);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
protected override DataContract ResolveDataContractFromTypeName()
|
|
{
|
|
if (mode == SerializationMode.SharedContract)
|
|
{
|
|
return base.ResolveDataContractFromTypeName();
|
|
}
|
|
else
|
|
{
|
|
if (attributes.ClrAssembly != null && attributes.ClrType != null)
|
|
{
|
|
Assembly assembly;
|
|
Type type;
|
|
return ResolveDataContractInSharedTypeMode(attributes.ClrAssembly, attributes.ClrType, out assembly, out type);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Calls the critical methods of ISurrogateSelector", Safe = "Demands for FullTrust")]
|
|
[SecuritySafeCritical]
|
|
[PermissionSet(SecurityAction.Demand, Unrestricted = true)]
|
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
|
bool CheckIfTypeSerializableForSharedTypeMode(Type memberType)
|
|
{
|
|
Fx.Assert(surrogateSelector != null, "Method should not be called when surrogateSelector is null.");
|
|
ISurrogateSelector surrogateSelectorNotUsed;
|
|
return (surrogateSelector.GetSurrogate(memberType, GetStreamingContext(), out surrogateSelectorNotUsed) != null);
|
|
}
|
|
|
|
internal override void CheckIfTypeSerializable(Type memberType, bool isMemberTypeSerializable)
|
|
{
|
|
if (mode == SerializationMode.SharedType && surrogateSelector != null &&
|
|
CheckIfTypeSerializableForSharedTypeMode(memberType))
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if (dataContractSurrogate != null)
|
|
{
|
|
while (memberType.IsArray)
|
|
memberType = memberType.GetElementType();
|
|
memberType = DataContractSurrogateCaller.GetDataContractType(dataContractSurrogate, memberType);
|
|
if (!DataContract.IsTypeSerializable(memberType))
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.TypeNotSerializable, memberType)));
|
|
return;
|
|
}
|
|
}
|
|
|
|
base.CheckIfTypeSerializable(memberType, isMemberTypeSerializable);
|
|
}
|
|
|
|
internal override Type GetSurrogatedType(Type type)
|
|
{
|
|
if (dataContractSurrogate == null)
|
|
{
|
|
return base.GetSurrogatedType(type);
|
|
}
|
|
else
|
|
{
|
|
type = DataContract.UnwrapNullableType(type);
|
|
Type surrogateType = DataContractSerializer.GetSurrogatedType(dataContractSurrogate, type);
|
|
if (this.IsGetOnlyCollection && surrogateType != type)
|
|
{
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.SurrogatesWithGetOnlyCollectionsNotSupportedSerDeser,
|
|
DataContract.GetClrTypeFullName(type))));
|
|
}
|
|
else
|
|
{
|
|
return surrogateType;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if USE_REFEMIT
|
|
public override int GetArraySize()
|
|
#else
|
|
internal override int GetArraySize()
|
|
#endif
|
|
{
|
|
return preserveObjectReferences ? attributes.ArraySZSize : -1;
|
|
}
|
|
|
|
static Assembly ResolveSimpleAssemblyName(AssemblyName assemblyName)
|
|
{
|
|
return ResolveSimpleAssemblyName(assemblyName.FullName);
|
|
}
|
|
|
|
static Assembly ResolveSimpleAssemblyName(string assemblyName)
|
|
{
|
|
Assembly assembly;
|
|
if (assemblyName == Globals.MscorlibAssemblyName)
|
|
{
|
|
assembly = Globals.TypeOfInt.Assembly;
|
|
}
|
|
else
|
|
{
|
|
assembly = Assembly.LoadWithPartialName(assemblyName);
|
|
if (assembly == null)
|
|
{
|
|
AssemblyName an = new AssemblyName(assemblyName);
|
|
an.Version = null;
|
|
assembly = Assembly.LoadWithPartialName(an.FullName);
|
|
}
|
|
}
|
|
return assembly;
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Gets the SecurityCritical PermissionSet for sourceAssembly and destinationAssembly.",
|
|
Safe = "Doesn't leak anything.")]
|
|
[SecuritySafeCritical]
|
|
static void CheckTypeForwardedTo(Assembly sourceAssembly, Assembly destinationAssembly, Type resolvedType)
|
|
{
|
|
if (sourceAssembly != destinationAssembly && !NetDataContractSerializer.UnsafeTypeForwardingEnabled && !sourceAssembly.IsFullyTrusted)
|
|
{
|
|
#if !NO_DESKTOP_SECURITY
|
|
// We have a TypeForwardedTo attribute
|
|
if (!destinationAssembly.PermissionSet.IsSubsetOf(sourceAssembly.PermissionSet))
|
|
{
|
|
// We look for a matching TypeForwardedFrom attribute
|
|
TypeInformation typeInfo = NetDataContractSerializer.GetTypeInformation(resolvedType);
|
|
if (typeInfo.HasTypeForwardedFrom)
|
|
{
|
|
Assembly typeForwardedFromAssembly = null;
|
|
try
|
|
{
|
|
// if this Assembly.Load fails, we still want to throw security exception
|
|
typeForwardedFromAssembly = Assembly.Load(typeInfo.AssemblyString);
|
|
}
|
|
catch { }
|
|
|
|
if (typeForwardedFromAssembly == sourceAssembly)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.CannotDeserializeForwardedType, DataContract.GetClrTypeFullName(resolvedType))));
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
sealed class TopLevelAssemblyTypeResolver
|
|
{
|
|
Assembly topLevelAssembly;
|
|
|
|
public TopLevelAssemblyTypeResolver(Assembly topLevelAssembly)
|
|
{
|
|
this.topLevelAssembly = topLevelAssembly;
|
|
}
|
|
public Type ResolveType(Assembly assembly, string simpleTypeName, bool ignoreCase)
|
|
{
|
|
if (assembly == null)
|
|
assembly = topLevelAssembly;
|
|
|
|
return assembly.GetType(simpleTypeName, false, ignoreCase);
|
|
}
|
|
}
|
|
|
|
class XmlObjectDataContractTypeInfo
|
|
{
|
|
Assembly assembly;
|
|
Type type;
|
|
public XmlObjectDataContractTypeInfo(Assembly assembly, Type type)
|
|
{
|
|
this.assembly = assembly;
|
|
this.type = type;
|
|
}
|
|
|
|
public Assembly Assembly
|
|
{
|
|
get
|
|
{
|
|
return this.assembly;
|
|
}
|
|
}
|
|
|
|
public Type Type
|
|
{
|
|
get
|
|
{
|
|
return this.type;
|
|
}
|
|
}
|
|
}
|
|
|
|
class XmlObjectDataContractTypeKey
|
|
{
|
|
string assemblyName;
|
|
string typeName;
|
|
public XmlObjectDataContractTypeKey(string assemblyName, string typeName)
|
|
{
|
|
this.assemblyName = assemblyName;
|
|
this.typeName = typeName;
|
|
}
|
|
|
|
public override bool Equals(object obj)
|
|
{
|
|
if (object.ReferenceEquals(this, obj))
|
|
return true;
|
|
|
|
XmlObjectDataContractTypeKey other = obj as XmlObjectDataContractTypeKey;
|
|
if (other == null)
|
|
return false;
|
|
|
|
if (this.assemblyName != other.assemblyName)
|
|
return false;
|
|
|
|
if (this.typeName != other.typeName)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
int hashCode = 0;
|
|
if (this.assemblyName != null)
|
|
hashCode = this.assemblyName.GetHashCode();
|
|
|
|
if (this.typeName != null)
|
|
hashCode ^= this.typeName.GetHashCode();
|
|
|
|
return hashCode;
|
|
}
|
|
}
|
|
}
|
|
}
|