a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
483 lines
13 KiB
C#
483 lines
13 KiB
C#
//
|
|
// System.Configuration.SectionGroupInfo.cs
|
|
//
|
|
// Authors:
|
|
// Lluis Sanchez (lluis@novell.com)
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
|
|
//
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Specialized;
|
|
using System.Xml;
|
|
using System.IO;
|
|
using System.Text;
|
|
|
|
namespace System.Configuration
|
|
{
|
|
internal class SectionGroupInfo: ConfigInfo
|
|
{
|
|
bool modified;
|
|
ConfigInfoCollection sections;
|
|
ConfigInfoCollection groups;
|
|
static ConfigInfoCollection emptyList = new ConfigInfoCollection ();
|
|
|
|
public SectionGroupInfo ()
|
|
{
|
|
Type = typeof (ConfigurationSectionGroup);
|
|
}
|
|
|
|
public SectionGroupInfo (string groupName, string typeName)
|
|
{
|
|
Name = groupName;
|
|
TypeName = typeName;
|
|
}
|
|
|
|
public void AddChild (ConfigInfo data)
|
|
{
|
|
modified = true;
|
|
data.Parent = this;
|
|
if (data is SectionInfo) {
|
|
if (sections == null) sections = new ConfigInfoCollection ();
|
|
sections [data.Name] = data;
|
|
}
|
|
else {
|
|
if (groups == null) groups = new ConfigInfoCollection ();
|
|
groups [data.Name] = data;
|
|
}
|
|
}
|
|
|
|
public void Clear ()
|
|
{
|
|
modified = true;
|
|
if (sections != null) sections.Clear ();
|
|
if (groups != null) groups.Clear ();
|
|
}
|
|
|
|
public bool HasChild (string name)
|
|
{
|
|
if (sections != null && sections [name] != null) return true;
|
|
return (groups != null && groups [name] != null);
|
|
}
|
|
|
|
public void RemoveChild (string name)
|
|
{
|
|
modified = true;
|
|
if (sections != null)
|
|
sections.Remove (name);
|
|
if (groups != null)
|
|
groups.Remove (name);
|
|
}
|
|
|
|
public SectionInfo GetChildSection (string name)
|
|
{
|
|
if (sections != null)
|
|
return sections [name] as SectionInfo;
|
|
else
|
|
return null;
|
|
}
|
|
|
|
public SectionGroupInfo GetChildGroup (string name)
|
|
{
|
|
if (groups != null)
|
|
return groups [name] as SectionGroupInfo;
|
|
else
|
|
return null;
|
|
}
|
|
|
|
public ConfigInfoCollection Sections
|
|
{
|
|
get { if (sections == null) return emptyList; else return sections; }
|
|
}
|
|
|
|
public ConfigInfoCollection Groups
|
|
{
|
|
get { if (groups == null) return emptyList; else return groups; }
|
|
}
|
|
|
|
public override bool HasDataContent (Configuration config)
|
|
{
|
|
foreach (ConfigInfoCollection col in new object[] {Sections, Groups}) {
|
|
foreach (string key in col) {
|
|
ConfigInfo cinfo = col [key];
|
|
if (cinfo.HasDataContent (config))
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public override bool HasConfigContent (Configuration cfg)
|
|
{
|
|
if (StreamName == cfg.FileName) return true;
|
|
foreach (ConfigInfoCollection col in new object[] {Sections, Groups}) {
|
|
foreach (string key in col) {
|
|
ConfigInfo cinfo = col [key];
|
|
if (cinfo.HasConfigContent (cfg))
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public override void ReadConfig (Configuration cfg, string streamName, XmlReader reader)
|
|
{
|
|
StreamName = streamName;
|
|
ConfigHost = cfg.ConfigHost;
|
|
|
|
if (reader.LocalName != "configSections")
|
|
{
|
|
while (reader.MoveToNextAttribute ()) {
|
|
if (reader.Name == "name")
|
|
Name = reader.Value;
|
|
else if (reader.Name == "type") {
|
|
TypeName = reader.Value;
|
|
Type = null;
|
|
}
|
|
else
|
|
ThrowException ("Unrecognized attribute", reader);
|
|
}
|
|
|
|
if (Name == null)
|
|
ThrowException ("sectionGroup must have a 'name' attribute", reader);
|
|
|
|
if (Name == "location")
|
|
ThrowException ("location is a reserved section name", reader);
|
|
}
|
|
|
|
if (TypeName == null)
|
|
TypeName = "System.Configuration.ConfigurationSectionGroup";
|
|
|
|
if (reader.IsEmptyElement) {
|
|
reader.Skip ();
|
|
return;
|
|
}
|
|
|
|
reader.ReadStartElement ();
|
|
reader.MoveToContent ();
|
|
|
|
while (reader.NodeType != XmlNodeType.EndElement)
|
|
{
|
|
if (reader.NodeType != XmlNodeType.Element) {
|
|
reader.Skip ();
|
|
continue;
|
|
}
|
|
|
|
string name = reader.LocalName;
|
|
ConfigInfo cinfo = null;
|
|
|
|
if (name == "remove") {
|
|
ReadRemoveSection (reader);
|
|
continue;
|
|
}
|
|
|
|
if (name == "clear") {
|
|
if (reader.HasAttributes)
|
|
ThrowException ("Unrecognized attribute.", reader);
|
|
|
|
Clear ();
|
|
reader.Skip ();
|
|
continue;
|
|
}
|
|
|
|
if (name == "section")
|
|
cinfo = new SectionInfo ();
|
|
else if (name == "sectionGroup") {
|
|
cinfo = new SectionGroupInfo ();
|
|
} else
|
|
ThrowException ("Unrecognized element: " + reader.Name, reader);
|
|
|
|
cinfo.ReadConfig (cfg, streamName, reader);
|
|
ConfigInfo actInfo = Groups [cinfo.Name];
|
|
if (actInfo == null) actInfo = Sections [cinfo.Name];
|
|
|
|
if (actInfo != null) {
|
|
if (actInfo.GetType () != cinfo.GetType ())
|
|
ThrowException ("A section or section group named '" + cinfo.Name + "' already exists", reader);
|
|
// Merge all the new data
|
|
actInfo.Merge (cinfo);
|
|
|
|
// Make sure that this section is saved in this configuration file:
|
|
actInfo.StreamName = streamName;
|
|
}
|
|
else
|
|
AddChild (cinfo);
|
|
}
|
|
|
|
reader.ReadEndElement ();
|
|
}
|
|
|
|
public override void WriteConfig (Configuration cfg, XmlWriter writer, ConfigurationSaveMode mode)
|
|
{
|
|
if (Name != null) {
|
|
writer.WriteStartElement ("sectionGroup");
|
|
writer.WriteAttributeString ("name", Name);
|
|
if (TypeName != null && TypeName != "" && TypeName != "System.Configuration.ConfigurationSectionGroup")
|
|
writer.WriteAttributeString ("type", TypeName);
|
|
}
|
|
else
|
|
writer.WriteStartElement ("configSections");
|
|
|
|
foreach (ConfigInfoCollection col in new object[] {Sections, Groups}) {
|
|
foreach (string key in col) {
|
|
ConfigInfo cinfo = col [key];
|
|
if (cinfo.HasConfigContent (cfg))
|
|
cinfo.WriteConfig (cfg, writer, mode);
|
|
}
|
|
}
|
|
|
|
writer.WriteEndElement ();
|
|
}
|
|
|
|
private void ReadRemoveSection (XmlReader reader)
|
|
{
|
|
if (!reader.MoveToNextAttribute () || reader.Name != "name")
|
|
ThrowException ("Unrecognized attribute.", reader);
|
|
|
|
string removeValue = reader.Value;
|
|
if (String.IsNullOrEmpty (removeValue))
|
|
ThrowException ("Empty name to remove", reader);
|
|
|
|
reader.MoveToElement ();
|
|
|
|
if (!HasChild (removeValue))
|
|
ThrowException ("No factory for " + removeValue, reader);
|
|
|
|
RemoveChild (removeValue);
|
|
reader.Skip ();
|
|
}
|
|
|
|
public void ReadRootData (XmlReader reader, Configuration config, bool overrideAllowed)
|
|
{
|
|
reader.MoveToContent ();
|
|
ReadContent (reader, config, overrideAllowed, true);
|
|
}
|
|
|
|
public override void ReadData (Configuration config, XmlReader reader, bool overrideAllowed)
|
|
{
|
|
reader.MoveToContent ();
|
|
if (!reader.IsEmptyElement) {
|
|
reader.ReadStartElement ();
|
|
ReadContent (reader, config, overrideAllowed, false);
|
|
reader.MoveToContent ();
|
|
reader.ReadEndElement ();
|
|
} else
|
|
reader.Read ();
|
|
}
|
|
|
|
void ReadContent (XmlReader reader, Configuration config, bool overrideAllowed, bool root)
|
|
{
|
|
while (reader.NodeType != XmlNodeType.EndElement && reader.NodeType != XmlNodeType.None) {
|
|
if (reader.NodeType != XmlNodeType.Element) {
|
|
reader.Skip ();
|
|
continue;
|
|
}
|
|
|
|
if (reader.LocalName == "dllmap") {
|
|
reader.Skip ();
|
|
continue;
|
|
}
|
|
|
|
if (reader.LocalName == "location") {
|
|
if (!root)
|
|
ThrowException ("<location> elements are only allowed in <configuration> elements.", reader);
|
|
|
|
string allowOverrideAttr = reader.GetAttribute ("allowOverride");
|
|
bool allowOverride = allowOverrideAttr == null || allowOverrideAttr.Length == 0 || bool.Parse (allowOverrideAttr);
|
|
string path = reader.GetAttribute ("path");
|
|
if (path != null && path.Length > 0) {
|
|
string xml = reader.ReadOuterXml ();
|
|
string[] pathList = path.Split (',');
|
|
string tpath;
|
|
foreach (string p in pathList) {
|
|
tpath = p.Trim ();
|
|
if (config.Locations.Find (tpath) != null)
|
|
ThrowException ("Sections must only appear once per config file.", reader);
|
|
|
|
ConfigurationLocation loc = new ConfigurationLocation (tpath, xml, config, allowOverride);
|
|
config.Locations.Add (loc);
|
|
}
|
|
} else {
|
|
ReadData (config, reader, allowOverride);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
ConfigInfo data = GetConfigInfo (reader, this);
|
|
if (data != null)
|
|
data.ReadData (config, reader, overrideAllowed);
|
|
else
|
|
ThrowException ("Unrecognized configuration section <" + reader.LocalName + ">", reader);
|
|
}
|
|
}
|
|
|
|
ConfigInfo GetConfigInfo (XmlReader reader, SectionGroupInfo current)
|
|
{
|
|
ConfigInfo data = null;
|
|
if (current.sections != null)
|
|
data = current.sections [reader.LocalName];
|
|
if (data != null)
|
|
return data;
|
|
if (current.groups != null)
|
|
data = current.groups [reader.LocalName];
|
|
if (data != null)
|
|
return data;
|
|
if (current.groups == null)
|
|
return null;
|
|
// It might be a section in descendant sectionGroups
|
|
foreach (string key in current.groups.AllKeys) {
|
|
data = GetConfigInfo (reader, (SectionGroupInfo) current.groups [key]);
|
|
if (data != null)
|
|
return data;
|
|
}
|
|
|
|
// It might be in the root section group
|
|
return null;
|
|
}
|
|
|
|
internal override void Merge (ConfigInfo newData)
|
|
{
|
|
SectionGroupInfo data = newData as SectionGroupInfo;
|
|
if (data == null)
|
|
return;
|
|
ConfigInfo actInfo;
|
|
if (data.sections != null && data.sections.Count > 0)
|
|
foreach (string key in data.sections.AllKeys) {
|
|
actInfo = sections[key];
|
|
if (actInfo != null)
|
|
continue;
|
|
sections.Add (key, data.sections[key]);
|
|
}
|
|
|
|
if (data.groups != null && data.sections != null && data.sections.Count > 0)
|
|
foreach (string key in data.groups.AllKeys) {
|
|
actInfo = groups[key];
|
|
if (actInfo != null)
|
|
continue;
|
|
groups.Add (key, data.groups[key]);
|
|
}
|
|
}
|
|
|
|
public void WriteRootData (XmlWriter writer, Configuration config, ConfigurationSaveMode mode)
|
|
{
|
|
WriteContent (writer, config, mode, false);
|
|
}
|
|
|
|
public override void WriteData (Configuration config, XmlWriter writer, ConfigurationSaveMode mode)
|
|
{
|
|
writer.WriteStartElement (Name);
|
|
WriteContent (writer, config, mode, true);
|
|
writer.WriteEndElement ();
|
|
}
|
|
|
|
public void WriteContent (XmlWriter writer, Configuration config, ConfigurationSaveMode mode, bool writeElem)
|
|
{
|
|
foreach (ConfigInfoCollection col in new object[] {Sections, Groups}) {
|
|
foreach (string key in col) {
|
|
ConfigInfo cinfo = col [key];
|
|
if (cinfo.HasDataContent (config))
|
|
cinfo.WriteData (config, writer, mode);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal override bool HasValues (Configuration config, ConfigurationSaveMode mode)
|
|
{
|
|
if (modified && (mode == ConfigurationSaveMode.Modified))
|
|
return true;
|
|
|
|
foreach (ConfigInfoCollection col in new object[] { Sections, Groups}) {
|
|
foreach (string key in col) {
|
|
ConfigInfo cinfo = col [key];
|
|
if (cinfo.HasValues (config, mode))
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
internal override void ResetModified (Configuration config)
|
|
{
|
|
modified = false;
|
|
foreach (ConfigInfoCollection col in new object[] { Sections, Groups}) {
|
|
foreach (string key in col) {
|
|
ConfigInfo cinfo = col [key];
|
|
cinfo.ResetModified (config);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
internal class ConfigInfoCollection : NameObjectCollectionBase
|
|
{
|
|
public ConfigInfoCollection ()
|
|
: base (StringComparer.Ordinal)
|
|
{
|
|
}
|
|
|
|
public ICollection AllKeys
|
|
{
|
|
get { return Keys; }
|
|
}
|
|
|
|
public ConfigInfo this [string name]
|
|
{
|
|
get { return (ConfigInfo) BaseGet (name); }
|
|
set { BaseSet (name, value); }
|
|
}
|
|
|
|
public ConfigInfo this [int index]
|
|
{
|
|
get { return (ConfigInfo) BaseGet (index); }
|
|
set { BaseSet (index, value); }
|
|
}
|
|
|
|
public void Add (string name, ConfigInfo config)
|
|
{
|
|
BaseAdd (name, config);
|
|
}
|
|
|
|
public void Clear ()
|
|
{
|
|
BaseClear ();
|
|
}
|
|
|
|
public string GetKey (int index)
|
|
{
|
|
return BaseGetKey (index);
|
|
}
|
|
|
|
public void Remove (string name)
|
|
{
|
|
BaseRemove (name);
|
|
}
|
|
|
|
public void RemoveAt (int index)
|
|
{
|
|
BaseRemoveAt (index);
|
|
}
|
|
}
|
|
}
|
|
|