//
// 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)
//
#if NET_2_0
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
{
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)
{
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 ()
{
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)
{
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 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);
}
}
}
#endif
|