| File: FrameworkFork\System.Runtime.Serialization\System\Runtime\Serialization\XmlDataContract.cs | Web Access |
| Project: src\src\dotnet-svcutil\lib\src\dotnet-svcutil-lib.csproj (dotnet-svcutil-lib) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. namespace System.Runtime.Serialization { using System; using System.Collections.Generic; using System.Reflection; using System.Threading; using Microsoft.Xml; using DataContractDictionary = System.Collections.Generic.Dictionary<Microsoft.Xml.XmlQualifiedName, DataContract>; using Microsoft.Xml.Serialization; using Microsoft.Xml.Schema; using System.Security; using System.Linq; #if NET_NATIVE public delegate IXmlSerializable CreateXmlSerializableDelegate(); public sealed class XmlDataContract : DataContract #else internal delegate IXmlSerializable CreateXmlSerializableDelegate(); internal sealed class XmlDataContract : DataContract #endif { [SecurityCritical] /// <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. /// </SecurityNote> private XmlDataContractCriticalHelper _helper; /// <SecurityNote> /// Critical - initializes SecurityCritical field 'helper' /// Safe - doesn't leak anything /// </SecurityNote> [SecuritySafeCritical] public XmlDataContract() : base(new XmlDataContractCriticalHelper()) { _helper = base.Helper as XmlDataContractCriticalHelper; } /// <SecurityNote> /// Critical - initializes SecurityCritical field 'helper' /// Safe - doesn't leak anything /// </SecurityNote> [SecuritySafeCritical] internal XmlDataContract(Type type) : base(new XmlDataContractCriticalHelper(type)) { _helper = base.Helper as XmlDataContractCriticalHelper; } public override DataContractDictionary KnownDataContracts { /// <SecurityNote> /// Critical - fetches the critical KnownDataContracts property /// Safe - KnownDataContracts only needs to be protected for write /// </SecurityNote> [SecuritySafeCritical] get { return _helper.KnownDataContracts; } /// <SecurityNote> /// Critical - sets the critical KnownDataContracts property /// </SecurityNote> [SecurityCritical] set { _helper.KnownDataContracts = value; } } internal bool IsAnonymous { /// <SecurityNote> /// Critical - fetches the critical IsAnonymous property /// Safe - IsAnonymous only needs to be protected for write /// </SecurityNote> [SecuritySafeCritical] get { return _helper.IsAnonymous; } } public override bool HasRoot { /// <SecurityNote> /// Critical - fetches the critical HasRoot property /// Safe - HasRoot only needs to be protected for write /// </SecurityNote> [SecuritySafeCritical] get { return _helper.HasRoot; } /// <SecurityNote> /// Critical - sets the critical HasRoot property /// </SecurityNote> [SecurityCritical] set { _helper.HasRoot = value; } } public override XmlDictionaryString TopLevelElementName { /// <SecurityNote> /// Critical - fetches the critical TopLevelElementName property /// Safe - TopLevelElementName only needs to be protected for write /// </SecurityNote> [SecuritySafeCritical] get { return _helper.TopLevelElementName; } /// <SecurityNote> /// Critical - sets the critical TopLevelElementName property /// </SecurityNote> [SecurityCritical] set { _helper.TopLevelElementName = value; } } internal XmlSchemaType XsdType { // TODO: [Fx.Tag.SecurityNote(Critical = "Fetches the critical XsdType property.", // Safe = "XsdType only needs to be protected for write.")] [SecuritySafeCritical] get { return _helper.XsdType; } // TODO: [Fx.Tag.SecurityNote(Critical = "Sets the critical XsdType property.")] [SecurityCritical] set { _helper.XsdType = value; } } public override XmlDictionaryString TopLevelElementNamespace { /// <SecurityNote> /// Critical - fetches the critical TopLevelElementNamespace property /// Safe - TopLevelElementNamespace only needs to be protected for write /// </SecurityNote> [SecuritySafeCritical] get { return _helper.TopLevelElementNamespace; } /// <SecurityNote> /// Critical - sets the critical TopLevelElementNamespace property /// </SecurityNote> [SecurityCritical] set { _helper.TopLevelElementNamespace = value; } } internal bool IsTopLevelElementNullable { // TODO: [Fx.Tag.SecurityNote(Critical = "Fetches the critical IsTopLevelElementNullable property.", // Safe = "IsTopLevelElementNullable only needs to be protected for write.")] [SecuritySafeCritical] get { return _helper.IsTopLevelElementNullable; } // TODO: [Fx.Tag.SecurityNote(Critical = "Sets the critical IsTopLevelElementNullable property.")] [SecurityCritical] set { _helper.IsTopLevelElementNullable = value; } } internal bool IsTypeDefinedOnImport { // TODO: [Fx.Tag.SecurityNote(Critical = "Fetches the critical IsTypeDefinedOnImport property.", // Safe = "IsTypeDefinedOnImport only needs to be protected for write.")] [SecuritySafeCritical] get { return _helper.IsTypeDefinedOnImport; } // TODO: [Fx.Tag.SecurityNote(Critical = "Sets the critical IsTypeDefinedOnImport property.")] [SecurityCritical] set { _helper.IsTypeDefinedOnImport = value; } } #if !NET_NATIVE internal CreateXmlSerializableDelegate CreateXmlSerializableDelegate { /// <SecurityNote> /// Critical - fetches the critical CreateXmlSerializableDelegate property /// Safe - CreateXmlSerializableDelegate only needs to be protected for write; initialized in getter if null /// </SecurityNote> [SecuritySafeCritical] get { if (_helper.CreateXmlSerializableDelegate == null) { lock (this) { if (_helper.CreateXmlSerializableDelegate == null) { CreateXmlSerializableDelegate tempCreateXmlSerializable = GenerateCreateXmlSerializableDelegate(); Interlocked.MemoryBarrier(); _helper.CreateXmlSerializableDelegate = tempCreateXmlSerializable; } } } return _helper.CreateXmlSerializableDelegate; } } #else public CreateXmlSerializableDelegate CreateXmlSerializableDelegate { get; set; } #endif internal override bool CanContainReferences { get { return false; } } public override bool IsBuiltInDataContract { get { return UnderlyingType == Globals.TypeOfXmlElement || UnderlyingType == Globals.TypeOfXmlNodeArray; } } /// <SecurityNote> /// Critical - holds all state used for for (de)serializing XML types. /// since the data is cached statically, we lock down access to it. /// </SecurityNote> [SecurityCritical] private class XmlDataContractCriticalHelper : DataContract.DataContractCriticalHelper { private DataContractDictionary _knownDataContracts; private bool _isKnownTypeAttributeChecked; private XmlDictionaryString _topLevelElementName; private XmlDictionaryString _topLevelElementNamespace; private bool _isTopLevelElementNullable; private bool _isTypeDefinedOnImport; private XmlSchemaType _xsdType; private bool _hasRoot; private CreateXmlSerializableDelegate _createXmlSerializable; internal XmlDataContractCriticalHelper() { } internal XmlDataContractCriticalHelper(Type type) : base(type) { if (type.GetTypeInfo().IsAttributeDefined(Globals.TypeOfDataContractAttribute)) throw /*System.Runtime.Serialization.*/DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(string.Format(SRSerialization.IXmlSerializableCannotHaveDataContract, DataContract.GetClrTypeFullName(type)))); if (type.GetTypeInfo().IsAttributeDefined(Globals.TypeOfCollectionDataContractAttribute)) throw /*System.Runtime.Serialization.*/DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(string.Format(SRSerialization.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.GetTypeInfo().GetCustomAttributes(Globals.TypeOfXmlRootAttribute, false).ToArray(); if (xmlRootAttributes == null || xmlRootAttributes.Length == 0) { if (hasRoot) { _topLevelElementName = Name; _topLevelElementNamespace = (this.StableName.Namespace == Globals.SchemaNamespace) ? DictionaryGlobals.EmptyString : Namespace; } } 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(string.Format(SRSerialization.IsAnyCannotHaveXmlRoot, DataContract.GetClrTypeFullName(UnderlyingType)))); } } } internal override DataContractDictionary KnownDataContracts { [SecurityCritical] get { if (!_isKnownTypeAttributeChecked && UnderlyingType != null) { lock (this) { if (!_isKnownTypeAttributeChecked) { _knownDataContracts = DataContract.ImportKnownTypeAttributes(this.UnderlyingType); Interlocked.MemoryBarrier(); _isKnownTypeAttributeChecked = true; } } } return _knownDataContracts; } [SecurityCritical] set { _knownDataContracts = value; } } internal XmlSchemaType XsdType { get { return _xsdType; } set { _xsdType = value; } } internal bool IsAnonymous { get { return false; } } internal override bool HasRoot { get { return _hasRoot; } set { _hasRoot = value; } } internal override XmlDictionaryString TopLevelElementName { [SecurityCritical] get { return _topLevelElementName; } [SecurityCritical] set { _topLevelElementName = value; } } internal override XmlDictionaryString TopLevelElementNamespace { [SecurityCritical] get { return _topLevelElementNamespace; } [SecurityCritical] 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; } } } private ConstructorInfo GetConstructor() { Type type = UnderlyingType; if (type.GetTypeInfo().IsValueType) return null; ConstructorInfo ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, Array.Empty<Type>()); if (ctor == null) throw /*System.Runtime.Serialization.*/DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(string.Format(SRSerialization.IXmlSerializableMustHaveDefaultConstructor, DataContract.GetClrTypeFullName(type)))); return ctor; } //TODO: [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 !NET_NATIVE /// <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 /// </SecurityNote> [SecuritySafeCritical] internal CreateXmlSerializableDelegate GenerateCreateXmlSerializableDelegate() { Type type = this.UnderlyingType; CodeGenerator ilg = new CodeGenerator(); bool memberAccessFlag = RequiresMemberAccessForCreate(null) && !(type.FullName == "System.Xml.Linq.XElement"); try { ilg.BeginMethod("Create" + DataContract.GetClrTypeFullName(type), typeof(CreateXmlSerializableDelegate), memberAccessFlag); } catch (SecurityException securityException) { if (memberAccessFlag) { RequiresMemberAccessForCreate(securityException); } else { throw; } } if (type.GetTypeInfo().IsValueType) { System.Reflection.Emit.LocalBuilder local = ilg.DeclareLocal(type, type.Name + "Value"); ilg.Ldloca(local); ilg.InitObj(type); ilg.Ldloc(local); } else { // Special case XElement // codegen the same as 'internal XElement : this("default") { }' ConstructorInfo ctor = GetConstructor(); if (!ctor.IsPublic && type.FullName == "System.Xml.Linq.XElement") { Type xName = type.GetTypeInfo().Assembly.GetType("System.Xml.Linq.XName"); if (xName != null) { MethodInfo XName_op_Implicit = xName.GetMethod( "op_Implicit", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, new Type[] { typeof(String) } ); ConstructorInfo XElement_ctor = type.GetConstructor( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, new Type[] { xName } ); if (XName_op_Implicit != null && XElement_ctor != null) { ilg.Ldstr("default"); ilg.Call(XName_op_Implicit); ctor = XElement_ctor; } } } ilg.New(ctor); } ilg.ConvertValue(this.UnderlyingType, Globals.TypeOfIXmlSerializable); ilg.Ret(); return (CreateXmlSerializableDelegate)ilg.EndMethod(); } /// <SecurityNote> /// Review - 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. /// </SecurityNote> private bool RequiresMemberAccessForCreate(SecurityException securityException) { if (!IsTypeVisible(UnderlyingType)) { if (securityException != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(string.Format(SRSerialization.PartialTrustIXmlSerializableTypeNotPublic, DataContract.GetClrTypeFullName(UnderlyingType)), securityException)); } return true; } if (ConstructorRequiresMemberAccess(GetConstructor())) { if (securityException != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(string.Format(SRSerialization.PartialTrustIXmlSerialzableNoPublicConstructor, DataContract.GetClrTypeFullName(UnderlyingType)), securityException)); } return true; } return false; } #endif 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; } } }