Files
libremetaverse/ExtensionLoader/Config/IniConfigSource.cs
2008-10-29 20:38:51 +00:00

329 lines
8.5 KiB
C#

#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.Collections;
using ExtensionLoader.Ini;
namespace ExtensionLoader.Config
{
/// <include file='IniConfigSource.xml' path='//Class[@name="IniConfigSource"]/docs/*' />
public class IniConfigSource : ConfigSourceBase
{
#region Private variables
IniDocument iniDocument = null;
string savePath = null;
bool caseSensitive = true;
#endregion
#region Public properties
#endregion
#region Constructors
/// <include file='IniConfigSource.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public IniConfigSource ()
{
iniDocument = new IniDocument ();
}
/// <include file='IniConfigSource.xml' path='//Constructor[@name="ConstructorPath"]/docs/*' />
public IniConfigSource (string filePath)
{
Load (filePath);
}
/// <include file='IniConfigSource.xml' path='//Constructor[@name="ConstructorTextReader"]/docs/*' />
public IniConfigSource (TextReader reader)
{
Load (reader);
}
/// <include file='IniConfigSource.xml' path='//Constructor[@name="ConstructorIniDocument"]/docs/*' />
public IniConfigSource (IniDocument document)
{
Load (document);
}
/// <include file='IniConfigSource.xml' path='//Constructor[@name="ConstructorStream"]/docs/*' />
public IniConfigSource (Stream stream)
{
Load (stream);
}
#endregion
#region Public properties
/// <include file='IniConfigSource.xml' path='//Property[@name="CaseSensitive"]/docs/*' />
public bool CaseSensitive
{
get { return caseSensitive; }
set { caseSensitive = value; }
}
/// <include file='IniConfigSource.xml' path='//Property[@name="SavePath"]/docs/*' />
public string SavePath
{
get { return savePath; }
}
#endregion
#region Public methods
/// <include file='IniConfigSource.xml' path='//Method[@name="LoadPath"]/docs/*' />
public void Load (string filePath)
{
Load (new StreamReader (filePath));
this.savePath = filePath;
}
/// <include file='IniConfigSource.xml' path='//Method[@name="LoadTextReader"]/docs/*' />
public void Load (TextReader reader)
{
Load (new IniDocument (reader));
}
/// <include file='IniConfigSource.xml' path='//Method[@name="LoadIniDocument"]/docs/*' />
public void Load (IniDocument document)
{
this.Configs.Clear ();
this.Merge (this); // required for SaveAll
iniDocument = document;
Load ();
}
/// <include file='IniConfigSource.xml' path='//Method[@name="LoadStream"]/docs/*' />
public void Load (Stream stream)
{
Load (new StreamReader (stream));
}
/// <include file='IniConfigSource.xml' path='//Method[@name="Save"]/docs/*' />
public override void Save ()
{
if (!IsSavable ()) {
throw new ArgumentException ("Source cannot be saved in this state");
}
MergeConfigsIntoDocument ();
iniDocument.Save (this.savePath);
base.Save ();
}
/// <include file='IniConfigSource.xml' path='//Method[@name="SavePath"]/docs/*' />
public void Save (string path)
{
this.savePath = path;
this.Save ();
}
/// <include file='IniConfigSource.xml' path='//Method[@name="SaveTextWriter"]/docs/*' />
public void Save (TextWriter writer)
{
MergeConfigsIntoDocument ();
iniDocument.Save (writer);
savePath = null;
OnSaved (new EventArgs ());
}
/// <include file='IniConfigSource.xml' path='//Method[@name="SaveStream"]/docs/*' />
public void Save (Stream stream)
{
MergeConfigsIntoDocument ();
iniDocument.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");
}
iniDocument = new IniDocument (savePath);
MergeDocumentIntoConfigs ();
base.Reload ();
}
/// <include file='IniConfigSource.xml' path='//Method[@name="ToString"]/docs/*' />
public override string ToString ()
{
MergeConfigsIntoDocument ();
StringWriter writer = new StringWriter ();
iniDocument.Save (writer);
return writer.ToString ();
}
#endregion
#region Private methods
/// <summary>
/// Merges all of the configs from the config collection into the
/// IniDocument before it is saved.
/// </summary>
private void MergeConfigsIntoDocument ()
{
RemoveSections ();
foreach (IConfig config in this.Configs)
{
string[] keys = config.GetKeys ();
// Create a new section if one doesn't exist
if (iniDocument.Sections[config.Name] == null) {
IniSection section = new IniSection (config.Name);
iniDocument.Sections.Add (section);
}
RemoveKeys (config.Name);
for (int i = 0; i < keys.Length; i++)
{
iniDocument.Sections[config.Name].Set (keys[i], config.Get (keys[i]));
}
}
}
/// <summary>
/// Removes all INI sections that were removed as configs.
/// </summary>
private void RemoveSections ()
{
IniSection section = null;
for (int i = 0; i < iniDocument.Sections.Count; i++)
{
section = iniDocument.Sections[i];
if (this.Configs[section.Name] == null) {
iniDocument.Sections.Remove (section.Name);
}
}
}
/// <summary>
/// Removes all INI keys that were removed as config keys.
/// </summary>
private void RemoveKeys (string sectionName)
{
IniSection section = iniDocument.Sections[sectionName];
if (section != null) {
foreach (string key in section.GetKeys ())
{
if (this.Configs[sectionName].Get (key) == null) {
section.Remove (key);
}
}
}
}
/// <summary>
/// Loads the configuration file.
/// </summary>
private void Load ()
{
IniConfig config = null;
IniSection section = null;
IniItem item = null;
for (int j = 0; j < iniDocument.Sections.Count; j++)
{
section = iniDocument.Sections[j];
config = new IniConfig (section.Name, this);
for (int i = 0; i < section.ItemCount; i++)
{
item = section.GetItem (i);
if (item.Type == IniType.Key) {
config.Add (item.Name, item.Value);
}
}
this.Configs.Add (config);
}
}
/// <summary>
/// Merges the IniDocument into the Configs when the document is
/// reloaded.
/// </summary>
private void MergeDocumentIntoConfigs ()
{
// Remove all missing configs first
RemoveConfigs ();
IniSection section = null;
for (int i = 0; i < iniDocument.Sections.Count; i++)
{
section = iniDocument.Sections[i];
IConfig config = this.Configs[section.Name];
if (config == null) {
// The section is new so add it
config = new ConfigBase (section.Name, this);
this.Configs.Add (config);
}
RemoveConfigKeys (config);
}
}
/// <summary>
/// Removes all configs that are not in the newly loaded INI doc.
/// </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 INI doc
if (iniDocument.Sections[config.Name] == null) {
this.Configs.Remove (config);
}
}
}
/// <summary>
/// Removes all INI keys that were removed as config keys.
/// </summary>
private void RemoveConfigKeys (IConfig config)
{
IniSection section = iniDocument.Sections[config.Name];
// Remove old keys
string[] configKeys = config.GetKeys ();
foreach (string configKey in configKeys)
{
if (!section.Contains (configKey)) {
// Key doesn't exist, remove
config.Remove (configKey);
}
}
// Add or set all new keys
string[] keys = section.GetKeys ();
for (int i = 0; i < keys.Length; i++)
{
string key = keys[i];
config.Set (key, section.GetItem (i).Value);
}
}
/// <summary>
/// Returns true if this instance is savable.
/// </summary>
private bool IsSavable ()
{
return (this.savePath != null);
}
#endregion
}
}