1321 lines
57 KiB
C#
1321 lines
57 KiB
C#
|
//------------------------------------------------------------------------------
|
||
|
// <copyright file="ConfigurationElementCollection.cs" company="Microsoft">
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
// </copyright>
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
using System;
|
||
|
using System.Collections;
|
||
|
using System.Collections.Specialized;
|
||
|
using System.Xml;
|
||
|
|
||
|
namespace System.Configuration {
|
||
|
|
||
|
[System.Diagnostics.DebuggerDisplay("Count = {Count}")]
|
||
|
public abstract class ConfigurationElementCollection : ConfigurationElement, ICollection {
|
||
|
internal const string DefaultAddItemName = "add";
|
||
|
internal const string DefaultRemoveItemName = "remove";
|
||
|
internal const string DefaultClearItemsName = "clear";
|
||
|
|
||
|
private int _removedItemCount = 0; // Number of items removed for this collection (not including parent)
|
||
|
private int _inheritedCount = 0; // Total number of inherited items
|
||
|
private ArrayList _items = new ArrayList();
|
||
|
private String _addElement = DefaultAddItemName;
|
||
|
private String _removeElement = DefaultRemoveItemName;
|
||
|
private String _clearElement = DefaultClearItemsName;
|
||
|
private bool bEmitClearTag = false;
|
||
|
private bool bCollectionCleared = false;
|
||
|
private bool bModified = false;
|
||
|
private bool bReadOnly = false;
|
||
|
private IComparer _comparer;
|
||
|
internal bool internalAddToEnd = false;
|
||
|
internal String internalElementTagName = string.Empty;
|
||
|
|
||
|
protected ConfigurationElementCollection() {
|
||
|
}
|
||
|
|
||
|
protected ConfigurationElementCollection(IComparer comparer) {
|
||
|
if (comparer == null) {
|
||
|
throw new ArgumentNullException("comparer");
|
||
|
}
|
||
|
|
||
|
_comparer = comparer;
|
||
|
}
|
||
|
|
||
|
private ArrayList Items {
|
||
|
get {
|
||
|
return _items;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private enum InheritedType {
|
||
|
inNeither = 0,
|
||
|
inParent = 1,
|
||
|
inSelf = 2,
|
||
|
inBothSame = 3,
|
||
|
inBothDiff = 4,
|
||
|
inBothCopyNoRemove = 5,
|
||
|
}
|
||
|
|
||
|
protected internal string AddElementName {
|
||
|
get {
|
||
|
return _addElement;
|
||
|
}
|
||
|
set {
|
||
|
_addElement = value;
|
||
|
if (BaseConfigurationRecord.IsReservedAttributeName(value)) {
|
||
|
throw new ArgumentException(SR.GetString(SR.Item_name_reserved, DefaultAddItemName, value));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected internal string RemoveElementName {
|
||
|
get {
|
||
|
return _removeElement;
|
||
|
}
|
||
|
set {
|
||
|
if (BaseConfigurationRecord.IsReservedAttributeName(value)) {
|
||
|
throw new ArgumentException(SR.GetString(SR.Item_name_reserved, DefaultRemoveItemName, value));
|
||
|
}
|
||
|
_removeElement = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected internal string ClearElementName {
|
||
|
get {
|
||
|
return _clearElement;
|
||
|
}
|
||
|
set {
|
||
|
if (BaseConfigurationRecord.IsReservedAttributeName(value)) {
|
||
|
throw new ArgumentException(SR.GetString(SR.Item_name_reserved, DefaultClearItemsName, value));
|
||
|
}
|
||
|
_clearElement = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// AssociateContext
|
||
|
//
|
||
|
// Associate a collection of values with a configRecord
|
||
|
//
|
||
|
internal override void AssociateContext(BaseConfigurationRecord configRecord) {
|
||
|
base.AssociateContext(configRecord);
|
||
|
|
||
|
foreach (Entry entry in _items) {
|
||
|
if (entry._value != null) {
|
||
|
entry._value.AssociateContext(configRecord);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected internal override bool IsModified() {
|
||
|
if (bModified == true) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if (base.IsModified() == true) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
foreach (Entry entry in _items) {
|
||
|
if (entry._entryType != EntryType.Removed) {
|
||
|
ConfigurationElement elem = entry._value;
|
||
|
if (elem.IsModified()) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
protected internal override void ResetModified() {
|
||
|
bModified = false;
|
||
|
base.ResetModified();
|
||
|
|
||
|
foreach (Entry entry in _items) {
|
||
|
if (entry._entryType != EntryType.Removed) {
|
||
|
ConfigurationElement elem = entry._value;
|
||
|
elem.ResetModified();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override bool IsReadOnly() {
|
||
|
return bReadOnly;
|
||
|
}
|
||
|
|
||
|
protected internal override void SetReadOnly() {
|
||
|
bReadOnly = true;
|
||
|
foreach (Entry entry in _items) {
|
||
|
if (entry._entryType != EntryType.Removed) {
|
||
|
ConfigurationElement elem = entry._value;
|
||
|
elem.SetReadOnly();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal virtual IEnumerator GetEnumeratorImpl() {
|
||
|
return new Enumerator(_items, this);
|
||
|
}
|
||
|
|
||
|
internal IEnumerator GetElementsEnumerator() {
|
||
|
// Return an enumerator over the collection's config elements.
|
||
|
// This is different then the std GetEnumerator because the second one
|
||
|
// can return different set of items if overriden in a derived class
|
||
|
|
||
|
return new Enumerator(_items, this);
|
||
|
}
|
||
|
|
||
|
public override bool Equals(object compareTo) {
|
||
|
if (compareTo.GetType() == this.GetType()) {
|
||
|
ConfigurationElementCollection compareToElem = (ConfigurationElementCollection)compareTo;
|
||
|
if (this.Count != compareToElem.Count) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
foreach (Entry thisEntry in Items) {
|
||
|
bool found = false;
|
||
|
foreach (Entry compareEntry in compareToElem.Items) {
|
||
|
if (Object.Equals(thisEntry._value, compareEntry._value)) {
|
||
|
found = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (found == false) {
|
||
|
// not in the collection must be different
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public override int GetHashCode() {
|
||
|
int hHashCode = 0;
|
||
|
foreach (Entry thisEntry in Items) {
|
||
|
ConfigurationElement elem = thisEntry._value;
|
||
|
hHashCode ^= elem.GetHashCode();
|
||
|
}
|
||
|
return hHashCode;
|
||
|
}
|
||
|
|
||
|
|
||
|
protected internal override void Unmerge(ConfigurationElement sourceElement,
|
||
|
ConfigurationElement parentElement,
|
||
|
ConfigurationSaveMode saveMode) {
|
||
|
|
||
|
base.Unmerge(sourceElement, parentElement, saveMode);
|
||
|
if (sourceElement != null) {
|
||
|
ConfigurationElementCollection parentCollection = parentElement as ConfigurationElementCollection;
|
||
|
ConfigurationElementCollection sourceCollection = sourceElement as ConfigurationElementCollection;
|
||
|
Hashtable Inheritance = new Hashtable();
|
||
|
_lockedAllExceptAttributesList = sourceElement._lockedAllExceptAttributesList;
|
||
|
_lockedAllExceptElementsList = sourceElement._lockedAllExceptElementsList;
|
||
|
_fItemLocked = sourceElement._fItemLocked;
|
||
|
_lockedAttributesList = sourceElement._lockedAttributesList;
|
||
|
_lockedElementsList = sourceElement._lockedElementsList;
|
||
|
|
||
|
AssociateContext(sourceElement._configRecord);
|
||
|
|
||
|
if (parentElement != null) {
|
||
|
if (parentElement._lockedAttributesList != null)
|
||
|
_lockedAttributesList = UnMergeLockList(sourceElement._lockedAttributesList,
|
||
|
parentElement._lockedAttributesList, saveMode);
|
||
|
if (parentElement._lockedElementsList != null)
|
||
|
_lockedElementsList = UnMergeLockList(sourceElement._lockedElementsList,
|
||
|
parentElement._lockedElementsList, saveMode);
|
||
|
if (parentElement._lockedAllExceptAttributesList != null)
|
||
|
_lockedAllExceptAttributesList = UnMergeLockList(sourceElement._lockedAllExceptAttributesList,
|
||
|
parentElement._lockedAllExceptAttributesList, saveMode);
|
||
|
if (parentElement._lockedAllExceptElementsList != null)
|
||
|
_lockedAllExceptElementsList = UnMergeLockList(sourceElement._lockedAllExceptElementsList,
|
||
|
parentElement._lockedAllExceptElementsList, saveMode);
|
||
|
}
|
||
|
|
||
|
if (CollectionType == ConfigurationElementCollectionType.AddRemoveClearMap ||
|
||
|
CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
|
||
|
// When writing out portable configurations the <clear/> tag should be written
|
||
|
bCollectionCleared = sourceCollection.bCollectionCleared;
|
||
|
EmitClear = (saveMode == ConfigurationSaveMode.Full && (_clearElement.Length != 0)) ||
|
||
|
(saveMode == ConfigurationSaveMode.Modified && bCollectionCleared) ?
|
||
|
true : sourceCollection.EmitClear;
|
||
|
|
||
|
if ((parentCollection != null) && (EmitClear != true)) {
|
||
|
foreach (Entry entry in parentCollection.Items) {
|
||
|
if (entry._entryType != EntryType.Removed) {
|
||
|
Inheritance[entry.GetKey(this)] = InheritedType.inParent;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
foreach (Entry entry in sourceCollection.Items) {
|
||
|
if (entry._entryType != EntryType.Removed) {
|
||
|
if (Inheritance.Contains(entry.GetKey(this))) {
|
||
|
Entry parentEntry = (Entry)parentCollection.Items[parentCollection.RealIndexOf(entry._value)];
|
||
|
|
||
|
ConfigurationElement elem = entry._value;
|
||
|
if (elem.Equals(parentEntry._value)) {
|
||
|
// in modified mode we consider any change to be different than the parent
|
||
|
Inheritance[entry.GetKey(this)] = InheritedType.inBothSame;
|
||
|
if (saveMode == ConfigurationSaveMode.Modified) {
|
||
|
if (elem.IsModified()) {
|
||
|
Inheritance[entry.GetKey(this)] = InheritedType.inBothDiff;
|
||
|
} else
|
||
|
if (elem.ElementPresent) {
|
||
|
// This is when the source file contained the entry but it was an
|
||
|
// exact copy. We don't want to emit a remove so we treat it as
|
||
|
// a special case.
|
||
|
Inheritance[entry.GetKey(this)] = InheritedType.inBothCopyNoRemove;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
Inheritance[entry.GetKey(this)] = InheritedType.inBothDiff;
|
||
|
if (CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate
|
||
|
&& entry._entryType == EntryType.Added) {
|
||
|
// this is a special case for deailing with defect number 529517
|
||
|
// this code allow the config to write out the same xml when no remove was
|
||
|
// present during deserialization.
|
||
|
Inheritance[entry.GetKey(this)] = InheritedType.inBothCopyNoRemove;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else { // not in parent
|
||
|
Inheritance[entry.GetKey(this)] = InheritedType.inSelf;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
if ((parentCollection != null) && (EmitClear != true)) {
|
||
|
foreach (Entry entry in parentCollection.Items) {
|
||
|
if (entry._entryType != EntryType.Removed) {
|
||
|
|
||
|
InheritedType tp = (InheritedType)Inheritance[entry.GetKey(this)];
|
||
|
if (tp == InheritedType.inParent || tp == InheritedType.inBothDiff) {
|
||
|
ConfigurationElement elem = CallCreateNewElement(entry.GetKey(this).ToString());
|
||
|
|
||
|
elem.Reset(entry._value); // copy this entry
|
||
|
BaseAdd(elem,ThrowOnDuplicate,true); // Add it (so that is once existed in the temp
|
||
|
BaseRemove(entry.GetKey(this), false); // now remove it to for a remove instruction
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
foreach (Entry entry in sourceCollection.Items) {
|
||
|
if (entry._entryType != EntryType.Removed) {
|
||
|
InheritedType tp = (InheritedType)Inheritance[entry.GetKey(this)];
|
||
|
|
||
|
if (tp == InheritedType.inSelf || tp == InheritedType.inBothDiff ||
|
||
|
tp == InheritedType.inBothCopyNoRemove) {
|
||
|
ConfigurationElement elem = CallCreateNewElement(entry.GetKey(this).ToString());
|
||
|
|
||
|
elem.Unmerge(entry._value, null, saveMode);
|
||
|
|
||
|
if (tp == InheritedType.inSelf) {
|
||
|
elem.RemoveAllInheritedLocks(); // If the key changed only local locks are kept
|
||
|
}
|
||
|
|
||
|
BaseAdd(elem,ThrowOnDuplicate,true); // Add it
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (CollectionType == ConfigurationElementCollectionType.BasicMap ||
|
||
|
CollectionType == ConfigurationElementCollectionType.BasicMapAlternate) {
|
||
|
foreach (Entry entry in sourceCollection.Items) {
|
||
|
bool FoundKeyInParent = false;
|
||
|
Entry parentEntrySaved = null;
|
||
|
|
||
|
if (entry._entryType == EntryType.Added ||
|
||
|
entry._entryType == EntryType.Replaced) {
|
||
|
bool InParent = false;
|
||
|
|
||
|
if (parentCollection != null) {
|
||
|
foreach (Entry parentEntry in parentCollection.Items) {
|
||
|
if (Object.Equals(entry.GetKey(this), parentEntry.GetKey(this))) {
|
||
|
// for basic map collection where the key is actually an element
|
||
|
// we do not want the merging behavior or data will not get written
|
||
|
// out for the properties if they match the first element deamed to be a parent
|
||
|
// For example <allow verbs="NewVerb" users="*"/> will loose the users because
|
||
|
// an entry exists in the root element.
|
||
|
if (!IsElementName(entry.GetKey(this).ToString())) {
|
||
|
// For elements which are not keyed by the element name
|
||
|
// need to be unmerged
|
||
|
FoundKeyInParent = true;
|
||
|
parentEntrySaved = parentEntry;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (Object.Equals(entry._value, parentEntry._value)) {
|
||
|
FoundKeyInParent = true;
|
||
|
InParent = true; // in parent and the same exact values
|
||
|
parentEntrySaved = parentEntry;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ConfigurationElement elem = CallCreateNewElement(entry.GetKey(this).ToString());
|
||
|
|
||
|
if (!FoundKeyInParent) { // Unmerge is similar to a reset when used like this
|
||
|
// except that it handles the different update modes
|
||
|
// which Reset does not understand
|
||
|
elem.Unmerge(entry._value, null, saveMode); // copy this entry
|
||
|
BaseAdd(-1, elem,true); // Add it
|
||
|
}
|
||
|
else {
|
||
|
ConfigurationElement sourceItem = entry._value;
|
||
|
if (!InParent ||
|
||
|
(saveMode == ConfigurationSaveMode.Modified && sourceItem.IsModified()) ||
|
||
|
(saveMode == ConfigurationSaveMode.Full)) {
|
||
|
elem.Unmerge(entry._value, parentEntrySaved._value, saveMode);
|
||
|
BaseAdd(-1, elem,true); // Add it
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected internal override void Reset(ConfigurationElement parentElement) {
|
||
|
ConfigurationElementCollection parentCollection = parentElement as ConfigurationElementCollection;
|
||
|
ResetLockLists(parentElement);
|
||
|
|
||
|
if (parentCollection != null) {
|
||
|
foreach (Entry entry in parentCollection.Items) {
|
||
|
ConfigurationElement elem = CallCreateNewElement(entry.GetKey(this).ToString());
|
||
|
elem.Reset(entry._value);
|
||
|
|
||
|
if ((CollectionType == ConfigurationElementCollectionType.AddRemoveClearMap ||
|
||
|
CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) &&
|
||
|
(entry._entryType == EntryType.Added ||
|
||
|
entry._entryType == EntryType.Replaced)) { // do not add removed items from the parent
|
||
|
BaseAdd(elem, true, true); // This version combines dups and throws (unless overridden)
|
||
|
}
|
||
|
else {
|
||
|
if (CollectionType == ConfigurationElementCollectionType.BasicMap ||
|
||
|
CollectionType == ConfigurationElementCollectionType.BasicMapAlternate) {
|
||
|
BaseAdd(-1, elem, true); // this version appends regardless of if it is a dup.
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
_inheritedCount = Count; // After reset the count is the number of items actually inherited.
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public int Count {
|
||
|
get {
|
||
|
return _items.Count - _removedItemCount;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public bool EmitClear {
|
||
|
get {
|
||
|
return bEmitClearTag;
|
||
|
}
|
||
|
set {
|
||
|
if (IsReadOnly()) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_read_only));
|
||
|
}
|
||
|
if (value == true) {
|
||
|
CheckLockedElement(_clearElement, null); // has clear been locked?
|
||
|
CheckLockedElement(_removeElement, null); // has remove been locked? Clear implies remove
|
||
|
}
|
||
|
bModified = true;
|
||
|
bEmitClearTag = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public bool IsSynchronized {
|
||
|
get {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Object SyncRoot {
|
||
|
get {
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void CopyTo(ConfigurationElement[] array, int index) {
|
||
|
((ICollection)this).CopyTo(array, index);
|
||
|
}
|
||
|
|
||
|
void ICollection.CopyTo(Array arr, int index) {
|
||
|
foreach (Entry entry in _items) {
|
||
|
if (entry._entryType != EntryType.Removed) {
|
||
|
arr.SetValue(entry._value, index++);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public IEnumerator GetEnumerator() {
|
||
|
return GetEnumeratorImpl();
|
||
|
}
|
||
|
|
||
|
protected virtual void BaseAdd(ConfigurationElement element) {
|
||
|
BaseAdd(element, ThrowOnDuplicate);
|
||
|
}
|
||
|
|
||
|
protected internal void BaseAdd(ConfigurationElement element, bool throwIfExists) {
|
||
|
BaseAdd(element, throwIfExists, false);
|
||
|
}
|
||
|
|
||
|
private void BaseAdd(ConfigurationElement element, bool throwIfExists, bool ignoreLocks) {
|
||
|
bool flagAsReplaced = false;
|
||
|
bool localAddToEnd = internalAddToEnd;
|
||
|
|
||
|
if (IsReadOnly()) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_read_only));
|
||
|
}
|
||
|
|
||
|
if (LockItem == true && ignoreLocks == false) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_element_locked, _addElement));
|
||
|
}
|
||
|
|
||
|
Object key = GetElementKeyInternal(element);
|
||
|
int iFoundItem = -1;
|
||
|
for (int index = 0; index < _items.Count; index++) {
|
||
|
Entry entry = (Entry)_items[index];
|
||
|
if (CompareKeys(key, entry.GetKey(this))) {
|
||
|
if (entry._value != null && entry._value.LockItem == true && ignoreLocks == false) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_item_locked));
|
||
|
}
|
||
|
if (entry._entryType != EntryType.Removed && throwIfExists) {
|
||
|
if (!element.Equals(entry._value)) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_entry_already_exists, key),
|
||
|
element.PropertyFileName(""), element.PropertyLineNumber(""));
|
||
|
}
|
||
|
else {
|
||
|
entry._value = element;
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
if (entry._entryType != EntryType.Added) {
|
||
|
if ((CollectionType == ConfigurationElementCollectionType.AddRemoveClearMap ||
|
||
|
CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) &&
|
||
|
entry._entryType == EntryType.Removed &&
|
||
|
_removedItemCount > 0) {
|
||
|
_removedItemCount--; // account for the value
|
||
|
}
|
||
|
entry._entryType = EntryType.Replaced;
|
||
|
flagAsReplaced = true;
|
||
|
}
|
||
|
if (localAddToEnd ||
|
||
|
CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
|
||
|
iFoundItem = index;
|
||
|
if (entry._entryType == EntryType.Added) {
|
||
|
// this is a special case for defect number 529517 to emulate everett behavior
|
||
|
localAddToEnd = true;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
else {
|
||
|
// check to see if the element is trying to set a locked property.
|
||
|
if (ignoreLocks == false) {
|
||
|
element.HandleLockedAttributes(entry._value);
|
||
|
// copy the lock from the removed element before setting the new element
|
||
|
element.MergeLocks(entry._value);
|
||
|
}
|
||
|
entry._value = element;
|
||
|
bModified = true;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Brand new item.
|
||
|
if (iFoundItem >= 0) {
|
||
|
_items.RemoveAt(iFoundItem);
|
||
|
|
||
|
// if the item being removed was inherited adjust the cout
|
||
|
if (CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate &&
|
||
|
iFoundItem > Count + _removedItemCount - _inheritedCount) {
|
||
|
_inheritedCount--;
|
||
|
}
|
||
|
}
|
||
|
BaseAddInternal(localAddToEnd ? -1 : iFoundItem, element, flagAsReplaced, ignoreLocks);
|
||
|
bModified = true;
|
||
|
}
|
||
|
|
||
|
protected int BaseIndexOf(ConfigurationElement element) {
|
||
|
int index = 0;
|
||
|
Object key = GetElementKeyInternal(element);
|
||
|
foreach (Entry entry in _items) {
|
||
|
if (entry._entryType != EntryType.Removed) {
|
||
|
if (CompareKeys(key, entry.GetKey(this))) {
|
||
|
return index;
|
||
|
}
|
||
|
index++;
|
||
|
}
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
internal int RealIndexOf(ConfigurationElement element) {
|
||
|
int index = 0;
|
||
|
Object key = GetElementKeyInternal(element);
|
||
|
foreach (Entry entry in _items) {
|
||
|
if (CompareKeys(key, entry.GetKey(this))) {
|
||
|
return index;
|
||
|
}
|
||
|
index++;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
private void BaseAddInternal(int index, ConfigurationElement element, bool flagAsReplaced, bool ignoreLocks) {
|
||
|
// Allow the element to initialize itself after its
|
||
|
// constructor has been run so that it may access
|
||
|
// virtual methods.
|
||
|
|
||
|
element.AssociateContext(_configRecord);
|
||
|
if (element != null) {
|
||
|
element.CallInit();
|
||
|
}
|
||
|
|
||
|
if (IsReadOnly()) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_read_only));
|
||
|
}
|
||
|
|
||
|
if (!ignoreLocks) { // during reset we ignore locks so we can copy the elements
|
||
|
if(CollectionType == ConfigurationElementCollectionType.BasicMap ||
|
||
|
CollectionType == ConfigurationElementCollectionType.BasicMapAlternate) {
|
||
|
if (BaseConfigurationRecord.IsReservedAttributeName(ElementName)) {
|
||
|
throw new ArgumentException(SR.GetString(SR.Basicmap_item_name_reserved, ElementName));
|
||
|
}
|
||
|
CheckLockedElement(ElementName, null);
|
||
|
}
|
||
|
if(CollectionType == ConfigurationElementCollectionType.AddRemoveClearMap ||
|
||
|
CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
|
||
|
|
||
|
CheckLockedElement(_addElement, null);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (CollectionType == ConfigurationElementCollectionType.BasicMapAlternate ||
|
||
|
CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
|
||
|
if (index == -1) {
|
||
|
index = Count + _removedItemCount - _inheritedCount; // insert before inherited, but after any removed
|
||
|
}
|
||
|
else {
|
||
|
if (index > Count + _removedItemCount - _inheritedCount && flagAsReplaced == false) {
|
||
|
throw (new ConfigurationErrorsException(SR.GetString(SR.Config_base_cannot_add_items_below_inherited_items)));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (CollectionType == ConfigurationElementCollectionType.BasicMap &&
|
||
|
index >= 0 &&
|
||
|
index < _inheritedCount) {
|
||
|
throw (new ConfigurationErrorsException(SR.GetString(SR.Config_base_cannot_add_items_above_inherited_items)));
|
||
|
}
|
||
|
|
||
|
EntryType entryType = (flagAsReplaced == false) ? EntryType.Added : EntryType.Replaced;
|
||
|
|
||
|
Object key = GetElementKeyInternal(element);
|
||
|
|
||
|
if (index >= 0) {
|
||
|
if (index > _items.Count) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.IndexOutOfRange, index));
|
||
|
}
|
||
|
_items.Insert(index, new Entry(entryType, key, element));
|
||
|
}
|
||
|
else {
|
||
|
_items.Add(new Entry(entryType, key, element));
|
||
|
}
|
||
|
|
||
|
bModified = true;
|
||
|
}
|
||
|
|
||
|
|
||
|
protected virtual void BaseAdd(int index, ConfigurationElement element) {
|
||
|
BaseAdd(index, element, false);
|
||
|
}
|
||
|
|
||
|
private void BaseAdd(int index, ConfigurationElement element, bool ignoreLocks) {
|
||
|
if (IsReadOnly()) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_read_only));
|
||
|
}
|
||
|
if (index < -1) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.IndexOutOfRange, index));
|
||
|
}
|
||
|
|
||
|
if ((index != -1) &&
|
||
|
(CollectionType == ConfigurationElementCollectionType.AddRemoveClearMap ||
|
||
|
CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate)) {
|
||
|
|
||
|
// If it's an AddRemoveClearMap*** collection, turn the index passed into into a real internal index
|
||
|
int realIndex = 0;
|
||
|
|
||
|
if (index > 0) {
|
||
|
foreach (Entry entryfound in _items) {
|
||
|
if (entryfound._entryType != EntryType.Removed) {
|
||
|
index--;
|
||
|
}
|
||
|
if (index == 0) {
|
||
|
break;
|
||
|
}
|
||
|
realIndex++;
|
||
|
}
|
||
|
index = ++realIndex;
|
||
|
}
|
||
|
// check for duplicates
|
||
|
Object key = GetElementKeyInternal(element);
|
||
|
foreach (Entry entry in _items) {
|
||
|
if (CompareKeys(key, entry.GetKey(this))) {
|
||
|
if (entry._entryType != EntryType.Removed) {
|
||
|
if (!element.Equals(entry._value)) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_entry_already_exists, key),
|
||
|
element.PropertyFileName(""), element.PropertyLineNumber(""));
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
BaseAddInternal(index, element, false, ignoreLocks);
|
||
|
}
|
||
|
|
||
|
protected internal void BaseRemove(Object key) {
|
||
|
BaseRemove(key, false);
|
||
|
}
|
||
|
|
||
|
private void BaseRemove(Object key, bool throwIfMissing) {
|
||
|
if (IsReadOnly())
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_read_only));
|
||
|
|
||
|
int index = 0;
|
||
|
bool foundEntry = false;
|
||
|
foreach (Entry entry in _items) {
|
||
|
if (CompareKeys(key, entry.GetKey(this))) {
|
||
|
foundEntry = true;
|
||
|
|
||
|
if (entry._value == null) // A phoney delete is already present
|
||
|
{
|
||
|
if (throwIfMissing) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_entry_not_found, key));
|
||
|
}
|
||
|
else {
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (entry._value.LockItem == true) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_attribute_locked, key));
|
||
|
}
|
||
|
|
||
|
if (entry._value.ElementPresent == false) {
|
||
|
CheckLockedElement(_removeElement, null); // has remove been locked?
|
||
|
}
|
||
|
|
||
|
switch (entry._entryType) {
|
||
|
case EntryType.Added:
|
||
|
if (CollectionType != ConfigurationElementCollectionType.AddRemoveClearMap &&
|
||
|
CollectionType != ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
|
||
|
if (CollectionType == ConfigurationElementCollectionType.BasicMapAlternate) {
|
||
|
if (index >= Count - _inheritedCount) {
|
||
|
throw (new ConfigurationErrorsException(SR.GetString(SR.Config_base_cannot_remove_inherited_items)));
|
||
|
}
|
||
|
}
|
||
|
if (CollectionType == ConfigurationElementCollectionType.BasicMap) {
|
||
|
if (index < _inheritedCount) {
|
||
|
throw (new ConfigurationErrorsException(SR.GetString(SR.Config_base_cannot_remove_inherited_items)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_items.RemoveAt(index);
|
||
|
}
|
||
|
else {
|
||
|
// don't really remove it from the collection just mark it removed
|
||
|
entry._entryType = EntryType.Removed;
|
||
|
_removedItemCount++;
|
||
|
}
|
||
|
break;
|
||
|
case EntryType.Removed:
|
||
|
if (throwIfMissing) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_entry_already_removed));
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
if (CollectionType != ConfigurationElementCollectionType.AddRemoveClearMap &&
|
||
|
CollectionType != ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_elements_may_not_be_removed));
|
||
|
}
|
||
|
entry._entryType = EntryType.Removed;
|
||
|
_removedItemCount++;
|
||
|
break;
|
||
|
}
|
||
|
bModified = true;
|
||
|
return;
|
||
|
}
|
||
|
index++;
|
||
|
}
|
||
|
// Note because it is possible for removes to get orphaned by the API they will
|
||
|
// not cause a throw from the base classes. The scenerio is:
|
||
|
// Add an item in a parent level
|
||
|
// remove the item in a child level
|
||
|
// remove the item at the parent level.
|
||
|
//
|
||
|
// throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_entry_not_found));
|
||
|
if (foundEntry == false) {
|
||
|
if (throwIfMissing) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_entry_not_found, key));
|
||
|
}
|
||
|
|
||
|
if (CollectionType == ConfigurationElementCollectionType.AddRemoveClearMap ||
|
||
|
CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
|
||
|
if (CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
|
||
|
_items.Insert(Count + _removedItemCount - _inheritedCount, new Entry(EntryType.Removed, key, null));
|
||
|
}
|
||
|
else {
|
||
|
_items.Add(new Entry(EntryType.Removed, key, null));
|
||
|
}
|
||
|
_removedItemCount++;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected internal ConfigurationElement BaseGet(Object key) {
|
||
|
foreach (Entry entry in _items) {
|
||
|
if (entry._entryType != EntryType.Removed) {
|
||
|
if (CompareKeys(key, entry.GetKey(this))) {
|
||
|
return entry._value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
protected internal bool BaseIsRemoved(Object key) {
|
||
|
foreach (Entry entry in _items) {
|
||
|
if (CompareKeys(key, entry.GetKey(this))) {
|
||
|
if (entry._entryType == EntryType.Removed) {
|
||
|
return true;
|
||
|
}
|
||
|
else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
protected internal ConfigurationElement BaseGet(int index) {
|
||
|
if (index < 0) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.IndexOutOfRange, index));
|
||
|
}
|
||
|
|
||
|
int VirtualIndex = 0;
|
||
|
Entry entry = (Entry)null;
|
||
|
|
||
|
foreach (Entry entryfound in _items) {
|
||
|
if (VirtualIndex == index && (entryfound._entryType != EntryType.Removed)) {
|
||
|
entry = entryfound;
|
||
|
break;
|
||
|
}
|
||
|
if (entryfound._entryType != EntryType.Removed) {
|
||
|
VirtualIndex++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (entry != null) {
|
||
|
return entry._value;
|
||
|
}
|
||
|
else {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.IndexOutOfRange, index));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected internal object[] BaseGetAllKeys() {
|
||
|
object[] keys = new object[Count];
|
||
|
int index = 0;
|
||
|
foreach (Entry entry in _items) {
|
||
|
if (entry._entryType != EntryType.Removed) {
|
||
|
keys[index] = entry.GetKey(this);
|
||
|
index++;
|
||
|
}
|
||
|
}
|
||
|
return keys;
|
||
|
}
|
||
|
|
||
|
protected internal object BaseGetKey(int index) {
|
||
|
int VirtualIndex = 0;
|
||
|
Entry entry = (Entry)null;
|
||
|
if (index < 0) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.IndexOutOfRange, index));
|
||
|
}
|
||
|
|
||
|
foreach (Entry entryfound in _items) {
|
||
|
if (VirtualIndex == index && (entryfound._entryType != EntryType.Removed)) {
|
||
|
entry = entryfound;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (entryfound._entryType != EntryType.Removed) {
|
||
|
VirtualIndex++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Entry entry = (Entry)_items[index];
|
||
|
if (entry != null) {
|
||
|
object key = entry.GetKey(this);
|
||
|
|
||
|
return key;
|
||
|
}
|
||
|
else {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.IndexOutOfRange, index));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected internal void BaseClear() {
|
||
|
if (IsReadOnly()) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_read_only));
|
||
|
}
|
||
|
|
||
|
CheckLockedElement(_clearElement, null); // has clear been locked?
|
||
|
CheckLockedElement(_removeElement, null); // has remove been locked? Clear implies remove
|
||
|
|
||
|
bModified = true;
|
||
|
bCollectionCleared = true;
|
||
|
if ((CollectionType == ConfigurationElementCollectionType.BasicMap ||
|
||
|
CollectionType == ConfigurationElementCollectionType.BasicMapAlternate)
|
||
|
&& _inheritedCount > 0) {
|
||
|
int RemoveIndex = 0;
|
||
|
if (CollectionType == ConfigurationElementCollectionType.BasicMapAlternate) {
|
||
|
RemoveIndex = 0; // Inherited items are at the bottom and cannot be removed
|
||
|
}
|
||
|
if (CollectionType == ConfigurationElementCollectionType.BasicMap) {
|
||
|
RemoveIndex = _inheritedCount; // inherited items are at the top and cannot be removed
|
||
|
}
|
||
|
while (Count - _inheritedCount > 0) {
|
||
|
_items.RemoveAt(RemoveIndex);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// do not clear any locked items
|
||
|
// _items.Clear();
|
||
|
int inheritedRemoved = 0;
|
||
|
int removedRemoved = 0;
|
||
|
int initialCount = Count;
|
||
|
|
||
|
// check for locks before removing any items from the collection
|
||
|
for (int CheckIndex = 0; CheckIndex < _items.Count; CheckIndex++) {
|
||
|
Entry entry = (Entry)_items[CheckIndex];
|
||
|
if (entry._value != null && entry._value.LockItem == true) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_item_locked_cannot_clear));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (int RemoveIndex = _items.Count - 1; RemoveIndex >= 0; RemoveIndex--) {
|
||
|
Entry entry = (Entry)_items[RemoveIndex];
|
||
|
if ((CollectionType == ConfigurationElementCollectionType.AddRemoveClearMap &&
|
||
|
RemoveIndex < _inheritedCount) ||
|
||
|
(CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate &&
|
||
|
(RemoveIndex >= initialCount - _inheritedCount))) {
|
||
|
inheritedRemoved++;
|
||
|
}
|
||
|
if (entry._entryType == EntryType.Removed) {
|
||
|
removedRemoved++;
|
||
|
}
|
||
|
|
||
|
_items.RemoveAt(RemoveIndex);
|
||
|
}
|
||
|
_inheritedCount -= inheritedRemoved;
|
||
|
_removedItemCount -= removedRemoved;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected internal void BaseRemoveAt(int index) {
|
||
|
if (IsReadOnly()) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_read_only));
|
||
|
}
|
||
|
int VirtualIndex = 0;
|
||
|
Entry entry = (Entry)null;
|
||
|
|
||
|
foreach (Entry entryfound in _items) {
|
||
|
if (VirtualIndex == index && (entryfound._entryType != EntryType.Removed)) {
|
||
|
entry = entryfound;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (entryfound._entryType != EntryType.Removed) {
|
||
|
VirtualIndex++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (entry == null) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.IndexOutOfRange, index));
|
||
|
}
|
||
|
else {
|
||
|
if (entry._value.LockItem == true) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_attribute_locked, entry.GetKey(this)));
|
||
|
}
|
||
|
|
||
|
if (entry._value.ElementPresent == false) {
|
||
|
CheckLockedElement(_removeElement, null); // has remove been locked?
|
||
|
}
|
||
|
|
||
|
switch (entry._entryType) {
|
||
|
case EntryType.Added:
|
||
|
if (CollectionType != ConfigurationElementCollectionType.AddRemoveClearMap &&
|
||
|
CollectionType != ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
|
||
|
if (CollectionType == ConfigurationElementCollectionType.BasicMapAlternate) {
|
||
|
if (index >= Count - _inheritedCount) {
|
||
|
throw (new ConfigurationErrorsException(SR.GetString(SR.Config_base_cannot_remove_inherited_items)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (CollectionType == ConfigurationElementCollectionType.BasicMap) {
|
||
|
if (index < _inheritedCount) {
|
||
|
throw (new ConfigurationErrorsException(SR.GetString(SR.Config_base_cannot_remove_inherited_items)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_items.RemoveAt(index);
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
// don't really remove it from the collection just mark it removed
|
||
|
if (entry._value.ElementPresent == false) {
|
||
|
CheckLockedElement(_removeElement, null); // has remove been locked?
|
||
|
}
|
||
|
|
||
|
entry._entryType = EntryType.Removed;
|
||
|
_removedItemCount++;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case EntryType.Removed:
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_entry_already_removed));
|
||
|
|
||
|
default:
|
||
|
if (CollectionType != ConfigurationElementCollectionType.AddRemoveClearMap &&
|
||
|
CollectionType != ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_elements_may_not_be_removed));
|
||
|
}
|
||
|
|
||
|
entry._entryType = EntryType.Removed;
|
||
|
_removedItemCount++;
|
||
|
break;
|
||
|
}
|
||
|
bModified = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
protected internal override bool SerializeElement(XmlWriter writer, bool serializeCollectionKey) {
|
||
|
ConfigurationElementCollectionType type = CollectionType;
|
||
|
bool DataToWrite = false;
|
||
|
|
||
|
DataToWrite |= base.SerializeElement(writer, serializeCollectionKey);
|
||
|
|
||
|
if (type == ConfigurationElementCollectionType.AddRemoveClearMap ||
|
||
|
type == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
|
||
|
// it is possible that the collection only has to be cleared and contains
|
||
|
// no real elements
|
||
|
if (bEmitClearTag == true && (_clearElement.Length != 0)) {
|
||
|
if (writer != null) {
|
||
|
writer.WriteStartElement(_clearElement);
|
||
|
writer.WriteEndElement();
|
||
|
}
|
||
|
DataToWrite = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
foreach (Entry entry in _items) {
|
||
|
if (type == ConfigurationElementCollectionType.BasicMap ||
|
||
|
type == ConfigurationElementCollectionType.BasicMapAlternate) {
|
||
|
if (entry._entryType == EntryType.Added || entry._entryType == EntryType.Replaced) {
|
||
|
if (ElementName != null && ElementName.Length != 0) {
|
||
|
if (BaseConfigurationRecord.IsReservedAttributeName(ElementName)) {
|
||
|
throw new ArgumentException(SR.GetString(SR.Basicmap_item_name_reserved, ElementName));
|
||
|
}
|
||
|
DataToWrite |= entry._value.SerializeToXmlElement(writer, ElementName);
|
||
|
}
|
||
|
else {
|
||
|
DataToWrite |= entry._value.SerializeElement(writer, false);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (type == ConfigurationElementCollectionType.AddRemoveClearMap ||
|
||
|
type == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
|
||
|
if ((entry._entryType == EntryType.Removed ||
|
||
|
entry._entryType == EntryType.Replaced) &&
|
||
|
entry._value != null) {
|
||
|
|
||
|
if (writer != null) {
|
||
|
writer.WriteStartElement(_removeElement);
|
||
|
}
|
||
|
|
||
|
DataToWrite |= entry._value.SerializeElement(writer, true);
|
||
|
|
||
|
if (writer != null) {
|
||
|
writer.WriteEndElement();
|
||
|
}
|
||
|
|
||
|
DataToWrite = true;
|
||
|
}
|
||
|
if (entry._entryType == EntryType.Added || entry._entryType == EntryType.Replaced) {
|
||
|
DataToWrite |= entry._value.SerializeToXmlElement(writer, _addElement);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return DataToWrite;
|
||
|
}
|
||
|
|
||
|
protected override bool OnDeserializeUnrecognizedElement(String elementName, XmlReader reader) {
|
||
|
bool handled = false; //
|
||
|
if (CollectionType == ConfigurationElementCollectionType.AddRemoveClearMap ||
|
||
|
CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
|
||
|
if (elementName == _addElement) {
|
||
|
ConfigurationElement elem = CallCreateNewElement();
|
||
|
elem.ResetLockLists(this);
|
||
|
elem.DeserializeElement(reader, false);
|
||
|
BaseAdd(elem);
|
||
|
handled = true;
|
||
|
}
|
||
|
else if (elementName == _removeElement) {
|
||
|
ConfigurationElement elem = CallCreateNewElement();
|
||
|
elem.ResetLockLists(this);
|
||
|
elem.DeserializeElement(reader, true);
|
||
|
if (IsElementRemovable(elem) == true) {
|
||
|
BaseRemove(GetElementKeyInternal(elem), false);
|
||
|
}
|
||
|
|
||
|
handled = true;
|
||
|
}
|
||
|
else if (elementName == _clearElement) {
|
||
|
if (reader.AttributeCount > 0) {
|
||
|
while (reader.MoveToNextAttribute()) {
|
||
|
String propertyName = reader.Name;
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_unrecognized_attribute, propertyName), reader);
|
||
|
}
|
||
|
}
|
||
|
CheckLockedElement(elementName, reader);
|
||
|
reader.MoveToElement();
|
||
|
BaseClear(); //
|
||
|
bEmitClearTag = true;
|
||
|
handled = true;
|
||
|
}
|
||
|
}
|
||
|
else if (elementName == ElementName) {
|
||
|
if (BaseConfigurationRecord.IsReservedAttributeName(elementName)) {
|
||
|
throw new ArgumentException(SR.GetString(SR.Basicmap_item_name_reserved, elementName));
|
||
|
}
|
||
|
ConfigurationElement elem = CallCreateNewElement();
|
||
|
elem.ResetLockLists(this);
|
||
|
elem.DeserializeElement(reader, false);
|
||
|
BaseAdd(elem);
|
||
|
|
||
|
handled = true;
|
||
|
}
|
||
|
else if (IsElementName(elementName)) { // this section handle the collection like the allow deny senario which
|
||
|
if (BaseConfigurationRecord.IsReservedAttributeName(elementName)) {
|
||
|
throw new ArgumentException(SR.GetString(SR.Basicmap_item_name_reserved, elementName));
|
||
|
}
|
||
|
// have multiple tags for the collection
|
||
|
ConfigurationElement elem = CallCreateNewElement(elementName);
|
||
|
elem.ResetLockLists(this);
|
||
|
elem.DeserializeElement(reader, false);
|
||
|
BaseAdd(-1, elem);
|
||
|
handled = true;
|
||
|
}
|
||
|
return handled;
|
||
|
}
|
||
|
|
||
|
private ConfigurationElement CallCreateNewElement(string elementName) {
|
||
|
ConfigurationElement elem = CreateNewElement(elementName);
|
||
|
elem.AssociateContext(_configRecord);
|
||
|
elem.CallInit();
|
||
|
return elem;
|
||
|
}
|
||
|
|
||
|
private ConfigurationElement CallCreateNewElement() {
|
||
|
ConfigurationElement elem = CreateNewElement();
|
||
|
elem.AssociateContext(_configRecord);
|
||
|
elem.CallInit();
|
||
|
return elem;
|
||
|
}
|
||
|
|
||
|
protected virtual ConfigurationElement CreateNewElement(string elementName) {
|
||
|
return CreateNewElement();
|
||
|
}
|
||
|
protected abstract ConfigurationElement CreateNewElement();
|
||
|
protected abstract Object GetElementKey(ConfigurationElement element);
|
||
|
internal Object GetElementKeyInternal(ConfigurationElement element) {
|
||
|
Object key = GetElementKey(element);
|
||
|
if (key == null)
|
||
|
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_invalid_element_key));
|
||
|
return key;
|
||
|
}
|
||
|
|
||
|
protected virtual bool IsElementRemovable(ConfigurationElement element) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
private bool CompareKeys(Object key1, Object key2) {
|
||
|
if (_comparer != null) {
|
||
|
return (_comparer.Compare(key1, key2) == 0);
|
||
|
}
|
||
|
else {
|
||
|
return key1.Equals(key2);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected virtual String ElementName {
|
||
|
get {
|
||
|
return "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected virtual bool IsElementName(string elementName) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
internal bool IsLockableElement(string elementName) {
|
||
|
if (CollectionType == ConfigurationElementCollectionType.AddRemoveClearMap ||
|
||
|
CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
|
||
|
return (elementName == AddElementName ||
|
||
|
elementName == RemoveElementName ||
|
||
|
elementName == ClearElementName);
|
||
|
}
|
||
|
else {
|
||
|
return (elementName == ElementName) || IsElementName(elementName);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal string LockableElements {
|
||
|
get {
|
||
|
if (CollectionType == ConfigurationElementCollectionType.AddRemoveClearMap ||
|
||
|
CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
|
||
|
|
||
|
string ElementNames = "'" + AddElementName + "'"; // Must have an add
|
||
|
if (RemoveElementName.Length != 0)
|
||
|
ElementNames += ", '" + RemoveElementName + "'";
|
||
|
if (ClearElementName.Length != 0)
|
||
|
ElementNames += ", '" + ClearElementName + "'";
|
||
|
return ElementNames;
|
||
|
}
|
||
|
else {
|
||
|
if (!String.IsNullOrEmpty(ElementName)) {
|
||
|
return "'" + ElementName + "'";
|
||
|
}
|
||
|
return String.Empty;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected virtual bool ThrowOnDuplicate {
|
||
|
get {
|
||
|
if (CollectionType == ConfigurationElementCollectionType.AddRemoveClearMap ||
|
||
|
CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public virtual ConfigurationElementCollectionType CollectionType {
|
||
|
get {
|
||
|
return ConfigurationElementCollectionType.AddRemoveClearMap;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private enum EntryType {
|
||
|
Inherited,
|
||
|
Replaced,
|
||
|
Removed,
|
||
|
Added,
|
||
|
}
|
||
|
|
||
|
private class Entry {
|
||
|
|
||
|
internal EntryType _entryType;
|
||
|
internal Object _key;
|
||
|
internal ConfigurationElement _value;
|
||
|
|
||
|
internal Object GetKey(ConfigurationElementCollection ThisCollection) {
|
||
|
// For items that have been really inserted...
|
||
|
if (_value != null) {
|
||
|
return ThisCollection.GetElementKeyInternal(_value);
|
||
|
}
|
||
|
else {
|
||
|
return _key; // These are items that only have been removed
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
internal Entry(EntryType type, Object key, ConfigurationElement value) {
|
||
|
_entryType = type;
|
||
|
_key = key;
|
||
|
_value = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private class Enumerator : IDictionaryEnumerator {
|
||
|
|
||
|
private IEnumerator _itemsEnumerator;
|
||
|
private DictionaryEntry _current = new DictionaryEntry();
|
||
|
private ConfigurationElementCollection ThisCollection;
|
||
|
|
||
|
|
||
|
internal Enumerator(ArrayList items, ConfigurationElementCollection collection) {
|
||
|
_itemsEnumerator = items.GetEnumerator();
|
||
|
ThisCollection = collection;
|
||
|
}
|
||
|
|
||
|
bool IEnumerator.MoveNext() {
|
||
|
while (_itemsEnumerator.MoveNext()) {
|
||
|
Entry entry = (Entry)_itemsEnumerator.Current;
|
||
|
if (entry._entryType != EntryType.Removed) {
|
||
|
_current.Key = (entry.GetKey(ThisCollection) != null) ? entry.GetKey(ThisCollection) : "key";
|
||
|
_current.Value = entry._value;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void IEnumerator.Reset() {
|
||
|
_itemsEnumerator.Reset();
|
||
|
}
|
||
|
|
||
|
Object IEnumerator.Current {
|
||
|
get {
|
||
|
return _current.Value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DictionaryEntry IDictionaryEnumerator.Entry {
|
||
|
get {
|
||
|
return _current;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Object IDictionaryEnumerator.Key {
|
||
|
get {
|
||
|
return _current.Key;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Object IDictionaryEnumerator.Value {
|
||
|
get {
|
||
|
return _current.Value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|