//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ namespace System.Configuration { using System.Configuration.Internal; using System.Collections; using System.Collections.Specialized; using System.Collections.Generic; using System.Configuration; using System.Text; using System.Threading; using System.Reflection; using System.Xml; [System.Diagnostics.DebuggerDisplay("SectionRecord {ConfigKey}")] internal class SectionRecord { // // Flags constants // // // Runtime flags below 0x10000 // // locked by parent input, either because a parent section is locked, // a parent section locks all children, or a location input for this // configPath has allowOverride=false. private const int Flag_Locked = 0x00000001; // lock children of this section private const int Flag_LockChildren = 0x00000002; // propagation of FactoryRecord.IsFactoryTrustedWithoutAptca private const int Flag_IsResultTrustedWithoutAptca = 0x00000004; // propagation of FactoryRecord.RequirePermission private const int Flag_RequirePermission = 0x00000008; // Look at AddLocationInput for explanation of this flag's purpose private const int Flag_LocationInputLockApplied = 0x00000010; // Look at AddIndirectLocationInput for explanation of this flag's purpose private const int Flag_IndirectLocationInputLockApplied = 0x00000020; // The flag gives us the inherited lock mode for this section record without the file input // We need this to support SectionInformation.OverrideModeEffective. private const int Flag_ChildrenLockWithoutFileInput = 0x00000040; // // Designtime flags at or above 0x00010000 // // the section has been added to the update list private const int Flag_AddUpdate = 0x00010000; // result can be null, so we use this object to indicate whether it has been evaluated static object s_unevaluated = new object(); private SafeBitVector32 _flags; // config key private string _configKey; // The input from location sections // This list is ordered to keep oldest ancestors at the front private List _locationInputs; // The input from this file private SectionInput _fileInput; // This special input is used only when creating a location config record. // The inputs are from location tags which are found in the same config file as the // location config configPath, but point to the parent paths of the location config // configPath. See the comment for VSWhidbey 540184 in Init() in // BaseConfigurationRecord.cs for more details. private List _indirectLocationInputs; // the cached result of evaluating this section private object _result; // the cached result of evaluating this section after GetRuntimeObject is called private object _resultRuntimeObject; internal SectionRecord(string configKey) { _configKey = configKey; _result = s_unevaluated; _resultRuntimeObject = s_unevaluated; } internal string ConfigKey { get {return _configKey;} } internal bool Locked { get {return _flags[Flag_Locked];} } internal bool LockChildren { get {return _flags[Flag_LockChildren];} } internal bool LockChildrenWithoutFileInput { get { // Start assuming we dont have a file input // When we don't have file input the lock mode for children is the same for LockChildren and LockChildrenWithoutFileInput bool result = LockChildren; if (HasFileInput) { result = _flags[Flag_ChildrenLockWithoutFileInput]; } return result; } } internal bool IsResultTrustedWithoutAptca { get {return _flags[Flag_IsResultTrustedWithoutAptca];} set {_flags[Flag_IsResultTrustedWithoutAptca] = value;} } internal bool RequirePermission { get {return _flags[Flag_RequirePermission];} set {_flags[Flag_RequirePermission] = value;} } internal bool AddUpdate { get {return _flags[Flag_AddUpdate];} set {_flags[Flag_AddUpdate] = value;} } internal bool HasLocationInputs { get { return _locationInputs != null && _locationInputs.Count > 0; } } internal List LocationInputs { get {return _locationInputs;} } internal SectionInput LastLocationInput { get { if (HasLocationInputs) { return _locationInputs[_locationInputs.Count - 1]; } else { return null; } } } internal void AddLocationInput(SectionInput sectionInput) { AddLocationInputImpl(sectionInput, false); } internal bool HasFileInput { get { return _fileInput != null; } } internal SectionInput FileInput { get { return _fileInput; } } internal void ChangeLockSettings(OverrideMode forSelf, OverrideMode forChildren) { if (forSelf != OverrideMode.Inherit) { _flags[Flag_Locked] = (forSelf == OverrideMode.Deny); _flags[Flag_LockChildren] = (forSelf == OverrideMode.Deny); } if (forChildren != OverrideMode.Inherit) { _flags[Flag_LockChildren] = ((forSelf == OverrideMode.Deny) || (forChildren == OverrideMode.Deny)); } } // AddFileInput internal void AddFileInput(SectionInput sectionInput) { Debug.Assert(sectionInput != null); _fileInput = sectionInput; if (!sectionInput.HasErrors) { // If the file input has an explciti value for its children locking - use it // Note we dont change the current lock setting if (sectionInput.SectionXmlInfo.OverrideModeSetting.OverrideMode != OverrideMode.Inherit) { // Store the current setting before applying the lock from the file input // So that if the user changes the current OverrideMode on this configKey to "Inherit" // we will know what we are going to inherit ( used in SectionInformation.OverrideModeEffective ) // Note that we cannot use BaseConfigurationRecord.ResolveOverrideModeFromParent as it gives us only the lock // resolved up to our immediate parent which does not inlcude normal and indirect location imputs _flags[Flag_ChildrenLockWithoutFileInput] = LockChildren; ChangeLockSettings(OverrideMode.Inherit, sectionInput.SectionXmlInfo.OverrideModeSetting.OverrideMode); } } } internal void RemoveFileInput() { if (_fileInput != null) { _fileInput = null; // Reset LockChildren flag to the value provided by // location input or inherited sections. _flags[Flag_LockChildren] = Locked; } } internal bool HasIndirectLocationInputs { get { return _indirectLocationInputs != null && _indirectLocationInputs.Count > 0; } } internal List IndirectLocationInputs { get {return _indirectLocationInputs;} } internal SectionInput LastIndirectLocationInput { get { if (HasIndirectLocationInputs) { return _indirectLocationInputs[_indirectLocationInputs.Count - 1]; } else { return null; } } } internal void AddIndirectLocationInput(SectionInput sectionInput) { AddLocationInputImpl(sectionInput, true); } private void AddLocationInputImpl(SectionInput sectionInput, bool isIndirectLocation) { List inputs = isIndirectLocation ? _indirectLocationInputs : _locationInputs; int flag = isIndirectLocation ? Flag_IndirectLocationInputLockApplied : Flag_LocationInputLockApplied; if (inputs == null) { inputs = new List(1); if (isIndirectLocation) { _indirectLocationInputs = inputs; } else { _locationInputs = inputs; } } // The list of locationSections is traversed from child to parent, // so insert at the beginning of the list. inputs.Insert(0, sectionInput); // Only the overrideMode from the parent thats closest to the SectionRecord has effect // // For location input: // Remember that this method will be called for location inputs comming from the immediate parent first // and then walking the hierarchy up to the root level // // For indirect location input: // This method will be first called for indirect input closest to the location config if (!sectionInput.HasErrors) { if (!_flags[flag]) { OverrideMode modeLocation = sectionInput.SectionXmlInfo.OverrideModeSetting.OverrideMode; if (modeLocation != OverrideMode.Inherit) { ChangeLockSettings(modeLocation, modeLocation); _flags[flag] = true; } } } } internal bool HasInput { get { return HasLocationInputs || HasFileInput || HasIndirectLocationInputs; } } internal void ClearRawXml() { if (HasLocationInputs) { foreach (SectionInput locationInput in LocationInputs) { locationInput.SectionXmlInfo.RawXml = null; } } if (HasIndirectLocationInputs) { foreach (SectionInput indirectLocationInput in IndirectLocationInputs) { indirectLocationInput.SectionXmlInfo.RawXml = null; } } if (HasFileInput) { FileInput.SectionXmlInfo.RawXml = null; } } internal bool HasResult { get {return _result != s_unevaluated;} } internal bool HasResultRuntimeObject { get {return _resultRuntimeObject != s_unevaluated;} } internal object Result { get { // Useful assert, but it fires in the debugger when using automatic property evaluation // Debug.Assert(_result != s_unevaluated, "_result != s_unevaluated"); return _result; } set {_result = value;} } internal object ResultRuntimeObject { get { // Useful assert, but it fires in the debugger when using automatic property evaluation // Debug.Assert(_resultRuntimeObject != s_unevaluated, "_resultRuntimeObject != s_unevaluated"); return _resultRuntimeObject; } set { _resultRuntimeObject = value; } } internal void ClearResult() { if (_fileInput != null) { _fileInput.ClearResult(); } if (_locationInputs != null) { foreach (SectionInput input in _locationInputs) { input.ClearResult(); } } _result = s_unevaluated; _resultRuntimeObject = s_unevaluated; } // // Error handling. // private List GetAllErrors() { List allErrors = null; if (HasLocationInputs) { foreach (SectionInput input in LocationInputs) { ErrorsHelper.AddErrors(ref allErrors, input.Errors); } } if (HasIndirectLocationInputs) { foreach (SectionInput input in IndirectLocationInputs) { ErrorsHelper.AddErrors(ref allErrors, input.Errors); } } if (HasFileInput) { ErrorsHelper.AddErrors(ref allErrors, FileInput.Errors); } return allErrors; } internal bool HasErrors { get { if (HasLocationInputs) { foreach (SectionInput input in LocationInputs) { if (input.HasErrors) { return true; } } } if (HasIndirectLocationInputs) { foreach (SectionInput input in IndirectLocationInputs) { if (input.HasErrors) { return true; } } } if (HasFileInput) { if (FileInput.HasErrors) { return true; } } return false; } } internal void ThrowOnErrors() { if (HasErrors) { throw new ConfigurationErrorsException(GetAllErrors()); } } } }