mirror of
https://github.com/twiglet/cs2j.git
synced 2025-01-18 13:15:17 +01:00
428 lines
11 KiB
C#
Executable File
428 lines
11 KiB
C#
Executable File
#region Copyright
|
|
//
|
|
// Nini Configuration Project.
|
|
// Copyright (C) 2006 Brent R. Matzelle. All rights reserved.
|
|
//
|
|
// This software is published under the terms of the MIT X11 license, a copy of
|
|
// which has been included with this distribution in the LICENSE.txt file.
|
|
//
|
|
#endregion
|
|
|
|
using System;
|
|
using System.IO;
|
|
using System.Xml;
|
|
using System.Collections;
|
|
|
|
namespace Nini.Config
|
|
{
|
|
/// <include file='XmlConfigSource.xml' path='//Class[@name="XmlConfigSource"]/docs/*' />
|
|
public class XmlConfigSource : ConfigSourceBase
|
|
{
|
|
#region Private variables
|
|
XmlDocument configDoc = null;
|
|
string savePath = null;
|
|
#endregion
|
|
|
|
#region Constructors
|
|
/// <include file='XmlConfigSource.xml' path='//Constructor[@name="Constructor"]/docs/*' />
|
|
public XmlConfigSource ()
|
|
{
|
|
configDoc = new XmlDocument ();
|
|
configDoc.LoadXml ("<Nini/>");
|
|
PerformLoad (configDoc);
|
|
}
|
|
|
|
/// <include file='XmlConfigSource.xml' path='//Constructor[@name="ConstructorPath"]/docs/*' />
|
|
public XmlConfigSource (string path)
|
|
{
|
|
Load (path);
|
|
}
|
|
|
|
/// <include file='XmlConfigSource.xml' path='//Constructor[@name="ConstructorXmlReader"]/docs/*' />
|
|
public XmlConfigSource (XmlReader reader)
|
|
{
|
|
Load (reader);
|
|
}
|
|
#endregion
|
|
|
|
#region Public properties
|
|
/// <include file='XmlConfigSource.xml' path='//Property[@name="SavePath"]/docs/*' />
|
|
public string SavePath
|
|
{
|
|
get { return savePath; }
|
|
}
|
|
#endregion
|
|
|
|
#region Public methods
|
|
/// <include file='XmlConfigSource.xml' path='//Method[@name="LoadPath"]/docs/*' />
|
|
public void Load (string path)
|
|
{
|
|
savePath = path;
|
|
configDoc = new XmlDocument ();
|
|
configDoc.Load (path);
|
|
PerformLoad (configDoc);
|
|
}
|
|
|
|
/// <include file='XmlConfigSource.xml' path='//Method[@name="LoadXmlReader"]/docs/*' />
|
|
public void Load (XmlReader reader)
|
|
{
|
|
configDoc = new XmlDocument ();
|
|
configDoc.Load (reader);
|
|
PerformLoad (configDoc);
|
|
}
|
|
|
|
/// <include file='XmlConfigSource.xml' path='//Method[@name="Save"]/docs/*' />
|
|
public override void Save ()
|
|
{
|
|
if (!IsSavable ()) {
|
|
throw new ArgumentException ("Source cannot be saved in this state");
|
|
}
|
|
|
|
MergeConfigsIntoDocument ();
|
|
configDoc.Save (savePath);
|
|
base.Save ();
|
|
}
|
|
|
|
/// <include file='XmlConfigSource.xml' path='//Method[@name="SavePath"]/docs/*' />
|
|
public void Save (string path)
|
|
{
|
|
this.savePath = path;
|
|
this.Save ();
|
|
}
|
|
|
|
/// <include file='XmlConfigSource.xml' path='//Method[@name="SaveTextWriter"]/docs/*' />
|
|
public void Save (TextWriter writer)
|
|
{
|
|
MergeConfigsIntoDocument ();
|
|
configDoc.Save (writer);
|
|
savePath = null;
|
|
OnSaved (new EventArgs ());
|
|
}
|
|
|
|
/// <include file='XmlConfigSource.xml' path='//Method[@name="SaveStream"]/docs/*' />
|
|
public void Save (Stream stream)
|
|
{
|
|
MergeConfigsIntoDocument ();
|
|
configDoc.Save (stream);
|
|
savePath = null;
|
|
OnSaved (new EventArgs ());
|
|
}
|
|
|
|
/// <include file='IConfigSource.xml' path='//Method[@name="Reload"]/docs/*' />
|
|
public override void Reload ()
|
|
{
|
|
if (savePath == null) {
|
|
throw new ArgumentException ("Error reloading: You must have "
|
|
+ "the loaded the source from a file");
|
|
}
|
|
|
|
configDoc = new XmlDocument ();
|
|
configDoc.Load (savePath);
|
|
MergeDocumentIntoConfigs ();
|
|
base.Reload ();
|
|
}
|
|
|
|
/// <include file='XmlConfigSource.xml' path='//Method[@name="ToString"]/docs/*' />
|
|
public override string ToString ()
|
|
{
|
|
MergeConfigsIntoDocument ();
|
|
StringWriter writer = new StringWriter ();
|
|
configDoc.Save (writer);
|
|
|
|
return writer.ToString ();
|
|
}
|
|
#endregion
|
|
|
|
#region Private methods
|
|
/// <summary>
|
|
/// Merges all of the configs from the config collection into the
|
|
/// XmlDocument.
|
|
/// </summary>
|
|
private void MergeConfigsIntoDocument ()
|
|
{
|
|
RemoveSections ();
|
|
foreach (IConfig config in this.Configs)
|
|
{
|
|
string[] keys = config.GetKeys ();
|
|
|
|
XmlNode node = GetSectionByName (config.Name);
|
|
if (node == null) {
|
|
node = SectionNode (config.Name);
|
|
configDoc.DocumentElement.AppendChild (node);
|
|
}
|
|
RemoveKeys (config.Name);
|
|
|
|
for (int i = 0; i < keys.Length; i++)
|
|
{
|
|
SetKey (node, keys[i], config.Get (keys[i]));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes all XML sections that were removed as configs.
|
|
/// </summary>
|
|
private void RemoveSections ()
|
|
{
|
|
XmlAttribute attr = null;
|
|
|
|
foreach (XmlNode node in configDoc.DocumentElement.ChildNodes)
|
|
{
|
|
if (node.NodeType == XmlNodeType.Element
|
|
&& node.Name == "Section") {
|
|
|
|
attr = node.Attributes["Name"];
|
|
if (attr != null) {
|
|
if (this.Configs[attr.Value] == null) {
|
|
configDoc.DocumentElement.RemoveChild (node);
|
|
}
|
|
} else {
|
|
throw new ArgumentException ("Section name attribute not found");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes all XML keys that were removed as config keys.
|
|
/// </summary>
|
|
private void RemoveKeys (string sectionName)
|
|
{
|
|
XmlNode sectionNode = GetSectionByName (sectionName);
|
|
XmlAttribute keyName = null;
|
|
|
|
if (sectionNode != null) {
|
|
foreach (XmlNode node in sectionNode.ChildNodes)
|
|
{
|
|
if (node.NodeType == XmlNodeType.Element
|
|
&& node.Name == "Key") {
|
|
|
|
keyName = node.Attributes["Name"];
|
|
if (keyName != null) {
|
|
if (this.Configs[sectionName].Get (keyName.Value) == null) {
|
|
sectionNode.RemoveChild (node);
|
|
}
|
|
} else {
|
|
throw new ArgumentException ("Name attribute not found in key");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads all sections and keys.
|
|
/// </summary>
|
|
private void PerformLoad (XmlDocument document)
|
|
{
|
|
this.Configs.Clear ();
|
|
|
|
this.Merge (this); // required for SaveAll
|
|
|
|
if (document.DocumentElement.Name != "Nini") {
|
|
throw new ArgumentException ("Did not find Nini XML root node");
|
|
}
|
|
|
|
LoadSections (document.DocumentElement);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads all configuration sections.
|
|
/// </summary>
|
|
private void LoadSections (XmlNode rootNode)
|
|
{
|
|
ConfigBase config = null;
|
|
|
|
foreach (XmlNode child in rootNode.ChildNodes)
|
|
{
|
|
if (child.NodeType == XmlNodeType.Element
|
|
&& child.Name == "Section") {
|
|
config = new ConfigBase (child.Attributes["Name"].Value, this);
|
|
this.Configs.Add (config);
|
|
LoadKeys (child, config);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads all keys for a config.
|
|
/// </summary>
|
|
private void LoadKeys (XmlNode node, ConfigBase config)
|
|
{
|
|
foreach (XmlNode child in node.ChildNodes)
|
|
{
|
|
if (child.NodeType == XmlNodeType.Element
|
|
&& child.Name == "Key") {
|
|
config.Add (child.Attributes["Name"].Value,
|
|
child.Attributes["Value"].Value);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets an XML key. If it does not exist then it is created.
|
|
/// </summary>
|
|
private void SetKey (XmlNode sectionNode, string key, string value)
|
|
{
|
|
XmlNode node = GetKeyByName (sectionNode, key);
|
|
|
|
if (node == null) {
|
|
CreateKey (sectionNode, key, value);
|
|
} else {
|
|
node.Attributes["Value"].Value = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a key node and adds it to the collection at the end.
|
|
/// </summary>
|
|
private void CreateKey (XmlNode sectionNode, string key, string value)
|
|
{
|
|
XmlNode node = configDoc.CreateElement ("Key");
|
|
XmlAttribute keyAttr = configDoc.CreateAttribute ("Name");
|
|
XmlAttribute valueAttr = configDoc.CreateAttribute ("Value");
|
|
keyAttr.Value = key;
|
|
valueAttr.Value = value;
|
|
|
|
node.Attributes.Append (keyAttr);
|
|
node.Attributes.Append (valueAttr);
|
|
|
|
sectionNode.AppendChild (node);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a new section node.
|
|
/// </summary>
|
|
private XmlNode SectionNode (string name)
|
|
{
|
|
XmlNode result = configDoc.CreateElement ("Section");
|
|
XmlAttribute nameAttr = configDoc.CreateAttribute ("Name");
|
|
nameAttr.Value = name;
|
|
result.Attributes.Append (nameAttr);
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a section node by name.
|
|
/// </summary>
|
|
private XmlNode GetSectionByName (string name)
|
|
{
|
|
XmlNode result = null;
|
|
|
|
foreach (XmlNode node in configDoc.DocumentElement.ChildNodes)
|
|
{
|
|
if (node.NodeType == XmlNodeType.Element
|
|
&& node.Name == "Section"
|
|
&& node.Attributes["Name"].Value == name) {
|
|
result = node;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a key node by name.
|
|
/// </summary>
|
|
private XmlNode GetKeyByName (XmlNode sectionNode, string name)
|
|
{
|
|
XmlNode result = null;
|
|
|
|
foreach (XmlNode node in sectionNode.ChildNodes)
|
|
{
|
|
if (node.NodeType == XmlNodeType.Element
|
|
&& node.Name == "Key"
|
|
&& node.Attributes["Name"].Value == name) {
|
|
result = node;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns true if this instance is savable.
|
|
/// </summary>
|
|
private bool IsSavable ()
|
|
{
|
|
return (this.savePath != null
|
|
&& configDoc != null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Merges the XmlDocument into the Configs when the document is
|
|
/// reloaded.
|
|
/// </summary>
|
|
private void MergeDocumentIntoConfigs ()
|
|
{
|
|
// Remove all missing configs first
|
|
RemoveConfigs ();
|
|
|
|
foreach (XmlNode node in configDoc.DocumentElement.ChildNodes)
|
|
{
|
|
// If node is a section node
|
|
if (node.NodeType == XmlNodeType.Element
|
|
&& node.Name == "Section") {
|
|
|
|
string sectionName = node.Attributes["Name"].Value;
|
|
IConfig config = this.Configs[sectionName];
|
|
if (config == null) {
|
|
// The section is new so add it
|
|
config = new ConfigBase (sectionName, this);
|
|
this.Configs.Add (config);
|
|
}
|
|
RemoveConfigKeys (config);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes all configs that are not in the newly loaded XmlDocument.
|
|
/// </summary>
|
|
private void RemoveConfigs ()
|
|
{
|
|
IConfig config = null;
|
|
for (int i = this.Configs.Count - 1; i > -1; i--)
|
|
{
|
|
config = this.Configs[i];
|
|
// If the section is not present in the XmlDocument
|
|
if (GetSectionByName (config.Name) == null) {
|
|
this.Configs.Remove (config);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes all XML keys that were removed as config keys.
|
|
/// </summary>
|
|
private void RemoveConfigKeys (IConfig config)
|
|
{
|
|
XmlNode section = GetSectionByName (config.Name);
|
|
|
|
// Remove old keys
|
|
string[] configKeys = config.GetKeys ();
|
|
foreach (string configKey in configKeys)
|
|
{
|
|
if (GetKeyByName (section, configKey) == null) {
|
|
// Key doesn't exist, remove
|
|
config.Remove (configKey);
|
|
}
|
|
}
|
|
|
|
// Add or set all new keys
|
|
foreach (XmlNode node in section.ChildNodes)
|
|
{
|
|
// Loop through all key nodes and add to config
|
|
if (node.NodeType == XmlNodeType.Element
|
|
&& node.Name == "Key") {
|
|
config.Set (node.Attributes["Name"].Value,
|
|
node.Attributes["Value"].Value);
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
} |