e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
465 lines
19 KiB
C#
465 lines
19 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
namespace System.Runtime.Serialization
|
|
{
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Reflection;
|
|
using System.Security;
|
|
using System.Security.Permissions;
|
|
using System.Threading;
|
|
using System.Xml;
|
|
using System.Xml.Schema;
|
|
using System.Xml.Serialization;
|
|
using DataContractDictionary = System.Collections.Generic.Dictionary<System.Xml.XmlQualifiedName, DataContract>;
|
|
|
|
internal delegate IXmlSerializable CreateXmlSerializableDelegate();
|
|
#if USE_REFEMIT
|
|
public sealed class XmlDataContract : DataContract
|
|
#else
|
|
internal sealed partial class XmlDataContract : DataContract
|
|
#endif
|
|
{
|
|
[Fx.Tag.SecurityNote(Critical = "Holds instance of CriticalHelper which keeps state that is cached statically for serialization."
|
|
+ " Static fields are marked SecurityCritical or readonly to prevent data from being modified or leaked to other components in appdomain.")]
|
|
[SecurityCritical]
|
|
XmlDataContractCriticalHelper helper;
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.",
|
|
Safe = "Doesn't leak anything.")]
|
|
[SecuritySafeCritical]
|
|
internal XmlDataContract()
|
|
: base(new XmlDataContractCriticalHelper())
|
|
{
|
|
helper = base.Helper as XmlDataContractCriticalHelper;
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.",
|
|
Safe = "Doesn't leak anything.")]
|
|
[SecuritySafeCritical]
|
|
internal XmlDataContract(Type type)
|
|
: base(new XmlDataContractCriticalHelper(type))
|
|
{
|
|
helper = base.Helper as XmlDataContractCriticalHelper;
|
|
}
|
|
|
|
internal override DataContractDictionary KnownDataContracts
|
|
{
|
|
[Fx.Tag.SecurityNote(Critical = "Fetches the critical KnownDataContracts property.",
|
|
Safe = "KnownDataContracts only needs to be protected for write.")]
|
|
[SecuritySafeCritical]
|
|
get { return helper.KnownDataContracts; }
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Sets the critical KnownDataContracts property.")]
|
|
[SecurityCritical]
|
|
set { helper.KnownDataContracts = value; }
|
|
}
|
|
|
|
internal XmlSchemaType XsdType
|
|
{
|
|
[Fx.Tag.SecurityNote(Critical = "Fetches the critical XsdType property.",
|
|
Safe = "XsdType only needs to be protected for write.")]
|
|
[SecuritySafeCritical]
|
|
get { return helper.XsdType; }
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Sets the critical XsdType property.")]
|
|
[SecurityCritical]
|
|
set { helper.XsdType = value; }
|
|
}
|
|
|
|
internal bool IsAnonymous
|
|
{
|
|
[Fx.Tag.SecurityNote(Critical = "Fetches the critical IsAnonymous property.",
|
|
Safe = "IsAnonymous only needs to be protected for write.")]
|
|
[SecuritySafeCritical]
|
|
get { return helper.IsAnonymous; }
|
|
}
|
|
|
|
internal override bool HasRoot
|
|
{
|
|
[Fx.Tag.SecurityNote(Critical = "Fetches the critical HasRoot property.",
|
|
Safe = "HasRoot only needs to be protected for write.")]
|
|
[SecuritySafeCritical]
|
|
get { return helper.HasRoot; }
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Sets the critical HasRoot property.")]
|
|
[SecurityCritical]
|
|
set { helper.HasRoot = value; }
|
|
}
|
|
|
|
internal override XmlDictionaryString TopLevelElementName
|
|
{
|
|
[Fx.Tag.SecurityNote(Critical = "Fetches the critical TopLevelElementName property.",
|
|
Safe = "TopLevelElementName only needs to be protected for write.")]
|
|
[SecuritySafeCritical]
|
|
get { return helper.TopLevelElementName; }
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Sets the critical TopLevelElementName property.")]
|
|
[SecurityCritical]
|
|
set { helper.TopLevelElementName = value; }
|
|
}
|
|
|
|
internal override XmlDictionaryString TopLevelElementNamespace
|
|
{
|
|
[Fx.Tag.SecurityNote(Critical = "Fetches the critical TopLevelElementNamespace property.",
|
|
Safe = "TopLevelElementNamespace only needs to be protected for write.")]
|
|
[SecuritySafeCritical]
|
|
get { return helper.TopLevelElementNamespace; }
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Sets the critical TopLevelElementNamespace property.")]
|
|
[SecurityCritical]
|
|
set { helper.TopLevelElementNamespace = value; }
|
|
}
|
|
|
|
internal bool IsTopLevelElementNullable
|
|
{
|
|
[Fx.Tag.SecurityNote(Critical = "Fetches the critical IsTopLevelElementNullable property.",
|
|
Safe = "IsTopLevelElementNullable only needs to be protected for write.")]
|
|
[SecuritySafeCritical]
|
|
get { return helper.IsTopLevelElementNullable; }
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Sets the critical IsTopLevelElementNullable property.")]
|
|
[SecurityCritical]
|
|
set { helper.IsTopLevelElementNullable = value; }
|
|
}
|
|
|
|
internal bool IsTypeDefinedOnImport
|
|
{
|
|
[Fx.Tag.SecurityNote(Critical = "Fetches the critical IsTypeDefinedOnImport property.",
|
|
Safe = "IsTypeDefinedOnImport only needs to be protected for write.")]
|
|
[SecuritySafeCritical]
|
|
get { return helper.IsTypeDefinedOnImport; }
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Sets the critical IsTypeDefinedOnImport property.")]
|
|
[SecurityCritical]
|
|
set { helper.IsTypeDefinedOnImport = value; }
|
|
}
|
|
|
|
internal CreateXmlSerializableDelegate CreateXmlSerializableDelegate
|
|
{
|
|
[Fx.Tag.SecurityNote(Critical = "Fetches the critical CreateXmlSerializableDelegate property.",
|
|
Safe = "CreateXmlSerializableDelegate only needs to be protected for write; initialized in getter if null.")]
|
|
[SecuritySafeCritical]
|
|
get
|
|
{
|
|
if (helper.CreateXmlSerializableDelegate == null)
|
|
{
|
|
lock (this)
|
|
{
|
|
if (helper.CreateXmlSerializableDelegate == null)
|
|
{
|
|
CreateXmlSerializableDelegate tempCreateXmlSerializable = GenerateCreateXmlSerializableDelegate();
|
|
Thread.MemoryBarrier();
|
|
helper.CreateXmlSerializableDelegate = tempCreateXmlSerializable;
|
|
}
|
|
}
|
|
}
|
|
return helper.CreateXmlSerializableDelegate;
|
|
}
|
|
}
|
|
|
|
internal override bool CanContainReferences
|
|
{
|
|
get { return false; }
|
|
}
|
|
|
|
internal override bool IsBuiltInDataContract
|
|
{
|
|
get
|
|
{
|
|
return UnderlyingType == Globals.TypeOfXmlElement || UnderlyingType == Globals.TypeOfXmlNodeArray;
|
|
}
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Holds all state used for for (de)serializing XML types."
|
|
+ " Since the data is cached statically, we lock down access to it.")]
|
|
#if !NO_SECURITY_ATTRIBUTES
|
|
[SecurityCritical(SecurityCriticalScope.Everything)]
|
|
#endif
|
|
class XmlDataContractCriticalHelper : DataContract.DataContractCriticalHelper
|
|
{
|
|
DataContractDictionary knownDataContracts;
|
|
bool isKnownTypeAttributeChecked;
|
|
XmlDictionaryString topLevelElementName;
|
|
XmlDictionaryString topLevelElementNamespace;
|
|
bool isTopLevelElementNullable;
|
|
bool isTypeDefinedOnImport;
|
|
XmlSchemaType xsdType;
|
|
bool hasRoot;
|
|
CreateXmlSerializableDelegate createXmlSerializable;
|
|
|
|
internal XmlDataContractCriticalHelper()
|
|
{
|
|
}
|
|
|
|
internal XmlDataContractCriticalHelper(Type type)
|
|
: base(type)
|
|
{
|
|
if (type.IsDefined(Globals.TypeOfDataContractAttribute, false))
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.IXmlSerializableCannotHaveDataContract, DataContract.GetClrTypeFullName(type))));
|
|
if (type.IsDefined(Globals.TypeOfCollectionDataContractAttribute, false))
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.IXmlSerializableCannotHaveCollectionDataContract, DataContract.GetClrTypeFullName(type))));
|
|
XmlSchemaType xsdType;
|
|
bool hasRoot;
|
|
XmlQualifiedName stableName;
|
|
SchemaExporter.GetXmlTypeInfo(type, out stableName, out xsdType, out hasRoot);
|
|
this.StableName = stableName;
|
|
this.XsdType = xsdType;
|
|
this.HasRoot = hasRoot;
|
|
XmlDictionary dictionary = new XmlDictionary();
|
|
this.Name = dictionary.Add(StableName.Name);
|
|
this.Namespace = dictionary.Add(StableName.Namespace);
|
|
object[] xmlRootAttributes = (UnderlyingType == null) ? null : UnderlyingType.GetCustomAttributes(Globals.TypeOfXmlRootAttribute, false);
|
|
if (xmlRootAttributes == null || xmlRootAttributes.Length == 0)
|
|
{
|
|
if (hasRoot)
|
|
{
|
|
topLevelElementName = Name;
|
|
topLevelElementNamespace = (this.StableName.Namespace == Globals.SchemaNamespace) ? DictionaryGlobals.EmptyString : Namespace;
|
|
isTopLevelElementNullable = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (hasRoot)
|
|
{
|
|
XmlRootAttribute xmlRootAttribute = (XmlRootAttribute)xmlRootAttributes[0];
|
|
isTopLevelElementNullable = xmlRootAttribute.IsNullable;
|
|
string elementName = xmlRootAttribute.ElementName;
|
|
topLevelElementName = (elementName == null || elementName.Length == 0) ? Name : dictionary.Add(DataContract.EncodeLocalName(elementName));
|
|
string elementNs = xmlRootAttribute.Namespace;
|
|
topLevelElementNamespace = (elementNs == null || elementNs.Length == 0) ? DictionaryGlobals.EmptyString : dictionary.Add(elementNs);
|
|
}
|
|
else
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.IsAnyCannotHaveXmlRoot, DataContract.GetClrTypeFullName(UnderlyingType))));
|
|
}
|
|
}
|
|
}
|
|
|
|
internal override DataContractDictionary KnownDataContracts
|
|
{
|
|
get
|
|
{
|
|
if (!isKnownTypeAttributeChecked && UnderlyingType != null)
|
|
{
|
|
lock (this)
|
|
{
|
|
if (!isKnownTypeAttributeChecked)
|
|
{
|
|
knownDataContracts = DataContract.ImportKnownTypeAttributes(this.UnderlyingType);
|
|
Thread.MemoryBarrier();
|
|
isKnownTypeAttributeChecked = true;
|
|
}
|
|
}
|
|
}
|
|
return knownDataContracts;
|
|
}
|
|
set { knownDataContracts = value; }
|
|
}
|
|
|
|
internal XmlSchemaType XsdType
|
|
{
|
|
get { return xsdType; }
|
|
set { xsdType = value; }
|
|
}
|
|
|
|
internal bool IsAnonymous
|
|
{
|
|
get { return xsdType != null; }
|
|
}
|
|
|
|
internal override bool HasRoot
|
|
{
|
|
get { return hasRoot; }
|
|
set { hasRoot = value; }
|
|
}
|
|
|
|
internal override XmlDictionaryString TopLevelElementName
|
|
{
|
|
get { return topLevelElementName; }
|
|
set { topLevelElementName = value; }
|
|
}
|
|
|
|
internal override XmlDictionaryString TopLevelElementNamespace
|
|
{
|
|
get { return topLevelElementNamespace; }
|
|
set { topLevelElementNamespace = value; }
|
|
}
|
|
|
|
internal bool IsTopLevelElementNullable
|
|
{
|
|
get { return isTopLevelElementNullable; }
|
|
set { isTopLevelElementNullable = value; }
|
|
}
|
|
|
|
internal bool IsTypeDefinedOnImport
|
|
{
|
|
get { return isTypeDefinedOnImport; }
|
|
set { isTypeDefinedOnImport = value; }
|
|
}
|
|
|
|
internal CreateXmlSerializableDelegate CreateXmlSerializableDelegate
|
|
{
|
|
get { return createXmlSerializable; }
|
|
set { createXmlSerializable = value; }
|
|
}
|
|
|
|
}
|
|
|
|
ConstructorInfo GetConstructor()
|
|
{
|
|
Type type = UnderlyingType;
|
|
|
|
if (type.IsValueType)
|
|
return null;
|
|
|
|
ConstructorInfo ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
|
|
if (ctor == null)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.IXmlSerializableMustHaveDefaultConstructor, DataContract.GetClrTypeFullName(type))));
|
|
|
|
return ctor;
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Sets critical properties on XmlDataContract.")]
|
|
[SecurityCritical]
|
|
internal void SetTopLevelElementName(XmlQualifiedName elementName)
|
|
{
|
|
if (elementName != null)
|
|
{
|
|
XmlDictionary dictionary = new XmlDictionary();
|
|
this.TopLevelElementName = dictionary.Add(elementName.Name);
|
|
this.TopLevelElementNamespace = dictionary.Add(elementName.Namespace);
|
|
}
|
|
}
|
|
|
|
#if !NO_DYNAMIC_CODEGEN
|
|
[Fx.Tag.SecurityNote(Critical = "Calls CodeGenerator.BeginMethod which is SecurityCritical.",
|
|
Safe = "Self-contained: returns the delegate to the generated IL but otherwise all IL generation is self-contained here.")]
|
|
[SecuritySafeCritical]
|
|
internal CreateXmlSerializableDelegate GenerateCreateXmlSerializableDelegate()
|
|
{
|
|
Type type = this.UnderlyingType;
|
|
CodeGenerator ilg = new CodeGenerator();
|
|
bool memberAccessFlag = RequiresMemberAccessForCreate(null);
|
|
try
|
|
{
|
|
ilg.BeginMethod("Create" + DataContract.GetClrTypeFullName(type), typeof(CreateXmlSerializableDelegate), memberAccessFlag);
|
|
}
|
|
catch (SecurityException securityException)
|
|
{
|
|
if (memberAccessFlag && securityException.PermissionType.Equals(typeof(ReflectionPermission)))
|
|
{
|
|
RequiresMemberAccessForCreate(securityException);
|
|
}
|
|
else
|
|
{
|
|
throw;
|
|
}
|
|
}
|
|
if (type.IsValueType)
|
|
{
|
|
System.Reflection.Emit.LocalBuilder local = ilg.DeclareLocal(type, type.Name + "Value");
|
|
ilg.Ldloca(local);
|
|
ilg.InitObj(type);
|
|
ilg.Ldloc(local);
|
|
}
|
|
else
|
|
{
|
|
ilg.New(GetConstructor());
|
|
}
|
|
ilg.ConvertValue(this.UnderlyingType, Globals.TypeOfIXmlSerializable);
|
|
ilg.Ret();
|
|
return (CreateXmlSerializableDelegate)ilg.EndMethod();
|
|
}
|
|
#endif
|
|
|
|
#if !NO_DYNAMIC_CODEGEN
|
|
[Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - Calculates whether this Xml type requires MemberAccessPermission for deserialization."
|
|
+ " Since this information is used to determine whether to give the generated code access"
|
|
+ " permissions to private members, any changes to the logic should be reviewed.")]
|
|
bool RequiresMemberAccessForCreate(SecurityException securityException)
|
|
{
|
|
if (!IsTypeVisible(UnderlyingType))
|
|
{
|
|
if (securityException != null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
|
|
new SecurityException(SR.GetString(SR.PartialTrustIXmlSerializableTypeNotPublic, DataContract.GetClrTypeFullName(UnderlyingType)),
|
|
securityException));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (ConstructorRequiresMemberAccess(GetConstructor()))
|
|
{
|
|
if (securityException != null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
|
|
new SecurityException(SR.GetString(SR.PartialTrustIXmlSerialzableNoPublicConstructor, DataContract.GetClrTypeFullName(UnderlyingType)),
|
|
securityException));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
internal override bool Equals(object other, Dictionary<DataContractPairKey, object> checkedContracts)
|
|
{
|
|
if (IsEqualOrChecked(other, checkedContracts))
|
|
return true;
|
|
|
|
XmlDataContract dataContract = other as XmlDataContract;
|
|
if (dataContract != null)
|
|
{
|
|
if (this.HasRoot != dataContract.HasRoot)
|
|
return false;
|
|
|
|
if (this.IsAnonymous)
|
|
{
|
|
return dataContract.IsAnonymous;
|
|
}
|
|
else
|
|
{
|
|
return (StableName.Name == dataContract.StableName.Name && StableName.Namespace == dataContract.StableName.Namespace);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return base.GetHashCode();
|
|
}
|
|
|
|
public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context)
|
|
{
|
|
if (context == null)
|
|
XmlObjectSerializerWriteContext.WriteRootIXmlSerializable(xmlWriter, obj);
|
|
else
|
|
context.WriteIXmlSerializable(xmlWriter, obj);
|
|
}
|
|
|
|
public override object ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)
|
|
{
|
|
object o;
|
|
if (context == null)
|
|
{
|
|
o = XmlObjectSerializerReadContext.ReadRootIXmlSerializable(xmlReader, this, true /*isMemberType*/);
|
|
}
|
|
else
|
|
{
|
|
o = context.ReadIXmlSerializable(xmlReader, this, true /*isMemberType*/);
|
|
context.AddNewObject(o);
|
|
}
|
|
xmlReader.ReadEndElement();
|
|
return o;
|
|
}
|
|
|
|
}
|
|
}
|
|
|