2015-04-07 09:35:12 +01:00
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.Runtime.Serialization
{
using System ;
using System.IO ;
using System.Xml ;
using System.Security ;
using System.Collections ;
using System.Security.Permissions ;
using System.Runtime.CompilerServices ;
using System.Runtime.Serialization.Formatters ;
using System.Collections.Generic ;
2015-08-26 07:17:56 -04:00
#if ! NO_CONFIGURATION
2015-04-07 09:35:12 +01:00
using System.Runtime.Serialization.Configuration ;
2015-08-26 07:17:56 -04:00
#endif
2015-04-07 09:35:12 +01:00
using System.Reflection ;
public sealed class NetDataContractSerializer : XmlObjectSerializer , IFormatter
{
XmlDictionaryString rootName ;
XmlDictionaryString rootNamespace ;
StreamingContext context ;
SerializationBinder binder ;
ISurrogateSelector surrogateSelector ;
int maxItemsInObjectGraph ;
bool ignoreExtensionDataObject ;
FormatterAssemblyStyle assemblyFormat ;
DataContract cachedDataContract ;
static Hashtable typeNameCache = new Hashtable ( ) ;
public NetDataContractSerializer ( )
: this ( new StreamingContext ( StreamingContextStates . All ) )
{
}
public NetDataContractSerializer ( StreamingContext context )
: this ( context , Int32 . MaxValue , false , FormatterAssemblyStyle . Full , null )
{
}
public NetDataContractSerializer ( StreamingContext context ,
int maxItemsInObjectGraph ,
bool ignoreExtensionDataObject ,
FormatterAssemblyStyle assemblyFormat ,
ISurrogateSelector surrogateSelector )
{
Initialize ( context , maxItemsInObjectGraph , ignoreExtensionDataObject , assemblyFormat , surrogateSelector ) ;
}
public NetDataContractSerializer ( string rootName , string rootNamespace )
: this ( rootName , rootNamespace , new StreamingContext ( StreamingContextStates . All ) , Int32 . MaxValue , false , FormatterAssemblyStyle . Full , null )
{
}
public NetDataContractSerializer ( string rootName , string rootNamespace ,
StreamingContext context ,
int maxItemsInObjectGraph ,
bool ignoreExtensionDataObject ,
FormatterAssemblyStyle assemblyFormat ,
ISurrogateSelector surrogateSelector )
{
XmlDictionary dictionary = new XmlDictionary ( 2 ) ;
Initialize ( dictionary . Add ( rootName ) , dictionary . Add ( DataContract . GetNamespace ( rootNamespace ) ) , context , maxItemsInObjectGraph , ignoreExtensionDataObject , assemblyFormat , surrogateSelector ) ;
}
public NetDataContractSerializer ( XmlDictionaryString rootName , XmlDictionaryString rootNamespace )
: this ( rootName , rootNamespace , new StreamingContext ( StreamingContextStates . All ) , Int32 . MaxValue , false , FormatterAssemblyStyle . Full , null )
{
}
public NetDataContractSerializer ( XmlDictionaryString rootName , XmlDictionaryString rootNamespace ,
StreamingContext context ,
int maxItemsInObjectGraph ,
bool ignoreExtensionDataObject ,
FormatterAssemblyStyle assemblyFormat ,
ISurrogateSelector surrogateSelector )
{
Initialize ( rootName , rootNamespace , context , maxItemsInObjectGraph , ignoreExtensionDataObject , assemblyFormat , surrogateSelector ) ;
}
void Initialize ( StreamingContext context ,
int maxItemsInObjectGraph ,
bool ignoreExtensionDataObject ,
FormatterAssemblyStyle assemblyFormat ,
ISurrogateSelector surrogateSelector )
{
this . context = context ;
if ( maxItemsInObjectGraph < 0 )
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new ArgumentOutOfRangeException ( "maxItemsInObjectGraph" , SR . GetString ( SR . ValueMustBeNonNegative ) ) ) ;
this . maxItemsInObjectGraph = maxItemsInObjectGraph ;
this . ignoreExtensionDataObject = ignoreExtensionDataObject ;
this . surrogateSelector = surrogateSelector ;
this . AssemblyFormat = assemblyFormat ;
}
void Initialize ( XmlDictionaryString rootName , XmlDictionaryString rootNamespace ,
StreamingContext context ,
int maxItemsInObjectGraph ,
bool ignoreExtensionDataObject ,
FormatterAssemblyStyle assemblyFormat ,
ISurrogateSelector surrogateSelector )
{
Initialize ( context , maxItemsInObjectGraph , ignoreExtensionDataObject , assemblyFormat , surrogateSelector ) ;
this . rootName = rootName ;
this . rootNamespace = rootNamespace ;
}
static bool? unsafeTypeForwardingEnabled ;
internal static bool UnsafeTypeForwardingEnabled
{
[Fx.Tag.SecurityNote(Critical = "Calls Security Critical method NetDataContractSerializerSection.TryUnsafeGetSection.", Safe = "The ConfigSection instance is not leaked.")]
[SecuritySafeCritical]
get
{
if ( unsafeTypeForwardingEnabled = = null )
{
2015-08-26 07:17:56 -04:00
#if NO_CONFIGURATION
unsafeTypeForwardingEnabled = false ;
#else
2015-04-07 09:35:12 +01:00
NetDataContractSerializerSection section ;
if ( NetDataContractSerializerSection . TryUnsafeGetSection ( out section ) )
{
unsafeTypeForwardingEnabled = section . EnableUnsafeTypeForwarding ;
}
else
{
unsafeTypeForwardingEnabled = false ;
}
2015-08-26 07:17:56 -04:00
#endif
2015-04-07 09:35:12 +01:00
}
Fx . Assert ( unsafeTypeForwardingEnabled ! = null , "unsafeTypeForwardingEnabled should not be null." ) ;
return unsafeTypeForwardingEnabled . Value ;
}
}
public StreamingContext Context
{
get { return context ; }
set { context = value ; }
}
public SerializationBinder Binder
{
get { return binder ; }
set { binder = value ; }
}
public ISurrogateSelector SurrogateSelector
{
get { return surrogateSelector ; }
set { surrogateSelector = value ; }
}
public FormatterAssemblyStyle AssemblyFormat
{
get { return assemblyFormat ; }
set
{
if ( value ! = FormatterAssemblyStyle . Full & & value ! = FormatterAssemblyStyle . Simple )
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new ArgumentException ( SR . GetString ( SR . InvalidAssemblyFormat , value ) ) ) ;
assemblyFormat = value ;
}
}
public int MaxItemsInObjectGraph
{
get { return maxItemsInObjectGraph ; }
}
public bool IgnoreExtensionDataObject
{
get { return ignoreExtensionDataObject ; }
}
public void Serialize ( Stream stream , object graph )
{
base . WriteObject ( stream , graph ) ;
}
public object Deserialize ( Stream stream )
{
return base . ReadObject ( stream ) ;
}
internal override void InternalWriteObject ( XmlWriterDelegator writer , object graph )
{
Hashtable surrogateDataContracts = null ;
DataContract contract = GetDataContract ( graph , ref surrogateDataContracts ) ;
InternalWriteStartObject ( writer , graph , contract ) ;
InternalWriteObjectContent ( writer , graph , contract , surrogateDataContracts ) ;
InternalWriteEndObject ( writer ) ;
}
public override void WriteObject ( XmlWriter writer , object graph )
{
WriteObjectHandleExceptions ( new XmlWriterDelegator ( writer ) , graph ) ;
}
public override void WriteStartObject ( XmlWriter writer , object graph )
{
WriteStartObjectHandleExceptions ( new XmlWriterDelegator ( writer ) , graph ) ;
}
public override void WriteObjectContent ( XmlWriter writer , object graph )
{
WriteObjectContentHandleExceptions ( new XmlWriterDelegator ( writer ) , graph ) ;
}
public override void WriteEndObject ( XmlWriter writer )
{
WriteEndObjectHandleExceptions ( new XmlWriterDelegator ( writer ) ) ;
}
public override void WriteStartObject ( XmlDictionaryWriter writer , object graph )
{
WriteStartObjectHandleExceptions ( new XmlWriterDelegator ( writer ) , graph ) ;
}
internal override void InternalWriteStartObject ( XmlWriterDelegator writer , object graph )
{
Hashtable surrogateDataContracts = null ;
DataContract contract = GetDataContract ( graph , ref surrogateDataContracts ) ;
InternalWriteStartObject ( writer , graph , contract ) ;
}
void InternalWriteStartObject ( XmlWriterDelegator writer , object graph , DataContract contract )
{
WriteRootElement ( writer , contract , rootName , rootNamespace , CheckIfNeedsContractNsAtRoot ( rootName , rootNamespace , contract ) ) ;
}
public override void WriteObjectContent ( XmlDictionaryWriter writer , object graph )
{
WriteObjectContentHandleExceptions ( new XmlWriterDelegator ( writer ) , graph ) ;
}
internal override void InternalWriteObjectContent ( XmlWriterDelegator writer , object graph )
{
Hashtable surrogateDataContracts = null ;
DataContract contract = GetDataContract ( graph , ref surrogateDataContracts ) ;
InternalWriteObjectContent ( writer , graph , contract , surrogateDataContracts ) ;
}
void InternalWriteObjectContent ( XmlWriterDelegator writer , object graph , DataContract contract , Hashtable surrogateDataContracts )
{
if ( MaxItemsInObjectGraph = = 0 )
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( XmlObjectSerializer . CreateSerializationException ( SR . GetString ( SR . ExceededMaxItemsQuota , MaxItemsInObjectGraph ) ) ) ;
if ( IsRootXmlAny ( rootName , contract ) )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( XmlObjectSerializer . CreateSerializationException ( SR . GetString ( SR . IsAnyNotSupportedByNetDataContractSerializer , contract . UnderlyingType ) ) ) ;
}
else if ( graph = = null )
{
WriteNull ( writer ) ;
}
else
{
Type graphType = graph . GetType ( ) ;
if ( contract . UnderlyingType ! = graphType )
contract = GetDataContract ( graph , ref surrogateDataContracts ) ;
XmlObjectSerializerWriteContext context = null ;
if ( contract . CanContainReferences )
{
context = XmlObjectSerializerWriteContext . CreateContext ( this , surrogateDataContracts ) ;
context . HandleGraphAtTopLevel ( writer , graph , contract ) ;
}
WriteClrTypeInfo ( writer , contract , binder ) ;
contract . WriteXmlValue ( writer , graph , context ) ;
}
}
// Update the overloads whenever you are changing this method
internal static void WriteClrTypeInfo ( XmlWriterDelegator writer , DataContract dataContract , SerializationBinder binder )
{
if ( ! dataContract . IsISerializable & & ! ( dataContract is SurrogateDataContract ) )
{
TypeInformation typeInformation = null ;
Type clrType = dataContract . OriginalUnderlyingType ;
string clrTypeName = null ;
string clrAssemblyName = null ;
if ( binder ! = null )
{
binder . BindToName ( clrType , out clrAssemblyName , out clrTypeName ) ;
}
if ( clrTypeName = = null )
{
typeInformation = NetDataContractSerializer . GetTypeInformation ( clrType ) ;
clrTypeName = typeInformation . FullTypeName ;
}
if ( clrAssemblyName = = null )
{
clrAssemblyName = ( typeInformation = = null ) ?
NetDataContractSerializer . GetTypeInformation ( clrType ) . AssemblyString :
typeInformation . AssemblyString ;
// Throw in the [TypeForwardedFrom] case to prevent a partially trusted assembly from forwarding itself to an assembly with higher privileges
if ( ! UnsafeTypeForwardingEnabled & & ! clrType . Assembly . IsFullyTrusted & & ! IsAssemblyNameForwardingSafe ( clrType . Assembly . FullName , clrAssemblyName ) )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( XmlObjectSerializer . CreateSerializationException ( SR . GetString ( SR . TypeCannotBeForwardedFrom , DataContract . GetClrTypeFullName ( clrType ) , clrType . Assembly . FullName , clrAssemblyName ) ) ) ;
}
}
WriteClrTypeInfo ( writer , clrTypeName , clrAssemblyName ) ;
}
}
// Update the overloads whenever you are changing this method
internal static void WriteClrTypeInfo ( XmlWriterDelegator writer , Type dataContractType , SerializationBinder binder , string defaultClrTypeName , string defaultClrAssemblyName )
{
string clrTypeName = null ;
string clrAssemblyName = null ;
if ( binder ! = null )
{
binder . BindToName ( dataContractType , out clrAssemblyName , out clrTypeName ) ;
}
if ( clrTypeName = = null )
{
clrTypeName = defaultClrTypeName ;
}
if ( clrAssemblyName = = null )
{
clrAssemblyName = defaultClrAssemblyName ;
}
WriteClrTypeInfo ( writer , clrTypeName , clrAssemblyName ) ;
}
// Update the overloads whenever you are changing this method
internal static void WriteClrTypeInfo ( XmlWriterDelegator writer , Type dataContractType , SerializationBinder binder , SerializationInfo serInfo )
{
TypeInformation typeInformation = null ;
string clrTypeName = null ;
string clrAssemblyName = null ;
if ( binder ! = null )
{
binder . BindToName ( dataContractType , out clrAssemblyName , out clrTypeName ) ;
}
if ( clrTypeName = = null )
{
if ( serInfo . IsFullTypeNameSetExplicit )
{
clrTypeName = serInfo . FullTypeName ;
}
else
{
typeInformation = NetDataContractSerializer . GetTypeInformation ( serInfo . ObjectType ) ;
clrTypeName = typeInformation . FullTypeName ;
}
}
if ( clrAssemblyName = = null )
{
if ( serInfo . IsAssemblyNameSetExplicit )
{
clrAssemblyName = serInfo . AssemblyName ;
}
else
{
clrAssemblyName = ( typeInformation = = null ) ?
NetDataContractSerializer . GetTypeInformation ( serInfo . ObjectType ) . AssemblyString :
typeInformation . AssemblyString ;
}
}
WriteClrTypeInfo ( writer , clrTypeName , clrAssemblyName ) ;
}
static void WriteClrTypeInfo ( XmlWriterDelegator writer , string clrTypeName , string clrAssemblyName )
{
if ( clrTypeName ! = null )
writer . WriteAttributeString ( Globals . SerPrefix , DictionaryGlobals . ClrTypeLocalName , DictionaryGlobals . SerializationNamespace , DataContract . GetClrTypeString ( clrTypeName ) ) ;
if ( clrAssemblyName ! = null )
writer . WriteAttributeString ( Globals . SerPrefix , DictionaryGlobals . ClrAssemblyLocalName , DictionaryGlobals . SerializationNamespace , DataContract . GetClrTypeString ( clrAssemblyName ) ) ;
}
public override void WriteEndObject ( XmlDictionaryWriter writer )
{
WriteEndObjectHandleExceptions ( new XmlWriterDelegator ( writer ) ) ;
}
internal override void InternalWriteEndObject ( XmlWriterDelegator writer )
{
writer . WriteEndElement ( ) ;
}
public override object ReadObject ( XmlReader reader )
{
return ReadObjectHandleExceptions ( new XmlReaderDelegator ( reader ) , true /*verifyObjectName*/ ) ;
}
public override object ReadObject ( XmlReader reader , bool verifyObjectName )
{
return ReadObjectHandleExceptions ( new XmlReaderDelegator ( reader ) , verifyObjectName ) ;
}
public override bool IsStartObject ( XmlReader reader )
{
return IsStartObjectHandleExceptions ( new XmlReaderDelegator ( reader ) ) ;
}
public override object ReadObject ( XmlDictionaryReader reader , bool verifyObjectName )
{
return ReadObjectHandleExceptions ( new XmlReaderDelegator ( reader ) , verifyObjectName ) ;
}
public override bool IsStartObject ( XmlDictionaryReader reader )
{
return IsStartObjectHandleExceptions ( new XmlReaderDelegator ( reader ) ) ;
}
internal override object InternalReadObject ( XmlReaderDelegator xmlReader , bool verifyObjectName )
{
if ( MaxItemsInObjectGraph = = 0 )
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( XmlObjectSerializer . CreateSerializationException ( SR . GetString ( SR . ExceededMaxItemsQuota , MaxItemsInObjectGraph ) ) ) ;
// verifyObjectName has no effect in SharedType mode
if ( ! IsStartElement ( xmlReader ) )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( XmlObjectSerializer . CreateSerializationExceptionWithReaderDetails ( SR . GetString ( SR . ExpectingElementAtDeserialize , XmlNodeType . Element ) , xmlReader ) ) ;
}
XmlObjectSerializerReadContext context = XmlObjectSerializerReadContext . CreateContext ( this ) ;
return context . InternalDeserialize ( xmlReader , null , null , null ) ;
}
internal override bool InternalIsStartObject ( XmlReaderDelegator reader )
{
return IsStartElement ( reader ) ;
}
internal DataContract GetDataContract ( object obj , ref Hashtable surrogateDataContracts )
{
return GetDataContract ( ( ( obj = = null ) ? Globals . TypeOfObject : obj . GetType ( ) ) , ref surrogateDataContracts ) ;
}
internal DataContract GetDataContract ( Type type , ref Hashtable surrogateDataContracts )
{
return GetDataContract ( type . TypeHandle , type , ref surrogateDataContracts ) ;
}
internal DataContract GetDataContract ( RuntimeTypeHandle typeHandle , Type type , ref Hashtable surrogateDataContracts )
{
DataContract dataContract = GetDataContractFromSurrogateSelector ( surrogateSelector , Context , typeHandle , type , ref surrogateDataContracts ) ;
if ( dataContract ! = null )
return dataContract ;
if ( cachedDataContract = = null )
{
dataContract = DataContract . GetDataContract ( typeHandle , type , SerializationMode . SharedType ) ;
cachedDataContract = dataContract ;
return dataContract ;
}
DataContract currentCachedDataContract = cachedDataContract ;
if ( currentCachedDataContract . UnderlyingType . TypeHandle . Equals ( typeHandle ) )
return currentCachedDataContract ;
return DataContract . GetDataContract ( typeHandle , type , SerializationMode . SharedType ) ;
}
[Fx.Tag.SecurityNote(Critical = "Calls the critical methods of ISurrogateSelector", Safe = "Demands for FullTrust")]
[SecuritySafeCritical]
[PermissionSet(SecurityAction.Demand, Unrestricted = true)]
[MethodImpl(MethodImplOptions.NoInlining)]
static ISerializationSurrogate GetSurrogate ( Type type , ISurrogateSelector surrogateSelector , StreamingContext context )
{
ISurrogateSelector surrogateSelectorNotUsed ;
return surrogateSelector . GetSurrogate ( type , context , out surrogateSelectorNotUsed ) ;
}
internal static DataContract GetDataContractFromSurrogateSelector ( ISurrogateSelector surrogateSelector , StreamingContext context , RuntimeTypeHandle typeHandle , Type type , ref Hashtable surrogateDataContracts )
{
if ( surrogateSelector = = null )
return null ;
if ( type = = null )
type = Type . GetTypeFromHandle ( typeHandle ) ;
DataContract builtInDataContract = DataContract . GetBuiltInDataContract ( type ) ;
if ( builtInDataContract ! = null )
return builtInDataContract ;
if ( surrogateDataContracts ! = null )
{
DataContract cachedSurrogateContract = ( DataContract ) surrogateDataContracts [ type ] ;
if ( cachedSurrogateContract ! = null )
return cachedSurrogateContract ;
}
DataContract surrogateContract = null ;
ISerializationSurrogate surrogate = GetSurrogate ( type , surrogateSelector , context ) ;
if ( surrogate ! = null )
surrogateContract = new SurrogateDataContract ( type , surrogate ) ;
else if ( type . IsArray )
{
Type elementType = type . GetElementType ( ) ;
DataContract itemContract = GetDataContractFromSurrogateSelector ( surrogateSelector , context , elementType . TypeHandle , elementType , ref surrogateDataContracts ) ;
if ( itemContract = = null )
itemContract = DataContract . GetDataContract ( elementType . TypeHandle , elementType , SerializationMode . SharedType ) ;
surrogateContract = new CollectionDataContract ( type , itemContract ) ;
}
if ( surrogateContract ! = null )
{
if ( surrogateDataContracts = = null )
surrogateDataContracts = new Hashtable ( ) ;
surrogateDataContracts . Add ( type , surrogateContract ) ;
return surrogateContract ;
}
return null ;
}
internal static TypeInformation GetTypeInformation ( Type type )
{
TypeInformation typeInformation = null ;
object typeInformationObject = typeNameCache [ type ] ;
if ( typeInformationObject = = null )
{
bool hasTypeForwardedFrom ;
string assemblyName = DataContract . GetClrAssemblyName ( type , out hasTypeForwardedFrom ) ;
typeInformation = new TypeInformation ( DataContract . GetClrTypeFullNameUsingTypeForwardedFromAttribute ( type ) , assemblyName , hasTypeForwardedFrom ) ;
lock ( typeNameCache )
{
typeNameCache [ type ] = typeInformation ;
}
}
else
{
typeInformation = ( TypeInformation ) typeInformationObject ;
}
return typeInformation ;
}
static bool IsAssemblyNameForwardingSafe ( string originalAssemblyName , string newAssemblyName )
{
if ( originalAssemblyName = = newAssemblyName )
{
return true ;
}
AssemblyName originalAssembly = new AssemblyName ( originalAssemblyName ) ;
AssemblyName newAssembly = new AssemblyName ( newAssemblyName ) ;
// mscorlib will get loaded by the runtime regardless of its string casing or its public key token,
// so setting the assembly name to mscorlib is always unsafe
if ( string . Equals ( newAssembly . Name , Globals . MscorlibAssemblySimpleName , StringComparison . OrdinalIgnoreCase ) | |
string . Equals ( newAssembly . Name , Globals . MscorlibFileName , StringComparison . OrdinalIgnoreCase ) )
{
return false ;
}
return IsPublicKeyTokenForwardingSafe ( originalAssembly . GetPublicKeyToken ( ) , newAssembly . GetPublicKeyToken ( ) ) ;
}
static bool IsPublicKeyTokenForwardingSafe ( byte [ ] sourceToken , byte [ ] destinationToken )
{
if ( sourceToken = = null | | destinationToken = = null | | sourceToken . Length = = 0 | | destinationToken . Length = = 0 | | sourceToken . Length ! = destinationToken . Length )
{
return false ;
}
for ( int i = 0 ; i < sourceToken . Length ; i + + )
{
if ( sourceToken [ i ] ! = destinationToken [ i ] )
{
return false ;
}
}
return true ;
}
}
}