Importing Nini's .ini file parsing into ExtensionLoader

git-svn-id: http://libopenmetaverse.googlecode.com/svn/trunk@2318 52acb1d6-8a22-11de-b505-999d5b087335
This commit is contained in:
John Hurliman
2008-10-29 20:38:51 +00:00
parent 3243e3153d
commit d841ffce8d
34 changed files with 7194 additions and 0 deletions

View File

@@ -0,0 +1,147 @@
#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.Collections;
namespace ExtensionLoader.Config
{
/// <include file='AliasText.xml' path='//Class[@name="AliasText"]/docs/*' />
public class AliasText
{
#region Private variables
Hashtable intAlias = null;
Hashtable booleanAlias = null;
#endregion
#region Constructors
/// <include file='AliasText.xml' path='//Constructor[@name="AliasText"]/docs/*' />
public AliasText ()
{
intAlias = InsensitiveHashtable ();
booleanAlias = InsensitiveHashtable ();
DefaultAliasLoad ();
}
#endregion
#region Public methods
/// <include file='AliasText.xml' path='//Method[@name="AddAliasInt"]/docs/*' />
public void AddAlias (string key, string alias, int value)
{
if (intAlias.Contains (key)) {
Hashtable keys = (Hashtable)intAlias[key];
keys[alias] = value;
} else {
Hashtable keys = InsensitiveHashtable ();
keys[alias] = value;
intAlias.Add (key, keys);
}
}
/// <include file='AliasText.xml' path='//Method[@name="AddAliasBoolean"]/docs/*' />
public void AddAlias (string alias, bool value)
{
booleanAlias[alias] = value;
}
#if (NET_COMPACT_1_0)
#else
/// <include file='AliasText.xml' path='//Method[@name="AddAliasEnum"]/docs/*' />
public void AddAlias (string key, Enum enumAlias)
{
SetAliasTypes (key, enumAlias);
}
#endif
/// <include file='AliasText.xml' path='//Method[@name="ContainsBoolean"]/docs/*' />
public bool ContainsBoolean (string key)
{
return booleanAlias.Contains (key);
}
/// <include file='AliasText.xml' path='//Method[@name="ContainsInt"]/docs/*' />
public bool ContainsInt (string key, string alias)
{
bool result = false;
if (intAlias.Contains (key)) {
Hashtable keys = (Hashtable)intAlias[key];
result = (keys.Contains (alias));
}
return result;
}
/// <include file='AliasText.xml' path='//Method[@name="GetBoolean"]/docs/*' />
public bool GetBoolean (string key)
{
if (!booleanAlias.Contains (key)) {
throw new ArgumentException ("Alias does not exist for text");
}
return (bool)booleanAlias[key];
}
/// <include file='AliasText.xml' path='//Method[@name="GetInt"]/docs/*' />
public int GetInt (string key, string alias)
{
if (!intAlias.Contains (key)) {
throw new ArgumentException ("Alias does not exist for key");
}
Hashtable keys = (Hashtable)intAlias[key];
if (!keys.Contains (alias)) {
throw new ArgumentException ("Config value does not match a " +
"supplied alias");
}
return (int)keys[alias];
}
#endregion
#region Private methods
/// <summary>
/// Loads the default alias values.
/// </summary>
private void DefaultAliasLoad ()
{
AddAlias("true", true);
AddAlias("false", false);
}
#if (NET_COMPACT_1_0)
#else
/// <summary>
/// Extracts and sets the alias types from an enumeration.
/// </summary>
private void SetAliasTypes (string key, Enum enumAlias)
{
string[] names = Enum.GetNames (enumAlias.GetType ());
int[] values = (int[])Enum.GetValues (enumAlias.GetType ());
for (int i = 0; i < names.Length; i++)
{
AddAlias (key, names[i], values[i]);
}
}
#endif
/// <summary>
/// Returns a case insensitive hashtable.
/// </summary>
private Hashtable InsensitiveHashtable ()
{
return new Hashtable (StringComparer.OrdinalIgnoreCase);
}
#endregion
}
}

View File

@@ -0,0 +1,422 @@
#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.Collections;
using System.Globalization;
using ExtensionLoader.Util;
namespace ExtensionLoader.Config
{
#region ConfigKeyEventArgs class
/// <include file='ConfigKeyEventArgs.xml' path='//Delegate[@name="ConfigKeyEventHandler"]/docs/*' />
public delegate void ConfigKeyEventHandler (object sender, ConfigKeyEventArgs e);
/// <include file='ConfigEventArgs.xml' path='//Class[@name="ConfigEventArgs"]/docs/*' />
public class ConfigKeyEventArgs : EventArgs
{
string keyName = null;
string keyValue = null;
/// <include file='ConfigEventArgs.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public ConfigKeyEventArgs (string keyName, string keyValue)
{
this.keyName = keyName;
this.keyValue = keyValue;
}
/// <include file='ConfigEventArgs.xml' path='//Property[@name="KeyName"]/docs/*' />
public string KeyName
{
get { return keyName; }
}
/// <include file='ConfigEventArgs.xml' path='//Property[@name="KeyValue"]/docs/*' />
public string KeyValue
{
get { return keyValue; }
}
}
#endregion
/// <include file='IConfig.xml' path='//Interface[@name="IConfig"]/docs/*' />
public class ConfigBase : IConfig
{
#region Private variables
string configName = null;
IConfigSource configSource = null;
AliasText aliasText = null;
IFormatProvider format = NumberFormatInfo.CurrentInfo;
#endregion
#region Protected variables
protected OrderedList keys = new OrderedList ();
#endregion
#region Constructors
/// <include file='ConfigBase.xml' path='//Constructor[@name="ConfigBase"]/docs/*' />
public ConfigBase (string name, IConfigSource source)
{
configName = name;
configSource = source;
aliasText = new AliasText ();
}
#endregion
#region Public properties
/// <include file='IConfig.xml' path='//Property[@name="Name"]/docs/*' />
public string Name
{
get { return configName; }
set {
if (configName != value) {
Rename (value);
}
}
}
/// <include file='IConfig.xml' path='//Property[@name="ConfigSource"]/docs/*' />
public IConfigSource ConfigSource
{
get { return configSource; }
}
/// <include file='IConfig.xml' path='//Property[@name="Alias"]/docs/*' />
public AliasText Alias
{
get { return aliasText; }
}
#endregion
#region Public methods
/// <include file='IConfig.xml' path='//Method[@name="Contains"]/docs/*' />
public bool Contains (string key)
{
return (Get (key) != null);
}
/// <include file='IConfig.xml' path='//Method[@name="Get"]/docs/*' />
public virtual string Get (string key)
{
string result = null;
if (keys.Contains (key)) {
result = keys[key].ToString ();
}
return result;
}
/// <include file='IConfig.xml' path='//Method[@name="GetDefault"]/docs/*' />
public string Get (string key, string defaultValue)
{
string result = Get (key);
return (result == null) ? defaultValue : result;
}
/// <include file='IConfig.xml' path='//Method[@name="GetExpanded"]/docs/*' />
public string GetExpanded (string key)
{
return this.ConfigSource.GetExpanded(this, key);
}
/// <include file='IConfig.xml' path='//Method[@name="Get"]/docs/*' />
public string GetString (string key)
{
return Get (key);
}
/// <include file='IConfig.xml' path='//Method[@name="GetDefault"]/docs/*' />
public string GetString (string key, string defaultValue)
{
return Get (key, defaultValue);
}
/// <include file='IConfig.xml' path='//Method[@name="GetInt"]/docs/*' />
public int GetInt (string key)
{
string text = Get (key);
if (text == null) {
throw new ArgumentException ("Value not found: " + key);
}
return Convert.ToInt32 (text, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetIntAlias"]/docs/*' />
public int GetInt (string key, bool fromAlias)
{
if (!fromAlias) {
return GetInt (key);
}
string result = Get (key);
if (result == null) {
throw new ArgumentException ("Value not found: " + key);
}
return GetIntAlias (key, result);
}
/// <include file='IConfig.xml' path='//Method[@name="GetIntDefault"]/docs/*' />
public int GetInt (string key, int defaultValue)
{
string result = Get (key);
return (result == null)
? defaultValue
: Convert.ToInt32 (result, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetIntDefaultAlias"]/docs/*' />
public int GetInt (string key, int defaultValue, bool fromAlias)
{
if (!fromAlias) {
return GetInt (key, defaultValue);
}
string result = Get (key);
return (result == null) ? defaultValue : GetIntAlias (key, result);
}
/// <include file='IConfig.xml' path='//Method[@name="GetLong"]/docs/*' />
public long GetLong (string key)
{
string text = Get (key);
if (text == null) {
throw new ArgumentException ("Value not found: " + key);
}
return Convert.ToInt64 (text, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetLongDefault"]/docs/*' />
public long GetLong (string key, long defaultValue)
{
string result = Get (key);
return (result == null)
? defaultValue
: Convert.ToInt64 (result, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetBoolean"]/docs/*' />
public bool GetBoolean (string key)
{
string text = Get (key);
if (text == null) {
throw new ArgumentException ("Value not found: " + key);
}
return GetBooleanAlias (text);
}
/// <include file='IConfig.xml' path='//Method[@name="GetBooleanDefault"]/docs/*' />
public bool GetBoolean (string key, bool defaultValue)
{
string text = Get (key);
return (text == null) ? defaultValue : GetBooleanAlias (text);
}
/// <include file='IConfig.xml' path='//Method[@name="GetFloat"]/docs/*' />
public float GetFloat (string key)
{
string text = Get (key);
if (text == null) {
throw new ArgumentException ("Value not found: " + key);
}
return Convert.ToSingle (text, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetFloatDefault"]/docs/*' />
public float GetFloat (string key, float defaultValue)
{
string result = Get (key);
return (result == null)
? defaultValue
: Convert.ToSingle (result, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetDouble"]/docs/*' />
public double GetDouble (string key)
{
string text = Get (key);
if (text == null) {
throw new ArgumentException ("Value not found: " + key);
}
return Convert.ToDouble (text, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetDoubleDefault"]/docs/*' />
public double GetDouble (string key, double defaultValue)
{
string result = Get (key);
return (result == null)
? defaultValue
: Convert.ToDouble (result, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetKeys"]/docs/*' />
public string[] GetKeys ()
{
string[] result = new string[keys.Keys.Count];
keys.Keys.CopyTo (result, 0);
return result;
}
/// <include file='IConfig.xml' path='//Method[@name="GetValues"]/docs/*' />
public string[] GetValues ()
{
string[] result = new string[keys.Values.Count];
keys.Values.CopyTo (result, 0);
return result;
}
/// <include file='ConfigBase.xml' path='//Method[@name="Add"]/docs/*' />
public void Add (string key, string value)
{
keys.Add (key, value);
}
/// <include file='IConfig.xml' path='//Method[@name="Set"]/docs/*' />
public virtual void Set (string key, object value)
{
if (value == null) {
throw new ArgumentNullException ("Value cannot be null");
}
if (Get (key) == null) {
this.Add (key, value.ToString ());
} else {
keys[key] = value.ToString ();
}
if (ConfigSource.AutoSave) {
ConfigSource.Save ();
}
OnKeySet (new ConfigKeyEventArgs (key, value.ToString ()));
}
/// <include file='IConfig.xml' path='//Method[@name="Remove"]/docs/*' />
public virtual void Remove (string key)
{
if (key == null) {
throw new ArgumentNullException ("Key cannot be null");
}
if (Get (key) != null) {
string keyValue = null;
if (KeySet != null) {
keyValue = Get (key);
}
keys.Remove (key);
OnKeyRemoved (new ConfigKeyEventArgs (key, keyValue));
}
}
#endregion
#region Public events
/// <include file='IConfig.xml' path='//Event[@name="KeySet"]/docs/*' />
public event ConfigKeyEventHandler KeySet;
/// <include file='IConfig.xml' path='//Event[@name="KeyRemoved"]/docs/*' />
public event ConfigKeyEventHandler KeyRemoved;
#endregion
#region Protected methods
/// <include file='ConfigBase.xml' path='//Method[@name="OnKeySet"]/docs/*' />
protected void OnKeySet (ConfigKeyEventArgs e)
{
if (KeySet != null) {
KeySet (this, e);
}
}
/// <include file='ConfigBase.xml' path='//Method[@name="OnKeyRemoved"]/docs/*' />
protected void OnKeyRemoved (ConfigKeyEventArgs e)
{
if (KeyRemoved != null) {
KeyRemoved (this, e);
}
}
#endregion
#region Private methods
/// <summary>
/// Renames the config to the new name.
/// </summary>
private void Rename (string name)
{
this.ConfigSource.Configs.Remove (this);
configName = name;
this.ConfigSource.Configs.Add (this);
}
/// <summary>
/// Returns the integer alias first from this IConfig then
/// the parent if there is none.
/// </summary>
private int GetIntAlias (string key, string alias)
{
int result = -1;
if (aliasText.ContainsInt (key, alias)) {
result = aliasText.GetInt (key, alias);
} else {
result = ConfigSource.Alias.GetInt (key, alias);
}
return result;
}
/// <summary>
/// Returns the boolean alias first from this IConfig then
/// the parent if there is none.
/// </summary>
private bool GetBooleanAlias (string key)
{
bool result = false;
if (aliasText.ContainsBoolean (key)) {
result = aliasText.GetBoolean (key);
} else {
if (ConfigSource.Alias.ContainsBoolean (key)) {
result = ConfigSource.Alias.GetBoolean (key);
} else {
throw new ArgumentException
("Alias value not found: " + key
+ ". Add it to the Alias property.");
}
}
return result;
}
#endregion
}
}

View File

@@ -0,0 +1,264 @@
#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.Collections;
namespace ExtensionLoader.Config
{
#region ConfigEventHandler class
/// <include file='ConfigEventArgs.xml' path='//Delegate[@name="ConfigEventHandler"]/docs/*' />
public delegate void ConfigEventHandler (object sender, ConfigEventArgs e);
/// <include file='ConfigEventArgs.xml' path='//Class[@name="ConfigEventArgs"]/docs/*' />
public class ConfigEventArgs : EventArgs
{
IConfig config = null;
/// <include file='ConfigEventArgs.xml' path='//Constructor[@name="ConstructorIConfig"]/docs/*' />
public ConfigEventArgs (IConfig config)
{
this.config = config;
}
/// <include file='ConfigEventArgs.xml' path='//Property[@name="Config"]/docs/*' />
public IConfig Config
{
get { return config; }
}
}
#endregion
/// <include file='ConfigCollection.xml' path='//Class[@name="ConfigCollection"]/docs/*' />
public class ConfigCollection : ICollection, IEnumerable, IList
{
#region Private variables
ArrayList configList = new ArrayList ();
ConfigSourceBase owner = null;
#endregion
#region Constructors
/// <include file='ConfigCollection.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public ConfigCollection (ConfigSourceBase owner)
{
this.owner = owner;
}
#endregion
#region Public properties
/// <include file='ConfigCollection.xml' path='//Property[@name="Count"]/docs/*' />
public int Count
{
get { return configList.Count; }
}
/// <include file='ConfigCollection.xml' path='//Property[@name="IsSynchronized"]/docs/*' />
public bool IsSynchronized
{
get { return false; }
}
/// <include file='ConfigCollection.xml' path='//Property[@name="SyncRoot"]/docs/*' />
public object SyncRoot
{
get { return this; }
}
/// <include file='ConfigCollection.xml' path='//Property[@name="ItemIndex"]/docs/*' />
public IConfig this[int index]
{
get { return (IConfig)configList[index]; }
}
/// <include file='ConfigCollection.xml' path='//Property[@name="ItemIndex"]/docs/*' />
object IList.this[int index]
{
get { return configList[index]; }
set { }
}
/// <include file='ConfigCollection.xml' path='//Property[@name="ItemName"]/docs/*' />
public IConfig this[string configName]
{
get
{
IConfig result = null;
foreach (IConfig config in configList)
{
if (config.Name == configName) {
result = config;
break;
}
}
return result;
}
}
/// <include file='ConfigCollection.xml' path='//Property[@name="IsFixedSize"]/docs/*' />
public bool IsFixedSize
{
get { return false; }
}
/// <include file='ConfigCollection.xml' path='//Property[@name="IsReadOnly"]/docs/*' />
public bool IsReadOnly
{
get { return false; }
}
#endregion
#region Public methods
/// <include file='ConfigCollection.xml' path='//Method[@name="Add"]/docs/*' />
public void Add (IConfig config)
{
if (configList.Contains (config)) {
throw new ArgumentException ("IConfig already exists");
}
IConfig existingConfig = this[config.Name];
if (existingConfig != null) {
// Set all new keys
string[] keys = config.GetKeys ();
for (int i = 0; i < keys.Length; i++)
{
existingConfig.Set (keys[i], config.Get (keys[i]));
}
} else {
configList.Add (config);
OnConfigAdded (new ConfigEventArgs (config));
}
}
/// <include file='ConfigCollection.xml' path='//Method[@name="Add"]/docs/*' />
int IList.Add (object config)
{
IConfig newConfig = config as IConfig;
if (newConfig == null) {
throw new Exception ("Must be an IConfig");
} else {
this.Add (newConfig);
return IndexOf (newConfig);
}
}
/// <include file='ConfigCollection.xml' path='//Method[@name="AddName"]/docs/*' />
public IConfig Add (string name)
{
ConfigBase result = null;
if (this[name] == null) {
result = new ConfigBase (name, owner);
configList.Add (result);
OnConfigAdded (new ConfigEventArgs (result));
} else {
throw new ArgumentException ("An IConfig of that name already exists");
}
return result;
}
/// <include file='ConfigCollection.xml' path='//Method[@name="Remove"]/docs/*' />
public void Remove (IConfig config)
{
configList.Remove (config);
OnConfigRemoved (new ConfigEventArgs (config));
}
/// <include file='ConfigCollection.xml' path='//Method[@name="Remove"]/docs/*' />
public void Remove (object config)
{
configList.Remove (config);
OnConfigRemoved (new ConfigEventArgs ((IConfig)config));
}
/// <include file='ConfigCollection.xml' path='//Method[@name="RemoveAt"]/docs/*' />
public void RemoveAt (int index)
{
IConfig config = (IConfig)configList[index];
configList.RemoveAt (index);
OnConfigRemoved (new ConfigEventArgs (config));
}
/// <include file='ConfigCollection.xml' path='//Method[@name="Clear"]/docs/*' />
public void Clear ()
{
configList.Clear ();
}
/// <include file='ConfigCollection.xml' path='//Method[@name="GetEnumerator"]/docs/*' />
public IEnumerator GetEnumerator ()
{
return configList.GetEnumerator ();
}
/// <include file='ConfigCollection.xml' path='//Method[@name="CopyTo"]/docs/*' />
public void CopyTo (Array array, int index)
{
configList.CopyTo (array, index);
}
/// <include file='ConfigCollection.xml' path='//Method[@name="CopyToStrong"]/docs/*' />
public void CopyTo (IConfig[] array, int index)
{
((ICollection)configList).CopyTo (array, index);
}
/// <include file='ConfigCollection.xml' path='//Method[@name="Contains"]/docs/*' />
public bool Contains (object config)
{
return configList.Contains (config);
}
/// <include file='ConfigCollection.xml' path='//Method[@name="IndexOf"]/docs/*' />
public int IndexOf (object config)
{
return configList.IndexOf (config);
}
/// <include file='ConfigCollection.xml' path='//Method[@name="Insert"]/docs/*' />
public void Insert (int index, object config)
{
configList.Insert (index, config);
}
#endregion
#region Public events
/// <include file='ConfigCollection.xml' path='//Event[@name="ConfigAdded"]/docs/*' />
public event ConfigEventHandler ConfigAdded;
/// <include file='ConfigCollection.xml' path='//Event[@name="ConfigRemoved"]/docs/*' />
public event ConfigEventHandler ConfigRemoved;
#endregion
#region Protected methods
/// <include file='ConfigCollection.xml' path='//Method[@name="OnConfigAdded"]/docs/*' />
protected void OnConfigAdded (ConfigEventArgs e)
{
if (ConfigAdded != null) {
ConfigAdded (this, e);
}
}
/// <include file='ConfigCollection.xml' path='//Method[@name="OnConfigRemoved"]/docs/*' />
protected void OnConfigRemoved (ConfigEventArgs e)
{
if (ConfigRemoved != null) {
ConfigRemoved (this, e);
}
}
#endregion
#region Private methods
#endregion
}
}

View File

@@ -0,0 +1,219 @@
#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.Text;
using System.Collections;
namespace ExtensionLoader.Config
{
/// <include file='IConfigSource.xml' path='//Interface[@name="IConfigSource"]/docs/*' />
public abstract class ConfigSourceBase : IConfigSource
{
#region Private variables
ArrayList sourceList = new ArrayList ();
ConfigCollection configList = null;
bool autoSave = false;
AliasText alias = new AliasText ();
#endregion
#region Constructors
/// <include file='ConfigSourceBase.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public ConfigSourceBase ()
{
configList = new ConfigCollection (this);
}
#endregion
#region Public properties
/// <include file='IConfigSource.xml' path='//Property[@name="Configs"]/docs/*' />
public ConfigCollection Configs
{
get { return configList; }
}
/// <include file='IConfigSource.xml' path='//Property[@name="AutoSave"]/docs/*' />
public bool AutoSave
{
get { return autoSave; }
set { autoSave = value; }
}
/// <include file='IConfigSource.xml' path='//Property[@name="Alias"]/docs/*' />
public AliasText Alias
{
get { return alias; }
}
#endregion
#region Public methods
/// <include file='IConfigSource.xml' path='//Method[@name="Merge"]/docs/*' />
public void Merge (IConfigSource source)
{
if (!sourceList.Contains (source)) {
sourceList.Add (source);
}
foreach (IConfig config in source.Configs)
{
this.Configs.Add (config);
}
}
/// <include file='IConfigSource.xml' path='//Method[@name="AddConfig"]/docs/*' />
public virtual IConfig AddConfig (string name)
{
return configList.Add (name);
}
/// <include file='IConfigSource.xml' path='//Method[@name="GetExpanded"]/docs/*' />
public string GetExpanded (IConfig config, string key)
{
return Expand (config, key, false);
}
/// <include file='IConfigSource.xml' path='//Method[@name="Save"]/docs/*' />
public virtual void Save ()
{
OnSaved (new EventArgs ());
}
/// <include file='IConfigSource.xml' path='//Method[@name="Reload"]/docs/*' />
public virtual void Reload ()
{
OnReloaded (new EventArgs ());
}
/// <include file='IConfigSource.xml' path='//Method[@name="ExpandKeyValues"]/docs/*' />
public void ExpandKeyValues ()
{
string[] keys = null;
foreach (IConfig config in configList)
{
keys = config.GetKeys ();
for (int i = 0; i < keys.Length; i++)
{
Expand (config, keys[i], true);
}
}
}
/// <include file='IConfigSource.xml' path='//Method[@name="ReplaceKeyValues"]/docs/*' />
public void ReplaceKeyValues ()
{
ExpandKeyValues ();
}
#endregion
#region Public events
/// <include file='IConfigSource.xml' path='//Event[@name="Reloaded"]/docs/*' />
public event EventHandler Reloaded;
/// <include file='IConfigSource.xml' path='//Event[@name="Saved"]/docs/*' />
public event EventHandler Saved;
#endregion
#region Protected methods
/// <include file='ConfigSourceBase.xml' path='//Method[@name="OnReloaded"]/docs/*' />
protected void OnReloaded (EventArgs e)
{
if (Reloaded != null) {
Reloaded (this, e);
}
}
/// <include file='ConfigSourceBase.xml' path='//Method[@name="OnSaved"]/docs/*' />
protected void OnSaved (EventArgs e)
{
if (Saved != null) {
Saved (this, e);
}
}
#endregion
#region Private methods
/// <summary>
/// Expands key values from the given IConfig.
/// </summary>
private string Expand (IConfig config, string key, bool setValue)
{
string result = config.Get (key);
if (result == null) {
throw new ArgumentException (String.Format ("[{0}] not found in [{1}]",
key, config.Name));
}
while (true)
{
int startIndex = result.IndexOf ("${", 0);
if (startIndex == -1) {
break;
}
int endIndex = result.IndexOf ("}", startIndex + 2);
if (endIndex == -1) {
break;
}
string search = result.Substring (startIndex + 2,
endIndex - (startIndex + 2));
if (search == key) {
// Prevent infinite recursion
throw new ArgumentException
("Key cannot have a expand value of itself: " + key);
}
string replace = ExpandValue (config, search);
result = result.Replace("${" + search + "}", replace);
}
if (setValue) {
config.Set(key, result);
}
return result;
}
/// <summary>
/// Returns the replacement value of a config.
/// </summary>
private string ExpandValue (IConfig config, string search)
{
string result = null;
string[] replaces = search.Split ('|');
if (replaces.Length > 1) {
IConfig newConfig = this.Configs[replaces[0]];
if (newConfig == null) {
throw new ArgumentException ("Expand config not found: "
+ replaces[0]);
}
result = newConfig.Get (replaces[1]);
if (result == null) {
throw new ArgumentException ("Expand key not found: "
+ replaces[1]);
}
} else {
result = config.Get (search);
if (result == null) {
throw new ArgumentException ("Key not found: " + search);
}
}
return result;
}
#endregion
}
}

View File

@@ -0,0 +1,99 @@
#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;
namespace ExtensionLoader.Config
{
/// <include file='IConfig.xml' path='//Interface[@name="IConfig"]/docs/*' />
public interface IConfig
{
/// <include file='IConfig.xml' path='//Property[@name="ConfigSource"]/docs/*' />
IConfigSource ConfigSource { get; }
/// <include file='IConfig.xml' path='//Property[@name="Name"]/docs/*' />
string Name { get; set; }
/// <include file='IConfig.xml' path='//Property[@name="Alias"]/docs/*' />
AliasText Alias { get; }
/// <include file='IConfig.xml' path='//Method[@name="Contains"]/docs/*' />
bool Contains (string key);
/// <include file='IConfig.xml' path='//Method[@name="Get"]/docs/*' />
string Get (string key);
/// <include file='IConfig.xml' path='//Method[@name="GetDefault"]/docs/*' />
string Get (string key, string defaultValue);
/// <include file='IConfig.xml' path='//Method[@name="GetExpanded"]/docs/*' />
string GetExpanded (string key);
/// <include file='IConfig.xml' path='//Method[@name="Get"]/docs/*' />
string GetString (string key);
/// <include file='IConfig.xml' path='//Method[@name="GetDefault"]/docs/*' />
string GetString (string key, string defaultValue);
/// <include file='IConfig.xml' path='//Method[@name="GetInt"]/docs/*' />
int GetInt (string key);
/// <include file='IConfig.xml' path='//Method[@name="GetIntAlias"]/docs/*' />
int GetInt (string key, bool fromAlias);
/// <include file='IConfig.xml' path='//Method[@name="GetIntDefault"]/docs/*' />
int GetInt (string key, int defaultValue);
/// <include file='IConfig.xml' path='//Method[@name="GetIntDefaultAlias"]/docs/*' />
int GetInt (string key, int defaultValue, bool fromAlias);
/// <include file='IConfig.xml' path='//Method[@name="GetLong"]/docs/*' />
long GetLong (string key);
/// <include file='IConfig.xml' path='//Method[@name="GetLongDefault"]/docs/*' />
long GetLong (string key, long defaultValue);
/// <include file='IConfig.xml' path='//Method[@name="GetBoolean"]/docs/*' />
bool GetBoolean (string key);
/// <include file='IConfig.xml' path='//Method[@name="GetBooleanDefault"]/docs/*' />
bool GetBoolean (string key, bool defaultValue);
/// <include file='IConfig.xml' path='//Method[@name="GetFloat"]/docs/*' />
float GetFloat (string key);
/// <include file='IConfig.xml' path='//Method[@name="GetFloatDefault"]/docs/*' />
float GetFloat (string key, float defaultValue);
/// <include file='IConfig.xml' path='//Method[@name="GetDouble"]/docs/*' />
double GetDouble (string key);
/// <include file='IConfig.xml' path='//Method[@name="GetDoubleDefault"]/docs/*' />
double GetDouble (string key, double defaultValue);
/// <include file='IConfig.xml' path='//Method[@name="GetKeys"]/docs/*' />
string[] GetKeys ();
/// <include file='IConfig.xml' path='//Method[@name="GetValues"]/docs/*' />
string[] GetValues ();
/// <include file='IConfig.xml' path='//Method[@name="Set"]/docs/*' />
void Set (string key, object value);
/// <include file='IConfig.xml' path='//Method[@name="Remove"]/docs/*' />
void Remove (string key);
/// <include file='IConfig.xml' path='//Event[@name="KeySet"]/docs/*' />
event ConfigKeyEventHandler KeySet;
/// <include file='IConfig.xml' path='//Event[@name="KeyRemoved"]/docs/*' />
event ConfigKeyEventHandler KeyRemoved;
}
}

View File

@@ -0,0 +1,55 @@
#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;
namespace ExtensionLoader.Config
{
/// <include file='IConfigSource.xml' path='//Interface[@name="IConfigSource"]/docs/*' />
public interface IConfigSource
{
/// <include file='IConfigSource.xml' path='//Property[@name="Configs"]/docs/*' />
ConfigCollection Configs { get; }
/// <include file='IConfigSource.xml' path='//Property[@name="AutoSave"]/docs/*' />
bool AutoSave { get; set; }
/// <include file='IConfigSource.xml' path='//Property[@name="Alias"]/docs/*' />
AliasText Alias { get; }
/// <include file='IConfigSource.xml' path='//Method[@name="Merge"]/docs/*' />
void Merge (IConfigSource source);
/// <include file='IConfigSource.xml' path='//Method[@name="Save"]/docs/*' />
void Save ();
/// <include file='IConfigSource.xml' path='//Method[@name="Reload"]/docs/*' />
void Reload ();
/// <include file='IConfigSource.xml' path='//Method[@name="AddConfig"]/docs/*' />
IConfig AddConfig (string name);
/// <include file='IConfigSource.xml' path='//Method[@name="GetExpanded"]/docs/*' />
string GetExpanded (IConfig config, string key);
/// <include file='IConfigSource.xml' path='//Method[@name="ExpandKeyValues"]/docs/*' />
void ExpandKeyValues ();
/// <include file='IConfigSource.xml' path='//Method[@name="ReplaceKeyValues"]/docs/*' />
void ReplaceKeyValues ();
/// <include file='IConfigSource.xml' path='//Event[@name="Reloaded"]/docs/*' />
event EventHandler Reloaded;
/// <include file='IConfigSource.xml' path='//Event[@name="Saved"]/docs/*' />
event EventHandler Saved;
}
}

View File

@@ -0,0 +1,90 @@
#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.Collections;
using System.Globalization;
using ExtensionLoader.Util;
namespace ExtensionLoader.Config
{
/// <include file='IniConfig.xml' path='//Class[@name="IniConfig"]/docs/*' />
public class IniConfig : ConfigBase
{
#region Private variables
IniConfigSource parent = null;
#endregion
#region Constructors
/// <include file='IniConfig.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public IniConfig (string name, IConfigSource source)
: base(name, source)
{
parent = (IniConfigSource)source;
}
#endregion
#region Public properties
#endregion
#region Public methods
/// <include file='IniConfig.xml' path='//Method[@name="Get"]/docs/*' />
public override string Get (string key)
{
if (!parent.CaseSensitive) {
key = CaseInsensitiveKeyName (key);
}
return base.Get (key);
}
/// <include file='IniConfig.xml' path='//Method[@name="Set"]/docs/*' />
public override void Set (string key, object value)
{
if (!parent.CaseSensitive) {
key = CaseInsensitiveKeyName (key);
}
base.Set (key, value);
}
/// <include file='IniConfig.xml' path='//Method[@name="Remove"]/docs/*' />
public override void Remove (string key)
{
if (!parent.CaseSensitive) {
key = CaseInsensitiveKeyName (key);
}
base.Remove (key);
}
#endregion
#region Private methods
/// <summary>
/// Returns the key name if the case insensitivity is turned on.
/// </summary>
private string CaseInsensitiveKeyName (string key)
{
string result = null;
string lowerKey = key.ToLower ();
foreach (string currentKey in keys.Keys)
{
if (currentKey.ToLower () == lowerKey) {
result = currentKey;
break;
}
}
return (result == null) ? key : result;
}
#endregion
}
}

View File

@@ -0,0 +1,329 @@
#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
}
}

View File

@@ -0,0 +1,302 @@
#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.Util;
namespace ExtensionLoader.Ini
{
#region IniFileType enumeration
/// <include file='IniDocument.xml' path='//Enum[@name="IniFileType"]/docs/*' />
public enum IniFileType
{
/// <include file='IniDocument.xml' path='//Enum[@name="IniFileType"]/Value[@name="Standard"]/docs/*' />
Standard,
/// <include file='IniDocument.xml' path='//Enum[@name="IniFileType"]/Value[@name="PythonStyle"]/docs/*' />
PythonStyle,
/// <include file='IniDocument.xml' path='//Enum[@name="IniFileType"]/Value[@name="SambaStyle"]/docs/*' />
SambaStyle,
/// <include file='IniDocument.xml' path='//Enum[@name="IniFileType"]/Value[@name="MysqlStyle"]/docs/*' />
MysqlStyle,
/// <include file='IniDocument.xml' path='//Enum[@name="IniFileType"]/Value[@name="WindowsStyle"]/docs/*' />
WindowsStyle
}
#endregion
/// <include file='IniDocument.xml' path='//Class[@name="IniDocument"]/docs/*' />
public class IniDocument
{
#region Private variables
IniSectionCollection sections = new IniSectionCollection ();
ArrayList initialComment = new ArrayList ();
IniFileType fileType = IniFileType.Standard;
#endregion
#region Public properties
/// <include file='IniDocument.xml' path='//Property[@name="FileType"]/docs/*' />
public IniFileType FileType
{
get { return fileType; }
set { fileType = value; }
}
#endregion
#region Constructors
/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorPath"]/docs/*' />
public IniDocument (string filePath)
{
fileType = IniFileType.Standard;
Load (filePath);
}
/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorPathType"]/docs/*' />
public IniDocument (string filePath, IniFileType type)
{
fileType = type;
Load (filePath);
}
/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorTextReader"]/docs/*' />
public IniDocument (TextReader reader)
{
fileType = IniFileType.Standard;
Load (reader);
}
/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorTextReaderType"]/docs/*' />
public IniDocument (TextReader reader, IniFileType type)
{
fileType = type;
Load (reader);
}
/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorStream"]/docs/*' />
public IniDocument (Stream stream)
{
fileType = IniFileType.Standard;
Load (stream);
}
/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorStreamType"]/docs/*' />
public IniDocument (Stream stream, IniFileType type)
{
fileType = type;
Load (stream);
}
/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorIniReader"]/docs/*' />
public IniDocument (IniReader reader)
{
fileType = IniFileType.Standard;
Load (reader);
}
/// <include file='IniDocument.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public IniDocument ()
{
}
#endregion
#region Public methods
/// <include file='IniDocument.xml' path='//Method[@name="LoadPath"]/docs/*' />
public void Load (string filePath)
{
Load (new StreamReader (filePath));
}
/// <include file='IniDocument.xml' path='//Method[@name="LoadTextReader"]/docs/*' />
public void Load (TextReader reader)
{
Load (GetIniReader (reader, fileType));
}
/// <include file='IniDocument.xml' path='//Method[@name="LoadStream"]/docs/*' />
public void Load (Stream stream)
{
Load (new StreamReader (stream));
}
/// <include file='IniDocument.xml' path='//Method[@name="LoadIniReader"]/docs/*' />
public void Load (IniReader reader)
{
LoadReader (reader);
}
/// <include file='IniSection.xml' path='//Property[@name="Comment"]/docs/*' />
public IniSectionCollection Sections
{
get { return sections; }
}
/// <include file='IniDocument.xml' path='//Method[@name="SaveTextWriter"]/docs/*' />
public void Save (TextWriter textWriter)
{
IniWriter writer = GetIniWriter (textWriter, fileType);
IniItem item = null;
IniSection section = null;
foreach (string comment in initialComment)
{
writer.WriteEmpty (comment);
}
for (int j = 0; j < sections.Count; j++)
{
section = sections[j];
writer.WriteSection (section.Name, section.Comment);
for (int i = 0; i < section.ItemCount; i++)
{
item = section.GetItem (i);
switch (item.Type)
{
case IniType.Key:
writer.WriteKey (item.Name, item.Value, item.Comment);
break;
case IniType.Empty:
writer.WriteEmpty (item.Comment);
break;
}
}
}
writer.Close ();
}
/// <include file='IniDocument.xml' path='//Method[@name="SavePath"]/docs/*' />
public void Save (string filePath)
{
StreamWriter writer = new StreamWriter (filePath);
Save (writer);
writer.Close ();
}
/// <include file='IniDocument.xml' path='//Method[@name="SaveStream"]/docs/*' />
public void Save (Stream stream)
{
Save (new StreamWriter (stream));
}
#endregion
#region Private methods
/// <summary>
/// Loads the file not saving comments.
/// </summary>
private void LoadReader (IniReader reader)
{
reader.IgnoreComments = false;
bool sectionFound = false;
IniSection section = null;
try {
while (reader.Read ())
{
switch (reader.Type)
{
case IniType.Empty:
if (!sectionFound) {
initialComment.Add (reader.Comment);
} else {
section.Set (reader.Comment);
}
break;
case IniType.Section:
sectionFound = true;
// If section already exists then overwrite it
if (sections[reader.Name] != null) {
sections.Remove (reader.Name);
}
section = new IniSection (reader.Name, reader.Comment);
sections.Add (section);
break;
case IniType.Key:
if (section.GetValue (reader.Name) == null) {
section.Set (reader.Name, reader.Value, reader.Comment);
}
break;
}
}
} catch (Exception ex) {
throw ex;
} finally {
// Always close the file
reader.Close ();
}
}
/// <summary>
/// Returns a proper INI reader depending upon the type parameter.
/// </summary>
private IniReader GetIniReader (TextReader reader, IniFileType type)
{
IniReader result = new IniReader (reader);
switch (type)
{
case IniFileType.Standard:
// do nothing
break;
case IniFileType.PythonStyle:
result.AcceptCommentAfterKey = false;
result.SetCommentDelimiters (new char[] { ';', '#' });
result.SetAssignDelimiters (new char[] { ':' });
break;
case IniFileType.SambaStyle:
result.AcceptCommentAfterKey = false;
result.SetCommentDelimiters (new char[] { ';', '#' });
result.LineContinuation = true;
break;
case IniFileType.MysqlStyle:
result.AcceptCommentAfterKey = false;
result.AcceptNoAssignmentOperator = true;
result.SetCommentDelimiters (new char[] { '#' });
result.SetAssignDelimiters (new char[] { ':', '=' });
break;
case IniFileType.WindowsStyle:
result.ConsumeAllKeyText = true;
break;
}
return result;
}
/// <summary>
/// Returns a proper IniWriter depending upon the type parameter.
/// </summary>
private IniWriter GetIniWriter (TextWriter reader, IniFileType type)
{
IniWriter result = new IniWriter (reader);
switch (type)
{
case IniFileType.Standard:
case IniFileType.WindowsStyle:
// do nothing
break;
case IniFileType.PythonStyle:
result.AssignDelimiter = ':';
result.CommentDelimiter = '#';
break;
case IniFileType.SambaStyle:
case IniFileType.MysqlStyle:
result.AssignDelimiter = '=';
result.CommentDelimiter = '#';
break;
}
return result;
}
#endregion
}
}

View File

@@ -0,0 +1,121 @@
#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.Security;
using System.Globalization;
using System.Security.Permissions;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace ExtensionLoader.Ini
{
/// <include file='IniException.xml' path='//Class[@name="IniException"]/docs/*' />
#if (NET_COMPACT_1_0)
#else
[Serializable]
#endif
public class IniException : SystemException /*, ISerializable */
{
#region Private variables
IniReader iniReader = null;
string message = "";
#endregion
#region Public properties
/// <include file='IniException.xml' path='//Property[@name="LinePosition"]/docs/*' />
public int LinePosition
{
get {
return (iniReader == null) ? 0 : iniReader.LinePosition;
}
}
/// <include file='IniException.xml' path='//Property[@name="LineNumber"]/docs/*' />
public int LineNumber
{
get {
return (iniReader == null) ? 0 : iniReader.LineNumber;
}
}
/// <include file='IniException.xml' path='//Property[@name="Message"]/docs/*' />
public override string Message
{
get {
if (iniReader == null) {
return base.Message;
}
return String.Format (CultureInfo.InvariantCulture, "{0} - Line: {1}, Position: {2}.",
message, this.LineNumber, this.LinePosition);
}
}
#endregion
#region Constructors
/// <include file='IniException.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public IniException ()
: base ()
{
this.message = "An error has occurred";
}
/// <include file='IniException.xml' path='//Constructor[@name="ConstructorException"]/docs/*' />
public IniException (string message, Exception exception)
: base (message, exception)
{
}
/// <include file='IniException.xml' path='//Constructor[@name="ConstructorMessage"]/docs/*' />
public IniException (string message)
: base (message)
{
this.message = message;
}
/// <include file='IniException.xml' path='//Constructor[@name="ConstructorTextReader"]/docs/*' />
internal IniException (IniReader reader, string message)
: this (message)
{
iniReader = reader;
this.message = message;
}
#if (NET_COMPACT_1_0)
#else
/// <include file='IniException.xml' path='//Constructor[@name="ConstructorSerialize"]/docs/*' />
protected IniException (SerializationInfo info, StreamingContext context)
: base (info, context)
{
}
#endif
#endregion
#region Public methods
#if (NET_COMPACT_1_0)
#else
/// <include file='IniException.xml' path='//Method[@name="GetObjectData"]/docs/*' />
[SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter=true)]
public override void GetObjectData (SerializationInfo info,
StreamingContext context)
{
base.GetObjectData (info, context);
if (iniReader != null) {
info.AddValue ("lineNumber", iniReader.LineNumber);
info.AddValue ("linePosition", iniReader.LinePosition);
}
}
#endif
#endregion
}
}

View File

@@ -0,0 +1,54 @@
using System;
namespace ExtensionLoader.Ini
{
/// <include file='IniItem.xml' path='//Class[@name="IniItem"]/docs/*' />
public class IniItem
{
#region Private variables
IniType iniType = IniType.Empty;
string iniName = "";
string iniValue = "";
string iniComment = null;
#endregion
#region Public properties
/// <include file='IniItem.xml' path='//Property[@name="Type"]/docs/*' />
public IniType Type
{
get { return iniType; }
set { iniType = value; }
}
/// <include file='IniItem.xml' path='//Property[@name="Value"]/docs/*' />
public string Value
{
get { return iniValue; }
set { iniValue = value; }
}
/// <include file='IniItem.xml' path='//Property[@name="Name"]/docs/*' />
public string Name
{
get { return iniName; }
}
/// <include file='IniItem.xml' path='//Property[@name="Comment"]/docs/*' />
public string Comment
{
get { return iniComment; }
set { iniComment = value; }
}
#endregion
/// <include file='IniItem.xml' path='//Constructor[@name="Constructor"]/docs/*' />
internal protected IniItem (string name, string value, IniType type, string comment)
{
iniName = name;
iniValue = value;
iniType = type;
iniComment = comment;
}
}
}

View File

@@ -0,0 +1,652 @@
#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.Text;
using System.Collections;
namespace ExtensionLoader.Ini
{
#region IniReadState enumeration
/// <include file='IniReader.xml' path='//Enum[@name="IniReadState"]/docs/*' />
public enum IniReadState : int
{
/// <include file='IniReader.xml' path='//Enum[@name="IniReadState"]/Value[@name="Closed"]/docs/*' />
Closed,
/// <include file='IniReader.xml' path='//Enum[@name="IniReadState"]/Value[@name="EndOfFile"]/docs/*' />
EndOfFile,
/// <include file='IniReader.xml' path='//Enum[@name="IniReadState"]/Value[@name="Error"]/docs/*' />
Error,
/// <include file='IniReader.xml' path='//Enum[@name="IniReadState"]/Value[@name="Initial"]/docs/*' />
Initial,
/// <include file='IniReader.xml' path='//Enum[@name="IniReadState"]/Value[@name="Interactive"]/docs/*' />
Interactive
};
#endregion
#region IniType enumeration
/// <include file='IniReader.xml' path='//Enum[@name="IniType"]/docs/*' />
public enum IniType : int
{
/// <include file='IniReader.xml' path='//Enum[@name="IniType"]/Value[@name="Section"]/docs/*' />
Section,
/// <include file='IniReader.xml' path='//Enum[@name="IniType"]/Value[@name="Key"]/docs/*' />
Key,
/// <include file='IniReader.xml' path='//Enum[@name="IniType"]/Value[@name="Empty"]/docs/*' />
Empty
}
#endregion
/// <include file='IniReader.xml' path='//Class[@name="IniReader"]/docs/*' />
public class IniReader : IDisposable
{
#region Private variables
int lineNumber = 1;
int column = 1;
IniType iniType = IniType.Empty;
TextReader textReader = null;
bool ignoreComments = false;
StringBuilder name = new StringBuilder ();
StringBuilder value = new StringBuilder ();
StringBuilder comment = new StringBuilder ();
IniReadState readState = IniReadState.Initial;
bool hasComment = false;
bool disposed = false;
bool lineContinuation = false;
bool acceptCommentAfterKey = true;
bool acceptNoAssignmentOperator = false;
bool consumeAllKeyText = false;
char[] commentDelimiters = new char[] { ';' };
char[] assignDelimiters = new char[] { '=' };
#endregion
#region Public properties
/// <include file='IniReader.xml' path='//Property[@name="Name"]/docs/*' />
public string Name
{
get { return this.name.ToString (); }
}
/// <include file='IniReader.xml' path='//Property[@name="Value"]/docs/*' />
public string Value
{
get { return this.value.ToString (); }
}
/// <include file='IniReader.xml' path='//Property[@name="Type"]/docs/*' />
public IniType Type
{
get { return iniType; }
}
/// <include file='IniReader.xml' path='//Property[@name="Comment"]/docs/*' />
public string Comment
{
get { return (hasComment) ? this.comment.ToString () : null; }
}
/// <include file='IniReader.xml' path='//Property[@name="LineNumber"]/docs/*' />
public int LineNumber
{
get { return lineNumber; }
}
/// <include file='IniReader.xml' path='//Property[@name="LinePosition"]/docs/*' />
public int LinePosition
{
get { return column; }
}
/// <include file='IniReader.xml' path='//Property[@name="IgnoreComments"]/docs/*' />
public bool IgnoreComments
{
get { return ignoreComments; }
set { ignoreComments = value; }
}
/// <include file='IniReader.xml' path='//Property[@name="ReadState"]/docs/*' />
public IniReadState ReadState
{
get { return readState; }
}
/// <include file='IniReader.xml' path='//Property[@name="LineContinuation"]/docs/*' />
public bool LineContinuation
{
get { return lineContinuation; }
set { lineContinuation = value; }
}
/// <include file='IniReader.xml' path='//Property[@name="AcceptCommentAfterKey"]/docs/*' />
public bool AcceptCommentAfterKey
{
get { return acceptCommentAfterKey; }
set { acceptCommentAfterKey = value; }
}
/// <include file='IniReader.xml' path='//Property[@name="AcceptNoAssignmentOperator"]/docs/*' />
public bool AcceptNoAssignmentOperator
{
get { return acceptNoAssignmentOperator; }
set { acceptNoAssignmentOperator = value; }
}
/// <include file='IniReader.xml' path='//Property[@name="ConsumeAllKeyText"]/docs/*' />
public bool ConsumeAllKeyText
{
get { return consumeAllKeyText; }
set { consumeAllKeyText = value; }
}
#endregion
#region Constructors
/// <include file='IniReader.xml' path='//Constructor[@name="ConstructorPath"]/docs/*' />
public IniReader (string filePath)
{
textReader = new StreamReader (filePath);
}
/// <include file='IniReader.xml' path='//Constructor[@name="ConstructorTextReader"]/docs/*' />
public IniReader (TextReader reader)
{
textReader = reader;
}
/// <include file='IniReader.xml' path='//Constructor[@name="ConstructorStream"]/docs/*' />
public IniReader (Stream stream)
: this (new StreamReader (stream))
{
}
#endregion
#region Public methods
/// <include file='IniReader.xml' path='//Method[@name="Read"]/docs/*' />
public bool Read ()
{
bool result = false;
if (readState != IniReadState.EndOfFile
|| readState != IniReadState.Closed) {
readState = IniReadState.Interactive;
result = ReadNext ();
}
return result;
}
/// <include file='IniReader.xml' path='//Method[@name="MoveToNextSection"]/docs/*' />
public bool MoveToNextSection ()
{
bool result = false;
while (true)
{
result = Read ();
if (iniType == IniType.Section || !result) {
break;
}
}
return result;
}
/// <include file='IniReader.xml' path='//Method[@name="MoveToNextKey"]/docs/*' />
public bool MoveToNextKey ()
{
bool result = false;
while (true)
{
result = Read ();
if (iniType == IniType.Section) {
result = false;
break;
}
if (iniType == IniType.Key || !result) {
break;
}
}
return result;
}
/// <include file='IniReader.xml' path='//Method[@name="Close"]/docs/*' />
public void Close ()
{
Reset ();
readState = IniReadState.Closed;
if (textReader != null) {
textReader.Close ();
}
}
/// <include file='IniReader.xml' path='//Method[@name="Dispose"]/docs/*' />
public void Dispose ()
{
Dispose (true);
}
/// <include file='IniReader.xml' path='//Method[@name="GetCommentDelimiters"]/docs/*' />
public char[] GetCommentDelimiters ()
{
char[] result = new char[commentDelimiters.Length];
Array.Copy (commentDelimiters, 0, result, 0, commentDelimiters.Length);
return result;
}
/// <include file='IniReader.xml' path='//Method[@name="SetCommentDelimiters"]/docs/*' />
public void SetCommentDelimiters (char[] delimiters)
{
if (delimiters.Length < 1) {
throw new ArgumentException ("Must supply at least one delimiter");
}
commentDelimiters = delimiters;
}
/// <include file='IniReader.xml' path='//Method[@name="GetAssignDelimiters"]/docs/*' />
public char[] GetAssignDelimiters ()
{
char[] result = new char[assignDelimiters.Length];
Array.Copy (assignDelimiters, 0, result, 0, assignDelimiters.Length);
return result;
}
/// <include file='IniReader.xml' path='//Method[@name="SetAssignDelimiters"]/docs/*' />
public void SetAssignDelimiters (char[] delimiters)
{
if (delimiters.Length < 1) {
throw new ArgumentException ("Must supply at least one delimiter");
}
assignDelimiters = delimiters;
}
#endregion
#region Protected methods
/// <include file='IniReader.xml' path='//Method[@name="DisposeBoolean"]/docs/*' />
protected virtual void Dispose (bool disposing)
{
if (!disposed) {
textReader.Close ();
disposed = true;
if (disposing) {
GC.SuppressFinalize (this);
}
}
}
#endregion
#region Private methods
/// <summary>
/// Destructor.
/// </summary>
~IniReader ()
{
Dispose (false);
}
/// <summary>
/// Resets all of the current INI line data.
/// </summary>
private void Reset ()
{
this.name.Remove (0, this.name.Length);
this.value.Remove (0, this.value.Length);
this.comment.Remove (0, this.comment.Length);
iniType = IniType.Empty;
hasComment = false;
}
/// <summary>
/// Reads the next INI line item.
/// </summary>
private bool ReadNext ()
{
bool result = true;
int ch = PeekChar ();
Reset ();
if (IsComment (ch)) {
iniType = IniType.Empty;
ReadChar (); // consume comment character
ReadComment ();
return result;
}
switch (ch)
{
case ' ':
case '\t':
case '\r':
SkipWhitespace ();
ReadNext ();
break;
case '\n':
ReadChar ();
break;
case '[':
ReadSection ();
break;
case -1:
readState = IniReadState.EndOfFile;
result = false;
break;
default:
ReadKey ();
break;
}
return result;
}
/// <summary>
/// Reads a comment. Must start after the comment delimiter.
/// </summary>
private void ReadComment ()
{
int ch = -1;
SkipWhitespace ();
hasComment = true;
do
{
ch = ReadChar ();
this.comment.Append ((char)ch);
} while (!EndOfLine (ch));
RemoveTrailingWhitespace (this.comment);
}
/// <summary>
/// Removes trailing whitespace from a StringBuilder.
/// </summary>
private void RemoveTrailingWhitespace (StringBuilder builder)
{
string temp = builder.ToString ();
builder.Remove (0, builder.Length);
builder.Append (temp.TrimEnd (null));
}
/// <summary>
/// Reads a key.
/// </summary>
private void ReadKey ()
{
int ch = -1;
iniType = IniType.Key;
while (true)
{
ch = PeekChar ();
if (IsAssign (ch)) {
ReadChar ();
break;
}
if (EndOfLine (ch)) {
if (acceptNoAssignmentOperator) {
break;
}
throw new IniException (this,
String.Format ("Expected assignment operator ({0})",
assignDelimiters[0]));
}
this.name.Append ((char)ReadChar ());
}
ReadKeyValue ();
SearchForComment ();
RemoveTrailingWhitespace (this.name);
}
/// <summary>
/// Reads the value of a key.
/// </summary>
private void ReadKeyValue ()
{
int ch = -1;
bool foundQuote = false;
int characters = 0;
SkipWhitespace ();
while (true)
{
ch = PeekChar ();
if (!IsWhitespace (ch)) {
characters++;
}
if (!this.ConsumeAllKeyText && ch == '"') {
ReadChar ();
if (!foundQuote && characters == 1) {
foundQuote = true;
continue;
} else {
break;
}
}
if (foundQuote && EndOfLine (ch)) {
throw new IniException (this, "Expected closing quote (\")");
}
// Handle line continuation
if (lineContinuation && ch == '\\')
{
StringBuilder buffer = new StringBuilder ();
buffer.Append ((char)ReadChar ()); // append '\'
while (PeekChar () != '\n' && IsWhitespace (PeekChar ()))
{
if (PeekChar () != '\r') {
buffer.Append ((char)ReadChar ());
} else {
ReadChar (); // consume '\r'
}
}
if (PeekChar () == '\n') {
// continue reading key value on next line
ReadChar ();
continue;
} else {
// Replace consumed characters
this.value.Append (buffer.ToString ());
}
}
if (!this.ConsumeAllKeyText) {
// If accepting comments then don't consume as key value
if (acceptCommentAfterKey && IsComment (ch) && !foundQuote) {
break;
}
}
// Always break at end of line
if (EndOfLine (ch)) {
break;
}
this.value.Append ((char)ReadChar ());
}
if (!foundQuote) {
RemoveTrailingWhitespace (this.value);
}
}
/// <summary>
/// Reads an INI section.
/// </summary>
private void ReadSection ()
{
int ch = -1;
iniType = IniType.Section;
ch = ReadChar (); // consume "["
while (true)
{
ch = PeekChar ();
if (ch == ']') {
break;
}
if (EndOfLine (ch)) {
throw new IniException (this, "Expected section end (])");
}
this.name.Append ((char)ReadChar ());
}
ConsumeToEnd (); // all after '[' is garbage
RemoveTrailingWhitespace (this.name);
}
/// <summary>
/// Looks for a comment.
/// </summary>
private void SearchForComment ()
{
int ch = ReadChar ();
while (!EndOfLine (ch))
{
if (IsComment (ch)) {
if (ignoreComments) {
ConsumeToEnd ();
} else {
ReadComment ();
}
break;
}
ch = ReadChar ();
}
}
/// <summary>
/// Consumes all data until the end of a line.
/// </summary>
private void ConsumeToEnd ()
{
int ch = -1;
do
{
ch = ReadChar ();
} while (!EndOfLine (ch));
}
/// <summary>
/// Returns and consumes the next character from the stream.
/// </summary>
private int ReadChar ()
{
int result = textReader.Read ();
if (result == '\n') {
lineNumber++;
column = 1;
} else {
column++;
}
return result;
}
/// <summary>
/// Returns the next upcoming character from the stream.
/// </summary>
private int PeekChar ()
{
return textReader.Peek ();
}
/// <summary>
/// Returns true if a comment character is found.
/// </summary>
private bool IsComment (int ch)
{
return HasCharacter (commentDelimiters, ch);
}
/// <summary>
/// Returns true if character is an assign character.
/// </summary>
private bool IsAssign (int ch)
{
return HasCharacter (assignDelimiters, ch);
}
/// <summary>
/// Returns true if the character is found in the given array.
/// </summary>
private bool HasCharacter (char[] characters, int ch)
{
bool result = false;
for (int i = 0; i < characters.Length; i++)
{
if (ch == characters[i])
{
result = true;
break;
}
}
return result;
}
/// <summary>
/// Returns true if a value is whitespace.
/// </summary>
private bool IsWhitespace (int ch)
{
return ch == 0x20 || ch == 0x9 || ch == 0xD || ch == 0xA;
}
/// <summary>
/// Skips all whitespace.
/// </summary>
private void SkipWhitespace ()
{
while (IsWhitespace (PeekChar ()))
{
if (EndOfLine (PeekChar ())) {
break;
}
ReadChar ();
}
}
/// <summary>
/// Returns true if an end of line is found. End of line
/// includes both an end of line or end of file.
/// </summary>
private bool EndOfLine (int ch)
{
return (ch == '\n' || ch == -1);
}
#endregion
}
}

View File

@@ -0,0 +1,155 @@
#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.Collections;
using ExtensionLoader.Util;
namespace ExtensionLoader.Ini
{
/// <include file='IniSection.xml' path='//Class[@name="IniSection"]/docs/*' />
public class IniSection
{
#region Private variables
OrderedList configList = new OrderedList ();
string name = "";
string comment = null;
int commentCount = 0;
#endregion
#region Constructors
/// <include file='IniSection.xml' path='//Constructor[@name="ConstructorComment"]/docs/*' />
public IniSection (string name, string comment)
{
this.name = name;
this.comment = comment;
}
/// <include file='IniSection.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public IniSection (string name)
: this (name, null)
{
}
#endregion
#region Public properties
/// <include file='IniSection.xml' path='//Property[@name="Name"]/docs/*' />
public string Name
{
get { return name; }
}
/// <include file='IniSection.xml' path='//Property[@name="Comment"]/docs/*' />
public string Comment
{
get { return comment; }
}
/// <include file='IniSection.xml' path='//Property[@name="ItemCount"]/docs/*' />
public int ItemCount
{
get { return configList.Count; }
}
#endregion
#region Public methods
/// <include file='IniSection.xml' path='//Method[@name="GetValue"]/docs/*' />
public string GetValue (string key)
{
string result = null;
if (Contains (key)) {
IniItem item = (IniItem)configList[key];
result = item.Value;
}
return result;
}
/// <include file='IniSection.xml' path='//Method[@name="GetItem"]/docs/*' />
public IniItem GetItem (int index)
{
return (IniItem)configList[index];
}
/// <include file='IniSection.xml' path='//Method[@name="GetKeys"]/docs/*' />
public string[] GetKeys ()
{
ArrayList list = new ArrayList ();
IniItem item = null;
for (int i = 0; i < configList.Count; i++)
{
item = (IniItem)configList[i];
if (item.Type == IniType.Key) {
list.Add (item.Name);
}
}
string[] result = new string[list.Count];
list.CopyTo (result, 0);
return result;
}
/// <include file='IniSection.xml' path='//Method[@name="Contains"]/docs/*' />
public bool Contains (string key)
{
return (configList[key] != null);
}
/// <include file='IniSection.xml' path='//Method[@name="SetKeyComment"]/docs/*' />
public void Set (string key, string value, string comment)
{
IniItem item = null;
if (Contains (key)) {
item = (IniItem)configList[key];
item.Value = value;
item.Comment = comment;
} else {
item = new IniItem (key, value, IniType.Key, comment);
configList.Add (key, item);
}
}
/// <include file='IniSection.xml' path='//Method[@name="SetKey"]/docs/*' />
public void Set (string key, string value)
{
Set (key, value, null);
}
/// <include file='IniSection.xml' path='//Method[@name="SetComment"]/docs/*' />
public void Set (string comment)
{
string name = "#comment" + commentCount;
IniItem item = new IniItem (name, null,
IniType.Empty, comment);
configList.Add (name, item);
commentCount++;
}
/// <include file='IniSection.xml' path='//Method[@name="SetNoComment"]/docs/*' />
public void Set ()
{
Set (null);
}
/// <include file='IniSection.xml' path='//Method[@name="Remove"]/docs/*' />
public void Remove (string key)
{
if (Contains (key)) {
configList.Remove (key);
}
}
#endregion
}
}

View File

@@ -0,0 +1,95 @@
#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.Collections;
using ExtensionLoader.Util;
namespace ExtensionLoader.Ini
{
/// <include file='IniSectionCollection.xml' path='//Class[@name="IniSectionCollection"]/docs/*' />
public class IniSectionCollection : ICollection, IEnumerable
{
#region Private variables
OrderedList list = new OrderedList ();
#endregion
#region Public properties
/// <include file='IniSectionCollection.xml' path='//Property[@name="ItemIndex"]/docs/*' />
public IniSection this[int index]
{
get { return (IniSection)list[index]; }
}
/// <include file='IniSectionCollection.xml' path='//Property[@name="ItemName"]/docs/*' />
public IniSection this[string configName]
{
get { return (IniSection)list[configName]; }
}
/// <include file='IniSectionCollection.xml' path='//Property[@name="Count"]/docs/*' />
public int Count
{
get { return list.Count; }
}
/// <include file='IniSectionCollection.xml' path='//Property[@name="SyncRoot"]/docs/*' />
public object SyncRoot
{
get { return list.SyncRoot; }
}
/// <include file='IniSectionCollection.xml' path='//Property[@name="IsSynchronized"]/docs/*' />
public bool IsSynchronized
{
get { return list.IsSynchronized; }
}
#endregion
#region Public methods
/// <include file='IniSectionCollection.xml' path='//Method[@name="Add"]/docs/*' />
public void Add (IniSection section)
{
if (list.Contains (section)) {
throw new ArgumentException ("IniSection already exists");
}
list.Add (section.Name, section);
}
/// <include file='IniSectionCollection.xml' path='//Method[@name="Remove"]/docs/*' />
public void Remove (string config)
{
list.Remove (config);
}
/// <include file='IniSectionCollection.xml' path='//Method[@name="CopyTo"]/docs/*' />
public void CopyTo (Array array, int index)
{
list.CopyTo (array, index);
}
/// <include file='IniSectionCollection.xml' path='//Method[@name="CopyToStrong"]/docs/*' />
public void CopyTo (IniSection[] array, int index)
{
((ICollection)list).CopyTo (array, index);
}
/// <include file='IniSectionCollection.xml' path='//Method[@name="GetEnumerator"]/docs/*' />
public IEnumerator GetEnumerator ()
{
return list.GetEnumerator ();
}
#endregion
#region Private methods
#endregion
}
}

View File

@@ -0,0 +1,308 @@
#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.Text;
namespace ExtensionLoader.Ini
{
#region IniWriteState enumeration
/// <include file='IniWriter.xml' path='//Enum[@name="IniWriteState"]/docs/*' />
public enum IniWriteState : int
{
/// <include file='IniWriter.xml' path='//Enum[@name="IniWriteState"]/Value[@name="Start"]/docs/*' />
Start,
/// <include file='IniWriter.xml' path='//Enum[@name="IniWriteState"]/Value[@name="BeforeFirstSection"]/docs/*' />
BeforeFirstSection,
/// <include file='IniWriter.xml' path='//Enum[@name="IniWriteState"]/Value[@name="Section"]/docs/*' />
Section,
/// <include file='IniWriter.xml' path='//Enum[@name="IniWriteState"]/Value[@name="Closed"]/docs/*' />
Closed
};
#endregion
/// <include file='IniWriter.xml' path='//Class[@name="IniWriter"]/docs/*' />
public class IniWriter : IDisposable
{
#region Private variables
int indentation = 0;
bool useValueQuotes = false;
IniWriteState writeState = IniWriteState.Start;
char commentDelimiter = ';';
char assignDelimiter = '=';
TextWriter textWriter = null;
string eol = "\r\n";
StringBuilder indentationBuffer = new StringBuilder ();
Stream baseStream = null;
bool disposed = false;
#endregion
#region Public properties
/// <include file='IniWriter.xml' path='//Property[@name="Indentation"]/docs/*' />
public int Indentation
{
get { return indentation; }
set
{
if (value < 0)
throw new ArgumentException ("Negative values are illegal");
indentation = value;
indentationBuffer.Remove(0, indentationBuffer.Length);
for (int i = 0; i < value; i++)
indentationBuffer.Append (' ');
}
}
/// <include file='IniWriter.xml' path='//Property[@name="UseValueQuotes"]/docs/*' />
public bool UseValueQuotes
{
get { return useValueQuotes; }
set { useValueQuotes = value; }
}
/// <include file='IniWriter.xml' path='//Property[@name="WriteState"]/docs/*' />
public IniWriteState WriteState
{
get { return writeState; }
}
/// <include file='IniWriter.xml' path='//Property[@name="CommentDelimiter"]/docs/*' />
public char CommentDelimiter
{
get { return commentDelimiter; }
set { commentDelimiter = value; }
}
/// <include file='IniWriter.xml' path='//Property[@name="AssignDelimiter"]/docs/*' />
public char AssignDelimiter
{
get { return assignDelimiter; }
set { assignDelimiter = value; }
}
/// <include file='IniWriter.xml' path='//Property[@name="BaseStream"]/docs/*' />
public Stream BaseStream
{
get { return baseStream; }
}
#endregion
#region Constructors
/// <include file='IniWriter.xml' path='//Constructor[@name="ConstructorPath"]/docs/*' />
public IniWriter(string filePath)
: this (new FileStream (filePath, FileMode.Create, FileAccess.Write, FileShare.None))
{
}
/// <include file='IniWriter.xml' path='//Constructor[@name="ConstructorTextWriter"]/docs/*' />
public IniWriter (TextWriter writer)
{
textWriter = writer;
StreamWriter streamWriter = writer as StreamWriter;
if (streamWriter != null) {
baseStream = streamWriter.BaseStream;
}
}
/// <include file='IniWriter.xml' path='//Constructor[@name="ConstructorStream"]/docs/*' />
public IniWriter (Stream stream)
: this (new StreamWriter (stream))
{
}
#endregion
#region Public methods
/// <include file='IniWriter.xml' path='//Method[@name="Close"]/docs/*' />
public void Close ()
{
textWriter.Close ();
writeState = IniWriteState.Closed;
}
/// <include file='IniWriter.xml' path='//Method[@name="Flush"]/docs/*' />
public void Flush ()
{
textWriter.Flush ();
}
/// <include file='IniWriter.xml' path='//Method[@name="ToString"]/docs/*' />
public override string ToString ()
{
return textWriter.ToString ();
}
/// <include file='IniWriter.xml' path='//Method[@name="WriteSection"]/docs/*' />
public void WriteSection (string section)
{
ValidateState ();
writeState = IniWriteState.Section;
WriteLine ("[" + section + "]");
}
/// <include file='IniWriter.xml' path='//Method[@name="WriteSectionComment"]/docs/*' />
public void WriteSection (string section, string comment)
{
ValidateState ();
writeState = IniWriteState.Section;
WriteLine ("[" + section + "]" + Comment(comment));
}
/// <include file='IniWriter.xml' path='//Method[@name="WriteKey"]/docs/*' />
public void WriteKey (string key, string value)
{
ValidateStateKey ();
WriteLine (key + " " + assignDelimiter + " " + GetKeyValue (value));
}
/// <include file='IniWriter.xml' path='//Method[@name="WriteKeyComment"]/docs/*' />
public void WriteKey (string key, string value, string comment)
{
ValidateStateKey ();
WriteLine (key + " " + assignDelimiter + " " + GetKeyValue (value) + Comment (comment));
}
/// <include file='IniWriter.xml' path='//Method[@name="WriteEmpty"]/docs/*' />
public void WriteEmpty ()
{
ValidateState ();
if (writeState == IniWriteState.Start) {
writeState = IniWriteState.BeforeFirstSection;
}
WriteLine ("");
}
/// <include file='IniWriter.xml' path='//Method[@name="WriteEmptyComment"]/docs/*' />
public void WriteEmpty (string comment)
{
ValidateState ();
if (writeState == IniWriteState.Start) {
writeState = IniWriteState.BeforeFirstSection;
}
if (comment == null) {
WriteLine ("");
} else {
WriteLine (commentDelimiter + " " + comment);
}
}
/// <include file='IniWriter.xml' path='//Method[@name="Dispose"]/docs/*' />
public void Dispose ()
{
Dispose (true);
}
#endregion
#region Protected methods
/// <include file='IniWriter.xml' path='//Method[@name="DisposeBoolean"]/docs/*' />
protected virtual void Dispose (bool disposing)
{
if (!disposed)
{
textWriter.Close ();
baseStream.Close ();
disposed = true;
if (disposing)
{
GC.SuppressFinalize (this);
}
}
}
#endregion
#region Private methods
/// <summary>
/// Destructor.
/// </summary>
~IniWriter ()
{
Dispose (false);
}
/// <summary>
/// Returns the value of a key.
/// </summary>
private string GetKeyValue (string text)
{
string result;
if (useValueQuotes) {
result = MassageValue ('"' + text + '"');
} else {
result = MassageValue (text);
}
return result;
}
/// <summary>
/// Validates whether a key can be written.
/// </summary>
private void ValidateStateKey ()
{
ValidateState ();
switch (writeState)
{
case IniWriteState.BeforeFirstSection:
case IniWriteState.Start:
throw new InvalidOperationException ("The WriteState is not Section");
case IniWriteState.Closed:
throw new InvalidOperationException ("The writer is closed");
}
}
/// <summary>
/// Validates the state to determine if the item can be written.
/// </summary>
private void ValidateState ()
{
if (writeState == IniWriteState.Closed) {
throw new InvalidOperationException ("The writer is closed");
}
}
/// <summary>
/// Returns a formatted comment.
/// </summary>
private string Comment (string text)
{
return (text == null) ? "" : (" " + commentDelimiter + " " + text);
}
/// <summary>
/// Writes data to the writer.
/// </summary>
private void Write (string value)
{
textWriter.Write (indentationBuffer.ToString () + value);
}
/// <summary>
/// Writes a full line to the writer.
/// </summary>
private void WriteLine (string value)
{
Write (value + eol);
}
/// <summary>
/// Fixes the incoming value to prevent illegal characters from
/// hurting the integrity of the INI file.
/// </summary>
private string MassageValue (string text)
{
return text.Replace ("\n", "");
}
#endregion
}
}

View File

@@ -0,0 +1,147 @@
#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.Collections;
namespace Nini.Config
{
/// <include file='AliasText.xml' path='//Class[@name="AliasText"]/docs/*' />
public class AliasText
{
#region Private variables
Hashtable intAlias = null;
Hashtable booleanAlias = null;
#endregion
#region Constructors
/// <include file='AliasText.xml' path='//Constructor[@name="AliasText"]/docs/*' />
public AliasText ()
{
intAlias = InsensitiveHashtable ();
booleanAlias = InsensitiveHashtable ();
DefaultAliasLoad ();
}
#endregion
#region Public methods
/// <include file='AliasText.xml' path='//Method[@name="AddAliasInt"]/docs/*' />
public void AddAlias (string key, string alias, int value)
{
if (intAlias.Contains (key)) {
Hashtable keys = (Hashtable)intAlias[key];
keys[alias] = value;
} else {
Hashtable keys = InsensitiveHashtable ();
keys[alias] = value;
intAlias.Add (key, keys);
}
}
/// <include file='AliasText.xml' path='//Method[@name="AddAliasBoolean"]/docs/*' />
public void AddAlias (string alias, bool value)
{
booleanAlias[alias] = value;
}
#if (NET_COMPACT_1_0)
#else
/// <include file='AliasText.xml' path='//Method[@name="AddAliasEnum"]/docs/*' />
public void AddAlias (string key, Enum enumAlias)
{
SetAliasTypes (key, enumAlias);
}
#endif
/// <include file='AliasText.xml' path='//Method[@name="ContainsBoolean"]/docs/*' />
public bool ContainsBoolean (string key)
{
return booleanAlias.Contains (key);
}
/// <include file='AliasText.xml' path='//Method[@name="ContainsInt"]/docs/*' />
public bool ContainsInt (string key, string alias)
{
bool result = false;
if (intAlias.Contains (key)) {
Hashtable keys = (Hashtable)intAlias[key];
result = (keys.Contains (alias));
}
return result;
}
/// <include file='AliasText.xml' path='//Method[@name="GetBoolean"]/docs/*' />
public bool GetBoolean (string key)
{
if (!booleanAlias.Contains (key)) {
throw new ArgumentException ("Alias does not exist for text");
}
return (bool)booleanAlias[key];
}
/// <include file='AliasText.xml' path='//Method[@name="GetInt"]/docs/*' />
public int GetInt (string key, string alias)
{
if (!intAlias.Contains (key)) {
throw new ArgumentException ("Alias does not exist for key");
}
Hashtable keys = (Hashtable)intAlias[key];
if (!keys.Contains (alias)) {
throw new ArgumentException ("Config value does not match a " +
"supplied alias");
}
return (int)keys[alias];
}
#endregion
#region Private methods
/// <summary>
/// Loads the default alias values.
/// </summary>
private void DefaultAliasLoad ()
{
AddAlias("true", true);
AddAlias("false", false);
}
#if (NET_COMPACT_1_0)
#else
/// <summary>
/// Extracts and sets the alias types from an enumeration.
/// </summary>
private void SetAliasTypes (string key, Enum enumAlias)
{
string[] names = Enum.GetNames (enumAlias.GetType ());
int[] values = (int[])Enum.GetValues (enumAlias.GetType ());
for (int i = 0; i < names.Length; i++)
{
AddAlias (key, names[i], values[i]);
}
}
#endif
/// <summary>
/// Returns a case insensitive hashtable.
/// </summary>
private Hashtable InsensitiveHashtable ()
{
return new Hashtable (StringComparer.OrdinalIgnoreCase);
}
#endregion
}
}

View File

@@ -0,0 +1,422 @@
#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.Collections;
using System.Globalization;
using Nini.Util;
namespace Nini.Config
{
#region ConfigKeyEventArgs class
/// <include file='ConfigKeyEventArgs.xml' path='//Delegate[@name="ConfigKeyEventHandler"]/docs/*' />
public delegate void ConfigKeyEventHandler (object sender, ConfigKeyEventArgs e);
/// <include file='ConfigEventArgs.xml' path='//Class[@name="ConfigEventArgs"]/docs/*' />
public class ConfigKeyEventArgs : EventArgs
{
string keyName = null;
string keyValue = null;
/// <include file='ConfigEventArgs.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public ConfigKeyEventArgs (string keyName, string keyValue)
{
this.keyName = keyName;
this.keyValue = keyValue;
}
/// <include file='ConfigEventArgs.xml' path='//Property[@name="KeyName"]/docs/*' />
public string KeyName
{
get { return keyName; }
}
/// <include file='ConfigEventArgs.xml' path='//Property[@name="KeyValue"]/docs/*' />
public string KeyValue
{
get { return keyValue; }
}
}
#endregion
/// <include file='IConfig.xml' path='//Interface[@name="IConfig"]/docs/*' />
public class ConfigBase : IConfig
{
#region Private variables
string configName = null;
IConfigSource configSource = null;
AliasText aliasText = null;
IFormatProvider format = NumberFormatInfo.CurrentInfo;
#endregion
#region Protected variables
protected OrderedList keys = new OrderedList ();
#endregion
#region Constructors
/// <include file='ConfigBase.xml' path='//Constructor[@name="ConfigBase"]/docs/*' />
public ConfigBase (string name, IConfigSource source)
{
configName = name;
configSource = source;
aliasText = new AliasText ();
}
#endregion
#region Public properties
/// <include file='IConfig.xml' path='//Property[@name="Name"]/docs/*' />
public string Name
{
get { return configName; }
set {
if (configName != value) {
Rename (value);
}
}
}
/// <include file='IConfig.xml' path='//Property[@name="ConfigSource"]/docs/*' />
public IConfigSource ConfigSource
{
get { return configSource; }
}
/// <include file='IConfig.xml' path='//Property[@name="Alias"]/docs/*' />
public AliasText Alias
{
get { return aliasText; }
}
#endregion
#region Public methods
/// <include file='IConfig.xml' path='//Method[@name="Contains"]/docs/*' />
public bool Contains (string key)
{
return (Get (key) != null);
}
/// <include file='IConfig.xml' path='//Method[@name="Get"]/docs/*' />
public virtual string Get (string key)
{
string result = null;
if (keys.Contains (key)) {
result = keys[key].ToString ();
}
return result;
}
/// <include file='IConfig.xml' path='//Method[@name="GetDefault"]/docs/*' />
public string Get (string key, string defaultValue)
{
string result = Get (key);
return (result == null) ? defaultValue : result;
}
/// <include file='IConfig.xml' path='//Method[@name="GetExpanded"]/docs/*' />
public string GetExpanded (string key)
{
return this.ConfigSource.GetExpanded(this, key);
}
/// <include file='IConfig.xml' path='//Method[@name="Get"]/docs/*' />
public string GetString (string key)
{
return Get (key);
}
/// <include file='IConfig.xml' path='//Method[@name="GetDefault"]/docs/*' />
public string GetString (string key, string defaultValue)
{
return Get (key, defaultValue);
}
/// <include file='IConfig.xml' path='//Method[@name="GetInt"]/docs/*' />
public int GetInt (string key)
{
string text = Get (key);
if (text == null) {
throw new ArgumentException ("Value not found: " + key);
}
return Convert.ToInt32 (text, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetIntAlias"]/docs/*' />
public int GetInt (string key, bool fromAlias)
{
if (!fromAlias) {
return GetInt (key);
}
string result = Get (key);
if (result == null) {
throw new ArgumentException ("Value not found: " + key);
}
return GetIntAlias (key, result);
}
/// <include file='IConfig.xml' path='//Method[@name="GetIntDefault"]/docs/*' />
public int GetInt (string key, int defaultValue)
{
string result = Get (key);
return (result == null)
? defaultValue
: Convert.ToInt32 (result, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetIntDefaultAlias"]/docs/*' />
public int GetInt (string key, int defaultValue, bool fromAlias)
{
if (!fromAlias) {
return GetInt (key, defaultValue);
}
string result = Get (key);
return (result == null) ? defaultValue : GetIntAlias (key, result);
}
/// <include file='IConfig.xml' path='//Method[@name="GetLong"]/docs/*' />
public long GetLong (string key)
{
string text = Get (key);
if (text == null) {
throw new ArgumentException ("Value not found: " + key);
}
return Convert.ToInt64 (text, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetLongDefault"]/docs/*' />
public long GetLong (string key, long defaultValue)
{
string result = Get (key);
return (result == null)
? defaultValue
: Convert.ToInt64 (result, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetBoolean"]/docs/*' />
public bool GetBoolean (string key)
{
string text = Get (key);
if (text == null) {
throw new ArgumentException ("Value not found: " + key);
}
return GetBooleanAlias (text);
}
/// <include file='IConfig.xml' path='//Method[@name="GetBooleanDefault"]/docs/*' />
public bool GetBoolean (string key, bool defaultValue)
{
string text = Get (key);
return (text == null) ? defaultValue : GetBooleanAlias (text);
}
/// <include file='IConfig.xml' path='//Method[@name="GetFloat"]/docs/*' />
public float GetFloat (string key)
{
string text = Get (key);
if (text == null) {
throw new ArgumentException ("Value not found: " + key);
}
return Convert.ToSingle (text, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetFloatDefault"]/docs/*' />
public float GetFloat (string key, float defaultValue)
{
string result = Get (key);
return (result == null)
? defaultValue
: Convert.ToSingle (result, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetDouble"]/docs/*' />
public double GetDouble (string key)
{
string text = Get (key);
if (text == null) {
throw new ArgumentException ("Value not found: " + key);
}
return Convert.ToDouble (text, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetDoubleDefault"]/docs/*' />
public double GetDouble (string key, double defaultValue)
{
string result = Get (key);
return (result == null)
? defaultValue
: Convert.ToDouble (result, format);
}
/// <include file='IConfig.xml' path='//Method[@name="GetKeys"]/docs/*' />
public string[] GetKeys ()
{
string[] result = new string[keys.Keys.Count];
keys.Keys.CopyTo (result, 0);
return result;
}
/// <include file='IConfig.xml' path='//Method[@name="GetValues"]/docs/*' />
public string[] GetValues ()
{
string[] result = new string[keys.Values.Count];
keys.Values.CopyTo (result, 0);
return result;
}
/// <include file='ConfigBase.xml' path='//Method[@name="Add"]/docs/*' />
public void Add (string key, string value)
{
keys.Add (key, value);
}
/// <include file='IConfig.xml' path='//Method[@name="Set"]/docs/*' />
public virtual void Set (string key, object value)
{
if (value == null) {
throw new ArgumentNullException ("Value cannot be null");
}
if (Get (key) == null) {
this.Add (key, value.ToString ());
} else {
keys[key] = value.ToString ();
}
if (ConfigSource.AutoSave) {
ConfigSource.Save ();
}
OnKeySet (new ConfigKeyEventArgs (key, value.ToString ()));
}
/// <include file='IConfig.xml' path='//Method[@name="Remove"]/docs/*' />
public virtual void Remove (string key)
{
if (key == null) {
throw new ArgumentNullException ("Key cannot be null");
}
if (Get (key) != null) {
string keyValue = null;
if (KeySet != null) {
keyValue = Get (key);
}
keys.Remove (key);
OnKeyRemoved (new ConfigKeyEventArgs (key, keyValue));
}
}
#endregion
#region Public events
/// <include file='IConfig.xml' path='//Event[@name="KeySet"]/docs/*' />
public event ConfigKeyEventHandler KeySet;
/// <include file='IConfig.xml' path='//Event[@name="KeyRemoved"]/docs/*' />
public event ConfigKeyEventHandler KeyRemoved;
#endregion
#region Protected methods
/// <include file='ConfigBase.xml' path='//Method[@name="OnKeySet"]/docs/*' />
protected void OnKeySet (ConfigKeyEventArgs e)
{
if (KeySet != null) {
KeySet (this, e);
}
}
/// <include file='ConfigBase.xml' path='//Method[@name="OnKeyRemoved"]/docs/*' />
protected void OnKeyRemoved (ConfigKeyEventArgs e)
{
if (KeyRemoved != null) {
KeyRemoved (this, e);
}
}
#endregion
#region Private methods
/// <summary>
/// Renames the config to the new name.
/// </summary>
private void Rename (string name)
{
this.ConfigSource.Configs.Remove (this);
configName = name;
this.ConfigSource.Configs.Add (this);
}
/// <summary>
/// Returns the integer alias first from this IConfig then
/// the parent if there is none.
/// </summary>
private int GetIntAlias (string key, string alias)
{
int result = -1;
if (aliasText.ContainsInt (key, alias)) {
result = aliasText.GetInt (key, alias);
} else {
result = ConfigSource.Alias.GetInt (key, alias);
}
return result;
}
/// <summary>
/// Returns the boolean alias first from this IConfig then
/// the parent if there is none.
/// </summary>
private bool GetBooleanAlias (string key)
{
bool result = false;
if (aliasText.ContainsBoolean (key)) {
result = aliasText.GetBoolean (key);
} else {
if (ConfigSource.Alias.ContainsBoolean (key)) {
result = ConfigSource.Alias.GetBoolean (key);
} else {
throw new ArgumentException
("Alias value not found: " + key
+ ". Add it to the Alias property.");
}
}
return result;
}
#endregion
}
}

View File

@@ -0,0 +1,264 @@
#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.Collections;
namespace Nini.Config
{
#region ConfigEventHandler class
/// <include file='ConfigEventArgs.xml' path='//Delegate[@name="ConfigEventHandler"]/docs/*' />
public delegate void ConfigEventHandler (object sender, ConfigEventArgs e);
/// <include file='ConfigEventArgs.xml' path='//Class[@name="ConfigEventArgs"]/docs/*' />
public class ConfigEventArgs : EventArgs
{
IConfig config = null;
/// <include file='ConfigEventArgs.xml' path='//Constructor[@name="ConstructorIConfig"]/docs/*' />
public ConfigEventArgs (IConfig config)
{
this.config = config;
}
/// <include file='ConfigEventArgs.xml' path='//Property[@name="Config"]/docs/*' />
public IConfig Config
{
get { return config; }
}
}
#endregion
/// <include file='ConfigCollection.xml' path='//Class[@name="ConfigCollection"]/docs/*' />
public class ConfigCollection : ICollection, IEnumerable, IList
{
#region Private variables
ArrayList configList = new ArrayList ();
ConfigSourceBase owner = null;
#endregion
#region Constructors
/// <include file='ConfigCollection.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public ConfigCollection (ConfigSourceBase owner)
{
this.owner = owner;
}
#endregion
#region Public properties
/// <include file='ConfigCollection.xml' path='//Property[@name="Count"]/docs/*' />
public int Count
{
get { return configList.Count; }
}
/// <include file='ConfigCollection.xml' path='//Property[@name="IsSynchronized"]/docs/*' />
public bool IsSynchronized
{
get { return false; }
}
/// <include file='ConfigCollection.xml' path='//Property[@name="SyncRoot"]/docs/*' />
public object SyncRoot
{
get { return this; }
}
/// <include file='ConfigCollection.xml' path='//Property[@name="ItemIndex"]/docs/*' />
public IConfig this[int index]
{
get { return (IConfig)configList[index]; }
}
/// <include file='ConfigCollection.xml' path='//Property[@name="ItemIndex"]/docs/*' />
object IList.this[int index]
{
get { return configList[index]; }
set { }
}
/// <include file='ConfigCollection.xml' path='//Property[@name="ItemName"]/docs/*' />
public IConfig this[string configName]
{
get
{
IConfig result = null;
foreach (IConfig config in configList)
{
if (config.Name == configName) {
result = config;
break;
}
}
return result;
}
}
/// <include file='ConfigCollection.xml' path='//Property[@name="IsFixedSize"]/docs/*' />
public bool IsFixedSize
{
get { return false; }
}
/// <include file='ConfigCollection.xml' path='//Property[@name="IsReadOnly"]/docs/*' />
public bool IsReadOnly
{
get { return false; }
}
#endregion
#region Public methods
/// <include file='ConfigCollection.xml' path='//Method[@name="Add"]/docs/*' />
public void Add (IConfig config)
{
if (configList.Contains (config)) {
throw new ArgumentException ("IConfig already exists");
}
IConfig existingConfig = this[config.Name];
if (existingConfig != null) {
// Set all new keys
string[] keys = config.GetKeys ();
for (int i = 0; i < keys.Length; i++)
{
existingConfig.Set (keys[i], config.Get (keys[i]));
}
} else {
configList.Add (config);
OnConfigAdded (new ConfigEventArgs (config));
}
}
/// <include file='ConfigCollection.xml' path='//Method[@name="Add"]/docs/*' />
int IList.Add (object config)
{
IConfig newConfig = config as IConfig;
if (newConfig == null) {
throw new Exception ("Must be an IConfig");
} else {
this.Add (newConfig);
return IndexOf (newConfig);
}
}
/// <include file='ConfigCollection.xml' path='//Method[@name="AddName"]/docs/*' />
public IConfig Add (string name)
{
ConfigBase result = null;
if (this[name] == null) {
result = new ConfigBase (name, owner);
configList.Add (result);
OnConfigAdded (new ConfigEventArgs (result));
} else {
throw new ArgumentException ("An IConfig of that name already exists");
}
return result;
}
/// <include file='ConfigCollection.xml' path='//Method[@name="Remove"]/docs/*' />
public void Remove (IConfig config)
{
configList.Remove (config);
OnConfigRemoved (new ConfigEventArgs (config));
}
/// <include file='ConfigCollection.xml' path='//Method[@name="Remove"]/docs/*' />
public void Remove (object config)
{
configList.Remove (config);
OnConfigRemoved (new ConfigEventArgs ((IConfig)config));
}
/// <include file='ConfigCollection.xml' path='//Method[@name="RemoveAt"]/docs/*' />
public void RemoveAt (int index)
{
IConfig config = (IConfig)configList[index];
configList.RemoveAt (index);
OnConfigRemoved (new ConfigEventArgs (config));
}
/// <include file='ConfigCollection.xml' path='//Method[@name="Clear"]/docs/*' />
public void Clear ()
{
configList.Clear ();
}
/// <include file='ConfigCollection.xml' path='//Method[@name="GetEnumerator"]/docs/*' />
public IEnumerator GetEnumerator ()
{
return configList.GetEnumerator ();
}
/// <include file='ConfigCollection.xml' path='//Method[@name="CopyTo"]/docs/*' />
public void CopyTo (Array array, int index)
{
configList.CopyTo (array, index);
}
/// <include file='ConfigCollection.xml' path='//Method[@name="CopyToStrong"]/docs/*' />
public void CopyTo (IConfig[] array, int index)
{
((ICollection)configList).CopyTo (array, index);
}
/// <include file='ConfigCollection.xml' path='//Method[@name="Contains"]/docs/*' />
public bool Contains (object config)
{
return configList.Contains (config);
}
/// <include file='ConfigCollection.xml' path='//Method[@name="IndexOf"]/docs/*' />
public int IndexOf (object config)
{
return configList.IndexOf (config);
}
/// <include file='ConfigCollection.xml' path='//Method[@name="Insert"]/docs/*' />
public void Insert (int index, object config)
{
configList.Insert (index, config);
}
#endregion
#region Public events
/// <include file='ConfigCollection.xml' path='//Event[@name="ConfigAdded"]/docs/*' />
public event ConfigEventHandler ConfigAdded;
/// <include file='ConfigCollection.xml' path='//Event[@name="ConfigRemoved"]/docs/*' />
public event ConfigEventHandler ConfigRemoved;
#endregion
#region Protected methods
/// <include file='ConfigCollection.xml' path='//Method[@name="OnConfigAdded"]/docs/*' />
protected void OnConfigAdded (ConfigEventArgs e)
{
if (ConfigAdded != null) {
ConfigAdded (this, e);
}
}
/// <include file='ConfigCollection.xml' path='//Method[@name="OnConfigRemoved"]/docs/*' />
protected void OnConfigRemoved (ConfigEventArgs e)
{
if (ConfigRemoved != null) {
ConfigRemoved (this, e);
}
}
#endregion
#region Private methods
#endregion
}
}

View File

@@ -0,0 +1,219 @@
#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.Text;
using System.Collections;
namespace Nini.Config
{
/// <include file='IConfigSource.xml' path='//Interface[@name="IConfigSource"]/docs/*' />
public abstract class ConfigSourceBase : IConfigSource
{
#region Private variables
ArrayList sourceList = new ArrayList ();
ConfigCollection configList = null;
bool autoSave = false;
AliasText alias = new AliasText ();
#endregion
#region Constructors
/// <include file='ConfigSourceBase.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public ConfigSourceBase ()
{
configList = new ConfigCollection (this);
}
#endregion
#region Public properties
/// <include file='IConfigSource.xml' path='//Property[@name="Configs"]/docs/*' />
public ConfigCollection Configs
{
get { return configList; }
}
/// <include file='IConfigSource.xml' path='//Property[@name="AutoSave"]/docs/*' />
public bool AutoSave
{
get { return autoSave; }
set { autoSave = value; }
}
/// <include file='IConfigSource.xml' path='//Property[@name="Alias"]/docs/*' />
public AliasText Alias
{
get { return alias; }
}
#endregion
#region Public methods
/// <include file='IConfigSource.xml' path='//Method[@name="Merge"]/docs/*' />
public void Merge (IConfigSource source)
{
if (!sourceList.Contains (source)) {
sourceList.Add (source);
}
foreach (IConfig config in source.Configs)
{
this.Configs.Add (config);
}
}
/// <include file='IConfigSource.xml' path='//Method[@name="AddConfig"]/docs/*' />
public virtual IConfig AddConfig (string name)
{
return configList.Add (name);
}
/// <include file='IConfigSource.xml' path='//Method[@name="GetExpanded"]/docs/*' />
public string GetExpanded (IConfig config, string key)
{
return Expand (config, key, false);
}
/// <include file='IConfigSource.xml' path='//Method[@name="Save"]/docs/*' />
public virtual void Save ()
{
OnSaved (new EventArgs ());
}
/// <include file='IConfigSource.xml' path='//Method[@name="Reload"]/docs/*' />
public virtual void Reload ()
{
OnReloaded (new EventArgs ());
}
/// <include file='IConfigSource.xml' path='//Method[@name="ExpandKeyValues"]/docs/*' />
public void ExpandKeyValues ()
{
string[] keys = null;
foreach (IConfig config in configList)
{
keys = config.GetKeys ();
for (int i = 0; i < keys.Length; i++)
{
Expand (config, keys[i], true);
}
}
}
/// <include file='IConfigSource.xml' path='//Method[@name="ReplaceKeyValues"]/docs/*' />
public void ReplaceKeyValues ()
{
ExpandKeyValues ();
}
#endregion
#region Public events
/// <include file='IConfigSource.xml' path='//Event[@name="Reloaded"]/docs/*' />
public event EventHandler Reloaded;
/// <include file='IConfigSource.xml' path='//Event[@name="Saved"]/docs/*' />
public event EventHandler Saved;
#endregion
#region Protected methods
/// <include file='ConfigSourceBase.xml' path='//Method[@name="OnReloaded"]/docs/*' />
protected void OnReloaded (EventArgs e)
{
if (Reloaded != null) {
Reloaded (this, e);
}
}
/// <include file='ConfigSourceBase.xml' path='//Method[@name="OnSaved"]/docs/*' />
protected void OnSaved (EventArgs e)
{
if (Saved != null) {
Saved (this, e);
}
}
#endregion
#region Private methods
/// <summary>
/// Expands key values from the given IConfig.
/// </summary>
private string Expand (IConfig config, string key, bool setValue)
{
string result = config.Get (key);
if (result == null) {
throw new ArgumentException (String.Format ("[{0}] not found in [{1}]",
key, config.Name));
}
while (true)
{
int startIndex = result.IndexOf ("${", 0);
if (startIndex == -1) {
break;
}
int endIndex = result.IndexOf ("}", startIndex + 2);
if (endIndex == -1) {
break;
}
string search = result.Substring (startIndex + 2,
endIndex - (startIndex + 2));
if (search == key) {
// Prevent infinite recursion
throw new ArgumentException
("Key cannot have a expand value of itself: " + key);
}
string replace = ExpandValue (config, search);
result = result.Replace("${" + search + "}", replace);
}
if (setValue) {
config.Set(key, result);
}
return result;
}
/// <summary>
/// Returns the replacement value of a config.
/// </summary>
private string ExpandValue (IConfig config, string search)
{
string result = null;
string[] replaces = search.Split ('|');
if (replaces.Length > 1) {
IConfig newConfig = this.Configs[replaces[0]];
if (newConfig == null) {
throw new ArgumentException ("Expand config not found: "
+ replaces[0]);
}
result = newConfig.Get (replaces[1]);
if (result == null) {
throw new ArgumentException ("Expand key not found: "
+ replaces[1]);
}
} else {
result = config.Get (search);
if (result == null) {
throw new ArgumentException ("Key not found: " + search);
}
}
return result;
}
#endregion
}
}

View File

@@ -0,0 +1,99 @@
#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;
namespace Nini.Config
{
/// <include file='IConfig.xml' path='//Interface[@name="IConfig"]/docs/*' />
public interface IConfig
{
/// <include file='IConfig.xml' path='//Property[@name="ConfigSource"]/docs/*' />
IConfigSource ConfigSource { get; }
/// <include file='IConfig.xml' path='//Property[@name="Name"]/docs/*' />
string Name { get; set; }
/// <include file='IConfig.xml' path='//Property[@name="Alias"]/docs/*' />
AliasText Alias { get; }
/// <include file='IConfig.xml' path='//Method[@name="Contains"]/docs/*' />
bool Contains (string key);
/// <include file='IConfig.xml' path='//Method[@name="Get"]/docs/*' />
string Get (string key);
/// <include file='IConfig.xml' path='//Method[@name="GetDefault"]/docs/*' />
string Get (string key, string defaultValue);
/// <include file='IConfig.xml' path='//Method[@name="GetExpanded"]/docs/*' />
string GetExpanded (string key);
/// <include file='IConfig.xml' path='//Method[@name="Get"]/docs/*' />
string GetString (string key);
/// <include file='IConfig.xml' path='//Method[@name="GetDefault"]/docs/*' />
string GetString (string key, string defaultValue);
/// <include file='IConfig.xml' path='//Method[@name="GetInt"]/docs/*' />
int GetInt (string key);
/// <include file='IConfig.xml' path='//Method[@name="GetIntAlias"]/docs/*' />
int GetInt (string key, bool fromAlias);
/// <include file='IConfig.xml' path='//Method[@name="GetIntDefault"]/docs/*' />
int GetInt (string key, int defaultValue);
/// <include file='IConfig.xml' path='//Method[@name="GetIntDefaultAlias"]/docs/*' />
int GetInt (string key, int defaultValue, bool fromAlias);
/// <include file='IConfig.xml' path='//Method[@name="GetLong"]/docs/*' />
long GetLong (string key);
/// <include file='IConfig.xml' path='//Method[@name="GetLongDefault"]/docs/*' />
long GetLong (string key, long defaultValue);
/// <include file='IConfig.xml' path='//Method[@name="GetBoolean"]/docs/*' />
bool GetBoolean (string key);
/// <include file='IConfig.xml' path='//Method[@name="GetBooleanDefault"]/docs/*' />
bool GetBoolean (string key, bool defaultValue);
/// <include file='IConfig.xml' path='//Method[@name="GetFloat"]/docs/*' />
float GetFloat (string key);
/// <include file='IConfig.xml' path='//Method[@name="GetFloatDefault"]/docs/*' />
float GetFloat (string key, float defaultValue);
/// <include file='IConfig.xml' path='//Method[@name="GetDouble"]/docs/*' />
double GetDouble (string key);
/// <include file='IConfig.xml' path='//Method[@name="GetDoubleDefault"]/docs/*' />
double GetDouble (string key, double defaultValue);
/// <include file='IConfig.xml' path='//Method[@name="GetKeys"]/docs/*' />
string[] GetKeys ();
/// <include file='IConfig.xml' path='//Method[@name="GetValues"]/docs/*' />
string[] GetValues ();
/// <include file='IConfig.xml' path='//Method[@name="Set"]/docs/*' />
void Set (string key, object value);
/// <include file='IConfig.xml' path='//Method[@name="Remove"]/docs/*' />
void Remove (string key);
/// <include file='IConfig.xml' path='//Event[@name="KeySet"]/docs/*' />
event ConfigKeyEventHandler KeySet;
/// <include file='IConfig.xml' path='//Event[@name="KeyRemoved"]/docs/*' />
event ConfigKeyEventHandler KeyRemoved;
}
}

View File

@@ -0,0 +1,55 @@
#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;
namespace Nini.Config
{
/// <include file='IConfigSource.xml' path='//Interface[@name="IConfigSource"]/docs/*' />
public interface IConfigSource
{
/// <include file='IConfigSource.xml' path='//Property[@name="Configs"]/docs/*' />
ConfigCollection Configs { get; }
/// <include file='IConfigSource.xml' path='//Property[@name="AutoSave"]/docs/*' />
bool AutoSave { get; set; }
/// <include file='IConfigSource.xml' path='//Property[@name="Alias"]/docs/*' />
AliasText Alias { get; }
/// <include file='IConfigSource.xml' path='//Method[@name="Merge"]/docs/*' />
void Merge (IConfigSource source);
/// <include file='IConfigSource.xml' path='//Method[@name="Save"]/docs/*' />
void Save ();
/// <include file='IConfigSource.xml' path='//Method[@name="Reload"]/docs/*' />
void Reload ();
/// <include file='IConfigSource.xml' path='//Method[@name="AddConfig"]/docs/*' />
IConfig AddConfig (string name);
/// <include file='IConfigSource.xml' path='//Method[@name="GetExpanded"]/docs/*' />
string GetExpanded (IConfig config, string key);
/// <include file='IConfigSource.xml' path='//Method[@name="ExpandKeyValues"]/docs/*' />
void ExpandKeyValues ();
/// <include file='IConfigSource.xml' path='//Method[@name="ReplaceKeyValues"]/docs/*' />
void ReplaceKeyValues ();
/// <include file='IConfigSource.xml' path='//Event[@name="Reloaded"]/docs/*' />
event EventHandler Reloaded;
/// <include file='IConfigSource.xml' path='//Event[@name="Saved"]/docs/*' />
event EventHandler Saved;
}
}

View File

@@ -0,0 +1,90 @@
#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.Collections;
using System.Globalization;
using Nini.Util;
namespace Nini.Config
{
/// <include file='IniConfig.xml' path='//Class[@name="IniConfig"]/docs/*' />
public class IniConfig : ConfigBase
{
#region Private variables
IniConfigSource parent = null;
#endregion
#region Constructors
/// <include file='IniConfig.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public IniConfig (string name, IConfigSource source)
: base(name, source)
{
parent = (IniConfigSource)source;
}
#endregion
#region Public properties
#endregion
#region Public methods
/// <include file='IniConfig.xml' path='//Method[@name="Get"]/docs/*' />
public override string Get (string key)
{
if (!parent.CaseSensitive) {
key = CaseInsensitiveKeyName (key);
}
return base.Get (key);
}
/// <include file='IniConfig.xml' path='//Method[@name="Set"]/docs/*' />
public override void Set (string key, object value)
{
if (!parent.CaseSensitive) {
key = CaseInsensitiveKeyName (key);
}
base.Set (key, value);
}
/// <include file='IniConfig.xml' path='//Method[@name="Remove"]/docs/*' />
public override void Remove (string key)
{
if (!parent.CaseSensitive) {
key = CaseInsensitiveKeyName (key);
}
base.Remove (key);
}
#endregion
#region Private methods
/// <summary>
/// Returns the key name if the case insensitivity is turned on.
/// </summary>
private string CaseInsensitiveKeyName (string key)
{
string result = null;
string lowerKey = key.ToLower ();
foreach (string currentKey in keys.Keys)
{
if (currentKey.ToLower () == lowerKey) {
result = currentKey;
break;
}
}
return (result == null) ? key : result;
}
#endregion
}
}

View File

@@ -0,0 +1,329 @@
#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 Nini.Ini;
namespace Nini.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
}
}

View File

@@ -0,0 +1,302 @@
#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 Nini.Util;
namespace Nini.Ini
{
#region IniFileType enumeration
/// <include file='IniDocument.xml' path='//Enum[@name="IniFileType"]/docs/*' />
public enum IniFileType
{
/// <include file='IniDocument.xml' path='//Enum[@name="IniFileType"]/Value[@name="Standard"]/docs/*' />
Standard,
/// <include file='IniDocument.xml' path='//Enum[@name="IniFileType"]/Value[@name="PythonStyle"]/docs/*' />
PythonStyle,
/// <include file='IniDocument.xml' path='//Enum[@name="IniFileType"]/Value[@name="SambaStyle"]/docs/*' />
SambaStyle,
/// <include file='IniDocument.xml' path='//Enum[@name="IniFileType"]/Value[@name="MysqlStyle"]/docs/*' />
MysqlStyle,
/// <include file='IniDocument.xml' path='//Enum[@name="IniFileType"]/Value[@name="WindowsStyle"]/docs/*' />
WindowsStyle
}
#endregion
/// <include file='IniDocument.xml' path='//Class[@name="IniDocument"]/docs/*' />
public class IniDocument
{
#region Private variables
IniSectionCollection sections = new IniSectionCollection ();
ArrayList initialComment = new ArrayList ();
IniFileType fileType = IniFileType.Standard;
#endregion
#region Public properties
/// <include file='IniDocument.xml' path='//Property[@name="FileType"]/docs/*' />
public IniFileType FileType
{
get { return fileType; }
set { fileType = value; }
}
#endregion
#region Constructors
/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorPath"]/docs/*' />
public IniDocument (string filePath)
{
fileType = IniFileType.Standard;
Load (filePath);
}
/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorPathType"]/docs/*' />
public IniDocument (string filePath, IniFileType type)
{
fileType = type;
Load (filePath);
}
/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorTextReader"]/docs/*' />
public IniDocument (TextReader reader)
{
fileType = IniFileType.Standard;
Load (reader);
}
/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorTextReaderType"]/docs/*' />
public IniDocument (TextReader reader, IniFileType type)
{
fileType = type;
Load (reader);
}
/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorStream"]/docs/*' />
public IniDocument (Stream stream)
{
fileType = IniFileType.Standard;
Load (stream);
}
/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorStreamType"]/docs/*' />
public IniDocument (Stream stream, IniFileType type)
{
fileType = type;
Load (stream);
}
/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorIniReader"]/docs/*' />
public IniDocument (IniReader reader)
{
fileType = IniFileType.Standard;
Load (reader);
}
/// <include file='IniDocument.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public IniDocument ()
{
}
#endregion
#region Public methods
/// <include file='IniDocument.xml' path='//Method[@name="LoadPath"]/docs/*' />
public void Load (string filePath)
{
Load (new StreamReader (filePath));
}
/// <include file='IniDocument.xml' path='//Method[@name="LoadTextReader"]/docs/*' />
public void Load (TextReader reader)
{
Load (GetIniReader (reader, fileType));
}
/// <include file='IniDocument.xml' path='//Method[@name="LoadStream"]/docs/*' />
public void Load (Stream stream)
{
Load (new StreamReader (stream));
}
/// <include file='IniDocument.xml' path='//Method[@name="LoadIniReader"]/docs/*' />
public void Load (IniReader reader)
{
LoadReader (reader);
}
/// <include file='IniSection.xml' path='//Property[@name="Comment"]/docs/*' />
public IniSectionCollection Sections
{
get { return sections; }
}
/// <include file='IniDocument.xml' path='//Method[@name="SaveTextWriter"]/docs/*' />
public void Save (TextWriter textWriter)
{
IniWriter writer = GetIniWriter (textWriter, fileType);
IniItem item = null;
IniSection section = null;
foreach (string comment in initialComment)
{
writer.WriteEmpty (comment);
}
for (int j = 0; j < sections.Count; j++)
{
section = sections[j];
writer.WriteSection (section.Name, section.Comment);
for (int i = 0; i < section.ItemCount; i++)
{
item = section.GetItem (i);
switch (item.Type)
{
case IniType.Key:
writer.WriteKey (item.Name, item.Value, item.Comment);
break;
case IniType.Empty:
writer.WriteEmpty (item.Comment);
break;
}
}
}
writer.Close ();
}
/// <include file='IniDocument.xml' path='//Method[@name="SavePath"]/docs/*' />
public void Save (string filePath)
{
StreamWriter writer = new StreamWriter (filePath);
Save (writer);
writer.Close ();
}
/// <include file='IniDocument.xml' path='//Method[@name="SaveStream"]/docs/*' />
public void Save (Stream stream)
{
Save (new StreamWriter (stream));
}
#endregion
#region Private methods
/// <summary>
/// Loads the file not saving comments.
/// </summary>
private void LoadReader (IniReader reader)
{
reader.IgnoreComments = false;
bool sectionFound = false;
IniSection section = null;
try {
while (reader.Read ())
{
switch (reader.Type)
{
case IniType.Empty:
if (!sectionFound) {
initialComment.Add (reader.Comment);
} else {
section.Set (reader.Comment);
}
break;
case IniType.Section:
sectionFound = true;
// If section already exists then overwrite it
if (sections[reader.Name] != null) {
sections.Remove (reader.Name);
}
section = new IniSection (reader.Name, reader.Comment);
sections.Add (section);
break;
case IniType.Key:
if (section.GetValue (reader.Name) == null) {
section.Set (reader.Name, reader.Value, reader.Comment);
}
break;
}
}
} catch (Exception ex) {
throw ex;
} finally {
// Always close the file
reader.Close ();
}
}
/// <summary>
/// Returns a proper INI reader depending upon the type parameter.
/// </summary>
private IniReader GetIniReader (TextReader reader, IniFileType type)
{
IniReader result = new IniReader (reader);
switch (type)
{
case IniFileType.Standard:
// do nothing
break;
case IniFileType.PythonStyle:
result.AcceptCommentAfterKey = false;
result.SetCommentDelimiters (new char[] { ';', '#' });
result.SetAssignDelimiters (new char[] { ':' });
break;
case IniFileType.SambaStyle:
result.AcceptCommentAfterKey = false;
result.SetCommentDelimiters (new char[] { ';', '#' });
result.LineContinuation = true;
break;
case IniFileType.MysqlStyle:
result.AcceptCommentAfterKey = false;
result.AcceptNoAssignmentOperator = true;
result.SetCommentDelimiters (new char[] { '#' });
result.SetAssignDelimiters (new char[] { ':', '=' });
break;
case IniFileType.WindowsStyle:
result.ConsumeAllKeyText = true;
break;
}
return result;
}
/// <summary>
/// Returns a proper IniWriter depending upon the type parameter.
/// </summary>
private IniWriter GetIniWriter (TextWriter reader, IniFileType type)
{
IniWriter result = new IniWriter (reader);
switch (type)
{
case IniFileType.Standard:
case IniFileType.WindowsStyle:
// do nothing
break;
case IniFileType.PythonStyle:
result.AssignDelimiter = ':';
result.CommentDelimiter = '#';
break;
case IniFileType.SambaStyle:
case IniFileType.MysqlStyle:
result.AssignDelimiter = '=';
result.CommentDelimiter = '#';
break;
}
return result;
}
#endregion
}
}

View File

@@ -0,0 +1,121 @@
#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.Security;
using System.Globalization;
using System.Security.Permissions;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace Nini.Ini
{
/// <include file='IniException.xml' path='//Class[@name="IniException"]/docs/*' />
#if (NET_COMPACT_1_0)
#else
[Serializable]
#endif
public class IniException : SystemException /*, ISerializable */
{
#region Private variables
IniReader iniReader = null;
string message = "";
#endregion
#region Public properties
/// <include file='IniException.xml' path='//Property[@name="LinePosition"]/docs/*' />
public int LinePosition
{
get {
return (iniReader == null) ? 0 : iniReader.LinePosition;
}
}
/// <include file='IniException.xml' path='//Property[@name="LineNumber"]/docs/*' />
public int LineNumber
{
get {
return (iniReader == null) ? 0 : iniReader.LineNumber;
}
}
/// <include file='IniException.xml' path='//Property[@name="Message"]/docs/*' />
public override string Message
{
get {
if (iniReader == null) {
return base.Message;
}
return String.Format (CultureInfo.InvariantCulture, "{0} - Line: {1}, Position: {2}.",
message, this.LineNumber, this.LinePosition);
}
}
#endregion
#region Constructors
/// <include file='IniException.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public IniException ()
: base ()
{
this.message = "An error has occurred";
}
/// <include file='IniException.xml' path='//Constructor[@name="ConstructorException"]/docs/*' />
public IniException (string message, Exception exception)
: base (message, exception)
{
}
/// <include file='IniException.xml' path='//Constructor[@name="ConstructorMessage"]/docs/*' />
public IniException (string message)
: base (message)
{
this.message = message;
}
/// <include file='IniException.xml' path='//Constructor[@name="ConstructorTextReader"]/docs/*' />
internal IniException (IniReader reader, string message)
: this (message)
{
iniReader = reader;
this.message = message;
}
#if (NET_COMPACT_1_0)
#else
/// <include file='IniException.xml' path='//Constructor[@name="ConstructorSerialize"]/docs/*' />
protected IniException (SerializationInfo info, StreamingContext context)
: base (info, context)
{
}
#endif
#endregion
#region Public methods
#if (NET_COMPACT_1_0)
#else
/// <include file='IniException.xml' path='//Method[@name="GetObjectData"]/docs/*' />
[SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter=true)]
public override void GetObjectData (SerializationInfo info,
StreamingContext context)
{
base.GetObjectData (info, context);
if (iniReader != null) {
info.AddValue ("lineNumber", iniReader.LineNumber);
info.AddValue ("linePosition", iniReader.LinePosition);
}
}
#endif
#endregion
}
}

View File

@@ -0,0 +1,54 @@
using System;
namespace Nini.Ini
{
/// <include file='IniItem.xml' path='//Class[@name="IniItem"]/docs/*' />
public class IniItem
{
#region Private variables
IniType iniType = IniType.Empty;
string iniName = "";
string iniValue = "";
string iniComment = null;
#endregion
#region Public properties
/// <include file='IniItem.xml' path='//Property[@name="Type"]/docs/*' />
public IniType Type
{
get { return iniType; }
set { iniType = value; }
}
/// <include file='IniItem.xml' path='//Property[@name="Value"]/docs/*' />
public string Value
{
get { return iniValue; }
set { iniValue = value; }
}
/// <include file='IniItem.xml' path='//Property[@name="Name"]/docs/*' />
public string Name
{
get { return iniName; }
}
/// <include file='IniItem.xml' path='//Property[@name="Comment"]/docs/*' />
public string Comment
{
get { return iniComment; }
set { iniComment = value; }
}
#endregion
/// <include file='IniItem.xml' path='//Constructor[@name="Constructor"]/docs/*' />
internal protected IniItem (string name, string value, IniType type, string comment)
{
iniName = name;
iniValue = value;
iniType = type;
iniComment = comment;
}
}
}

View File

@@ -0,0 +1,652 @@
#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.Text;
using System.Collections;
namespace Nini.Ini
{
#region IniReadState enumeration
/// <include file='IniReader.xml' path='//Enum[@name="IniReadState"]/docs/*' />
public enum IniReadState : int
{
/// <include file='IniReader.xml' path='//Enum[@name="IniReadState"]/Value[@name="Closed"]/docs/*' />
Closed,
/// <include file='IniReader.xml' path='//Enum[@name="IniReadState"]/Value[@name="EndOfFile"]/docs/*' />
EndOfFile,
/// <include file='IniReader.xml' path='//Enum[@name="IniReadState"]/Value[@name="Error"]/docs/*' />
Error,
/// <include file='IniReader.xml' path='//Enum[@name="IniReadState"]/Value[@name="Initial"]/docs/*' />
Initial,
/// <include file='IniReader.xml' path='//Enum[@name="IniReadState"]/Value[@name="Interactive"]/docs/*' />
Interactive
};
#endregion
#region IniType enumeration
/// <include file='IniReader.xml' path='//Enum[@name="IniType"]/docs/*' />
public enum IniType : int
{
/// <include file='IniReader.xml' path='//Enum[@name="IniType"]/Value[@name="Section"]/docs/*' />
Section,
/// <include file='IniReader.xml' path='//Enum[@name="IniType"]/Value[@name="Key"]/docs/*' />
Key,
/// <include file='IniReader.xml' path='//Enum[@name="IniType"]/Value[@name="Empty"]/docs/*' />
Empty
}
#endregion
/// <include file='IniReader.xml' path='//Class[@name="IniReader"]/docs/*' />
public class IniReader : IDisposable
{
#region Private variables
int lineNumber = 1;
int column = 1;
IniType iniType = IniType.Empty;
TextReader textReader = null;
bool ignoreComments = false;
StringBuilder name = new StringBuilder ();
StringBuilder value = new StringBuilder ();
StringBuilder comment = new StringBuilder ();
IniReadState readState = IniReadState.Initial;
bool hasComment = false;
bool disposed = false;
bool lineContinuation = false;
bool acceptCommentAfterKey = true;
bool acceptNoAssignmentOperator = false;
bool consumeAllKeyText = false;
char[] commentDelimiters = new char[] { ';' };
char[] assignDelimiters = new char[] { '=' };
#endregion
#region Public properties
/// <include file='IniReader.xml' path='//Property[@name="Name"]/docs/*' />
public string Name
{
get { return this.name.ToString (); }
}
/// <include file='IniReader.xml' path='//Property[@name="Value"]/docs/*' />
public string Value
{
get { return this.value.ToString (); }
}
/// <include file='IniReader.xml' path='//Property[@name="Type"]/docs/*' />
public IniType Type
{
get { return iniType; }
}
/// <include file='IniReader.xml' path='//Property[@name="Comment"]/docs/*' />
public string Comment
{
get { return (hasComment) ? this.comment.ToString () : null; }
}
/// <include file='IniReader.xml' path='//Property[@name="LineNumber"]/docs/*' />
public int LineNumber
{
get { return lineNumber; }
}
/// <include file='IniReader.xml' path='//Property[@name="LinePosition"]/docs/*' />
public int LinePosition
{
get { return column; }
}
/// <include file='IniReader.xml' path='//Property[@name="IgnoreComments"]/docs/*' />
public bool IgnoreComments
{
get { return ignoreComments; }
set { ignoreComments = value; }
}
/// <include file='IniReader.xml' path='//Property[@name="ReadState"]/docs/*' />
public IniReadState ReadState
{
get { return readState; }
}
/// <include file='IniReader.xml' path='//Property[@name="LineContinuation"]/docs/*' />
public bool LineContinuation
{
get { return lineContinuation; }
set { lineContinuation = value; }
}
/// <include file='IniReader.xml' path='//Property[@name="AcceptCommentAfterKey"]/docs/*' />
public bool AcceptCommentAfterKey
{
get { return acceptCommentAfterKey; }
set { acceptCommentAfterKey = value; }
}
/// <include file='IniReader.xml' path='//Property[@name="AcceptNoAssignmentOperator"]/docs/*' />
public bool AcceptNoAssignmentOperator
{
get { return acceptNoAssignmentOperator; }
set { acceptNoAssignmentOperator = value; }
}
/// <include file='IniReader.xml' path='//Property[@name="ConsumeAllKeyText"]/docs/*' />
public bool ConsumeAllKeyText
{
get { return consumeAllKeyText; }
set { consumeAllKeyText = value; }
}
#endregion
#region Constructors
/// <include file='IniReader.xml' path='//Constructor[@name="ConstructorPath"]/docs/*' />
public IniReader (string filePath)
{
textReader = new StreamReader (filePath);
}
/// <include file='IniReader.xml' path='//Constructor[@name="ConstructorTextReader"]/docs/*' />
public IniReader (TextReader reader)
{
textReader = reader;
}
/// <include file='IniReader.xml' path='//Constructor[@name="ConstructorStream"]/docs/*' />
public IniReader (Stream stream)
: this (new StreamReader (stream))
{
}
#endregion
#region Public methods
/// <include file='IniReader.xml' path='//Method[@name="Read"]/docs/*' />
public bool Read ()
{
bool result = false;
if (readState != IniReadState.EndOfFile
|| readState != IniReadState.Closed) {
readState = IniReadState.Interactive;
result = ReadNext ();
}
return result;
}
/// <include file='IniReader.xml' path='//Method[@name="MoveToNextSection"]/docs/*' />
public bool MoveToNextSection ()
{
bool result = false;
while (true)
{
result = Read ();
if (iniType == IniType.Section || !result) {
break;
}
}
return result;
}
/// <include file='IniReader.xml' path='//Method[@name="MoveToNextKey"]/docs/*' />
public bool MoveToNextKey ()
{
bool result = false;
while (true)
{
result = Read ();
if (iniType == IniType.Section) {
result = false;
break;
}
if (iniType == IniType.Key || !result) {
break;
}
}
return result;
}
/// <include file='IniReader.xml' path='//Method[@name="Close"]/docs/*' />
public void Close ()
{
Reset ();
readState = IniReadState.Closed;
if (textReader != null) {
textReader.Close ();
}
}
/// <include file='IniReader.xml' path='//Method[@name="Dispose"]/docs/*' />
public void Dispose ()
{
Dispose (true);
}
/// <include file='IniReader.xml' path='//Method[@name="GetCommentDelimiters"]/docs/*' />
public char[] GetCommentDelimiters ()
{
char[] result = new char[commentDelimiters.Length];
Array.Copy (commentDelimiters, 0, result, 0, commentDelimiters.Length);
return result;
}
/// <include file='IniReader.xml' path='//Method[@name="SetCommentDelimiters"]/docs/*' />
public void SetCommentDelimiters (char[] delimiters)
{
if (delimiters.Length < 1) {
throw new ArgumentException ("Must supply at least one delimiter");
}
commentDelimiters = delimiters;
}
/// <include file='IniReader.xml' path='//Method[@name="GetAssignDelimiters"]/docs/*' />
public char[] GetAssignDelimiters ()
{
char[] result = new char[assignDelimiters.Length];
Array.Copy (assignDelimiters, 0, result, 0, assignDelimiters.Length);
return result;
}
/// <include file='IniReader.xml' path='//Method[@name="SetAssignDelimiters"]/docs/*' />
public void SetAssignDelimiters (char[] delimiters)
{
if (delimiters.Length < 1) {
throw new ArgumentException ("Must supply at least one delimiter");
}
assignDelimiters = delimiters;
}
#endregion
#region Protected methods
/// <include file='IniReader.xml' path='//Method[@name="DisposeBoolean"]/docs/*' />
protected virtual void Dispose (bool disposing)
{
if (!disposed) {
textReader.Close ();
disposed = true;
if (disposing) {
GC.SuppressFinalize (this);
}
}
}
#endregion
#region Private methods
/// <summary>
/// Destructor.
/// </summary>
~IniReader ()
{
Dispose (false);
}
/// <summary>
/// Resets all of the current INI line data.
/// </summary>
private void Reset ()
{
this.name.Remove (0, this.name.Length);
this.value.Remove (0, this.value.Length);
this.comment.Remove (0, this.comment.Length);
iniType = IniType.Empty;
hasComment = false;
}
/// <summary>
/// Reads the next INI line item.
/// </summary>
private bool ReadNext ()
{
bool result = true;
int ch = PeekChar ();
Reset ();
if (IsComment (ch)) {
iniType = IniType.Empty;
ReadChar (); // consume comment character
ReadComment ();
return result;
}
switch (ch)
{
case ' ':
case '\t':
case '\r':
SkipWhitespace ();
ReadNext ();
break;
case '\n':
ReadChar ();
break;
case '[':
ReadSection ();
break;
case -1:
readState = IniReadState.EndOfFile;
result = false;
break;
default:
ReadKey ();
break;
}
return result;
}
/// <summary>
/// Reads a comment. Must start after the comment delimiter.
/// </summary>
private void ReadComment ()
{
int ch = -1;
SkipWhitespace ();
hasComment = true;
do
{
ch = ReadChar ();
this.comment.Append ((char)ch);
} while (!EndOfLine (ch));
RemoveTrailingWhitespace (this.comment);
}
/// <summary>
/// Removes trailing whitespace from a StringBuilder.
/// </summary>
private void RemoveTrailingWhitespace (StringBuilder builder)
{
string temp = builder.ToString ();
builder.Remove (0, builder.Length);
builder.Append (temp.TrimEnd (null));
}
/// <summary>
/// Reads a key.
/// </summary>
private void ReadKey ()
{
int ch = -1;
iniType = IniType.Key;
while (true)
{
ch = PeekChar ();
if (IsAssign (ch)) {
ReadChar ();
break;
}
if (EndOfLine (ch)) {
if (acceptNoAssignmentOperator) {
break;
}
throw new IniException (this,
String.Format ("Expected assignment operator ({0})",
assignDelimiters[0]));
}
this.name.Append ((char)ReadChar ());
}
ReadKeyValue ();
SearchForComment ();
RemoveTrailingWhitespace (this.name);
}
/// <summary>
/// Reads the value of a key.
/// </summary>
private void ReadKeyValue ()
{
int ch = -1;
bool foundQuote = false;
int characters = 0;
SkipWhitespace ();
while (true)
{
ch = PeekChar ();
if (!IsWhitespace (ch)) {
characters++;
}
if (!this.ConsumeAllKeyText && ch == '"') {
ReadChar ();
if (!foundQuote && characters == 1) {
foundQuote = true;
continue;
} else {
break;
}
}
if (foundQuote && EndOfLine (ch)) {
throw new IniException (this, "Expected closing quote (\")");
}
// Handle line continuation
if (lineContinuation && ch == '\\')
{
StringBuilder buffer = new StringBuilder ();
buffer.Append ((char)ReadChar ()); // append '\'
while (PeekChar () != '\n' && IsWhitespace (PeekChar ()))
{
if (PeekChar () != '\r') {
buffer.Append ((char)ReadChar ());
} else {
ReadChar (); // consume '\r'
}
}
if (PeekChar () == '\n') {
// continue reading key value on next line
ReadChar ();
continue;
} else {
// Replace consumed characters
this.value.Append (buffer.ToString ());
}
}
if (!this.ConsumeAllKeyText) {
// If accepting comments then don't consume as key value
if (acceptCommentAfterKey && IsComment (ch) && !foundQuote) {
break;
}
}
// Always break at end of line
if (EndOfLine (ch)) {
break;
}
this.value.Append ((char)ReadChar ());
}
if (!foundQuote) {
RemoveTrailingWhitespace (this.value);
}
}
/// <summary>
/// Reads an INI section.
/// </summary>
private void ReadSection ()
{
int ch = -1;
iniType = IniType.Section;
ch = ReadChar (); // consume "["
while (true)
{
ch = PeekChar ();
if (ch == ']') {
break;
}
if (EndOfLine (ch)) {
throw new IniException (this, "Expected section end (])");
}
this.name.Append ((char)ReadChar ());
}
ConsumeToEnd (); // all after '[' is garbage
RemoveTrailingWhitespace (this.name);
}
/// <summary>
/// Looks for a comment.
/// </summary>
private void SearchForComment ()
{
int ch = ReadChar ();
while (!EndOfLine (ch))
{
if (IsComment (ch)) {
if (ignoreComments) {
ConsumeToEnd ();
} else {
ReadComment ();
}
break;
}
ch = ReadChar ();
}
}
/// <summary>
/// Consumes all data until the end of a line.
/// </summary>
private void ConsumeToEnd ()
{
int ch = -1;
do
{
ch = ReadChar ();
} while (!EndOfLine (ch));
}
/// <summary>
/// Returns and consumes the next character from the stream.
/// </summary>
private int ReadChar ()
{
int result = textReader.Read ();
if (result == '\n') {
lineNumber++;
column = 1;
} else {
column++;
}
return result;
}
/// <summary>
/// Returns the next upcoming character from the stream.
/// </summary>
private int PeekChar ()
{
return textReader.Peek ();
}
/// <summary>
/// Returns true if a comment character is found.
/// </summary>
private bool IsComment (int ch)
{
return HasCharacter (commentDelimiters, ch);
}
/// <summary>
/// Returns true if character is an assign character.
/// </summary>
private bool IsAssign (int ch)
{
return HasCharacter (assignDelimiters, ch);
}
/// <summary>
/// Returns true if the character is found in the given array.
/// </summary>
private bool HasCharacter (char[] characters, int ch)
{
bool result = false;
for (int i = 0; i < characters.Length; i++)
{
if (ch == characters[i])
{
result = true;
break;
}
}
return result;
}
/// <summary>
/// Returns true if a value is whitespace.
/// </summary>
private bool IsWhitespace (int ch)
{
return ch == 0x20 || ch == 0x9 || ch == 0xD || ch == 0xA;
}
/// <summary>
/// Skips all whitespace.
/// </summary>
private void SkipWhitespace ()
{
while (IsWhitespace (PeekChar ()))
{
if (EndOfLine (PeekChar ())) {
break;
}
ReadChar ();
}
}
/// <summary>
/// Returns true if an end of line is found. End of line
/// includes both an end of line or end of file.
/// </summary>
private bool EndOfLine (int ch)
{
return (ch == '\n' || ch == -1);
}
#endregion
}
}

View File

@@ -0,0 +1,155 @@
#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.Collections;
using Nini.Util;
namespace Nini.Ini
{
/// <include file='IniSection.xml' path='//Class[@name="IniSection"]/docs/*' />
public class IniSection
{
#region Private variables
OrderedList configList = new OrderedList ();
string name = "";
string comment = null;
int commentCount = 0;
#endregion
#region Constructors
/// <include file='IniSection.xml' path='//Constructor[@name="ConstructorComment"]/docs/*' />
public IniSection (string name, string comment)
{
this.name = name;
this.comment = comment;
}
/// <include file='IniSection.xml' path='//Constructor[@name="Constructor"]/docs/*' />
public IniSection (string name)
: this (name, null)
{
}
#endregion
#region Public properties
/// <include file='IniSection.xml' path='//Property[@name="Name"]/docs/*' />
public string Name
{
get { return name; }
}
/// <include file='IniSection.xml' path='//Property[@name="Comment"]/docs/*' />
public string Comment
{
get { return comment; }
}
/// <include file='IniSection.xml' path='//Property[@name="ItemCount"]/docs/*' />
public int ItemCount
{
get { return configList.Count; }
}
#endregion
#region Public methods
/// <include file='IniSection.xml' path='//Method[@name="GetValue"]/docs/*' />
public string GetValue (string key)
{
string result = null;
if (Contains (key)) {
IniItem item = (IniItem)configList[key];
result = item.Value;
}
return result;
}
/// <include file='IniSection.xml' path='//Method[@name="GetItem"]/docs/*' />
public IniItem GetItem (int index)
{
return (IniItem)configList[index];
}
/// <include file='IniSection.xml' path='//Method[@name="GetKeys"]/docs/*' />
public string[] GetKeys ()
{
ArrayList list = new ArrayList ();
IniItem item = null;
for (int i = 0; i < configList.Count; i++)
{
item = (IniItem)configList[i];
if (item.Type == IniType.Key) {
list.Add (item.Name);
}
}
string[] result = new string[list.Count];
list.CopyTo (result, 0);
return result;
}
/// <include file='IniSection.xml' path='//Method[@name="Contains"]/docs/*' />
public bool Contains (string key)
{
return (configList[key] != null);
}
/// <include file='IniSection.xml' path='//Method[@name="SetKeyComment"]/docs/*' />
public void Set (string key, string value, string comment)
{
IniItem item = null;
if (Contains (key)) {
item = (IniItem)configList[key];
item.Value = value;
item.Comment = comment;
} else {
item = new IniItem (key, value, IniType.Key, comment);
configList.Add (key, item);
}
}
/// <include file='IniSection.xml' path='//Method[@name="SetKey"]/docs/*' />
public void Set (string key, string value)
{
Set (key, value, null);
}
/// <include file='IniSection.xml' path='//Method[@name="SetComment"]/docs/*' />
public void Set (string comment)
{
string name = "#comment" + commentCount;
IniItem item = new IniItem (name, null,
IniType.Empty, comment);
configList.Add (name, item);
commentCount++;
}
/// <include file='IniSection.xml' path='//Method[@name="SetNoComment"]/docs/*' />
public void Set ()
{
Set (null);
}
/// <include file='IniSection.xml' path='//Method[@name="Remove"]/docs/*' />
public void Remove (string key)
{
if (Contains (key)) {
configList.Remove (key);
}
}
#endregion
}
}

View File

@@ -0,0 +1,95 @@
#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.Collections;
using Nini.Util;
namespace Nini.Ini
{
/// <include file='IniSectionCollection.xml' path='//Class[@name="IniSectionCollection"]/docs/*' />
public class IniSectionCollection : ICollection, IEnumerable
{
#region Private variables
OrderedList list = new OrderedList ();
#endregion
#region Public properties
/// <include file='IniSectionCollection.xml' path='//Property[@name="ItemIndex"]/docs/*' />
public IniSection this[int index]
{
get { return (IniSection)list[index]; }
}
/// <include file='IniSectionCollection.xml' path='//Property[@name="ItemName"]/docs/*' />
public IniSection this[string configName]
{
get { return (IniSection)list[configName]; }
}
/// <include file='IniSectionCollection.xml' path='//Property[@name="Count"]/docs/*' />
public int Count
{
get { return list.Count; }
}
/// <include file='IniSectionCollection.xml' path='//Property[@name="SyncRoot"]/docs/*' />
public object SyncRoot
{
get { return list.SyncRoot; }
}
/// <include file='IniSectionCollection.xml' path='//Property[@name="IsSynchronized"]/docs/*' />
public bool IsSynchronized
{
get { return list.IsSynchronized; }
}
#endregion
#region Public methods
/// <include file='IniSectionCollection.xml' path='//Method[@name="Add"]/docs/*' />
public void Add (IniSection section)
{
if (list.Contains (section)) {
throw new ArgumentException ("IniSection already exists");
}
list.Add (section.Name, section);
}
/// <include file='IniSectionCollection.xml' path='//Method[@name="Remove"]/docs/*' />
public void Remove (string config)
{
list.Remove (config);
}
/// <include file='IniSectionCollection.xml' path='//Method[@name="CopyTo"]/docs/*' />
public void CopyTo (Array array, int index)
{
list.CopyTo (array, index);
}
/// <include file='IniSectionCollection.xml' path='//Method[@name="CopyToStrong"]/docs/*' />
public void CopyTo (IniSection[] array, int index)
{
((ICollection)list).CopyTo (array, index);
}
/// <include file='IniSectionCollection.xml' path='//Method[@name="GetEnumerator"]/docs/*' />
public IEnumerator GetEnumerator ()
{
return list.GetEnumerator ();
}
#endregion
#region Private methods
#endregion
}
}

View File

@@ -0,0 +1,308 @@
#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.Text;
namespace Nini.Ini
{
#region IniWriteState enumeration
/// <include file='IniWriter.xml' path='//Enum[@name="IniWriteState"]/docs/*' />
public enum IniWriteState : int
{
/// <include file='IniWriter.xml' path='//Enum[@name="IniWriteState"]/Value[@name="Start"]/docs/*' />
Start,
/// <include file='IniWriter.xml' path='//Enum[@name="IniWriteState"]/Value[@name="BeforeFirstSection"]/docs/*' />
BeforeFirstSection,
/// <include file='IniWriter.xml' path='//Enum[@name="IniWriteState"]/Value[@name="Section"]/docs/*' />
Section,
/// <include file='IniWriter.xml' path='//Enum[@name="IniWriteState"]/Value[@name="Closed"]/docs/*' />
Closed
};
#endregion
/// <include file='IniWriter.xml' path='//Class[@name="IniWriter"]/docs/*' />
public class IniWriter : IDisposable
{
#region Private variables
int indentation = 0;
bool useValueQuotes = false;
IniWriteState writeState = IniWriteState.Start;
char commentDelimiter = ';';
char assignDelimiter = '=';
TextWriter textWriter = null;
string eol = "\r\n";
StringBuilder indentationBuffer = new StringBuilder ();
Stream baseStream = null;
bool disposed = false;
#endregion
#region Public properties
/// <include file='IniWriter.xml' path='//Property[@name="Indentation"]/docs/*' />
public int Indentation
{
get { return indentation; }
set
{
if (value < 0)
throw new ArgumentException ("Negative values are illegal");
indentation = value;
indentationBuffer.Remove(0, indentationBuffer.Length);
for (int i = 0; i < value; i++)
indentationBuffer.Append (' ');
}
}
/// <include file='IniWriter.xml' path='//Property[@name="UseValueQuotes"]/docs/*' />
public bool UseValueQuotes
{
get { return useValueQuotes; }
set { useValueQuotes = value; }
}
/// <include file='IniWriter.xml' path='//Property[@name="WriteState"]/docs/*' />
public IniWriteState WriteState
{
get { return writeState; }
}
/// <include file='IniWriter.xml' path='//Property[@name="CommentDelimiter"]/docs/*' />
public char CommentDelimiter
{
get { return commentDelimiter; }
set { commentDelimiter = value; }
}
/// <include file='IniWriter.xml' path='//Property[@name="AssignDelimiter"]/docs/*' />
public char AssignDelimiter
{
get { return assignDelimiter; }
set { assignDelimiter = value; }
}
/// <include file='IniWriter.xml' path='//Property[@name="BaseStream"]/docs/*' />
public Stream BaseStream
{
get { return baseStream; }
}
#endregion
#region Constructors
/// <include file='IniWriter.xml' path='//Constructor[@name="ConstructorPath"]/docs/*' />
public IniWriter(string filePath)
: this (new FileStream (filePath, FileMode.Create, FileAccess.Write, FileShare.None))
{
}
/// <include file='IniWriter.xml' path='//Constructor[@name="ConstructorTextWriter"]/docs/*' />
public IniWriter (TextWriter writer)
{
textWriter = writer;
StreamWriter streamWriter = writer as StreamWriter;
if (streamWriter != null) {
baseStream = streamWriter.BaseStream;
}
}
/// <include file='IniWriter.xml' path='//Constructor[@name="ConstructorStream"]/docs/*' />
public IniWriter (Stream stream)
: this (new StreamWriter (stream))
{
}
#endregion
#region Public methods
/// <include file='IniWriter.xml' path='//Method[@name="Close"]/docs/*' />
public void Close ()
{
textWriter.Close ();
writeState = IniWriteState.Closed;
}
/// <include file='IniWriter.xml' path='//Method[@name="Flush"]/docs/*' />
public void Flush ()
{
textWriter.Flush ();
}
/// <include file='IniWriter.xml' path='//Method[@name="ToString"]/docs/*' />
public override string ToString ()
{
return textWriter.ToString ();
}
/// <include file='IniWriter.xml' path='//Method[@name="WriteSection"]/docs/*' />
public void WriteSection (string section)
{
ValidateState ();
writeState = IniWriteState.Section;
WriteLine ("[" + section + "]");
}
/// <include file='IniWriter.xml' path='//Method[@name="WriteSectionComment"]/docs/*' />
public void WriteSection (string section, string comment)
{
ValidateState ();
writeState = IniWriteState.Section;
WriteLine ("[" + section + "]" + Comment(comment));
}
/// <include file='IniWriter.xml' path='//Method[@name="WriteKey"]/docs/*' />
public void WriteKey (string key, string value)
{
ValidateStateKey ();
WriteLine (key + " " + assignDelimiter + " " + GetKeyValue (value));
}
/// <include file='IniWriter.xml' path='//Method[@name="WriteKeyComment"]/docs/*' />
public void WriteKey (string key, string value, string comment)
{
ValidateStateKey ();
WriteLine (key + " " + assignDelimiter + " " + GetKeyValue (value) + Comment (comment));
}
/// <include file='IniWriter.xml' path='//Method[@name="WriteEmpty"]/docs/*' />
public void WriteEmpty ()
{
ValidateState ();
if (writeState == IniWriteState.Start) {
writeState = IniWriteState.BeforeFirstSection;
}
WriteLine ("");
}
/// <include file='IniWriter.xml' path='//Method[@name="WriteEmptyComment"]/docs/*' />
public void WriteEmpty (string comment)
{
ValidateState ();
if (writeState == IniWriteState.Start) {
writeState = IniWriteState.BeforeFirstSection;
}
if (comment == null) {
WriteLine ("");
} else {
WriteLine (commentDelimiter + " " + comment);
}
}
/// <include file='IniWriter.xml' path='//Method[@name="Dispose"]/docs/*' />
public void Dispose ()
{
Dispose (true);
}
#endregion
#region Protected methods
/// <include file='IniWriter.xml' path='//Method[@name="DisposeBoolean"]/docs/*' />
protected virtual void Dispose (bool disposing)
{
if (!disposed)
{
textWriter.Close ();
baseStream.Close ();
disposed = true;
if (disposing)
{
GC.SuppressFinalize (this);
}
}
}
#endregion
#region Private methods
/// <summary>
/// Destructor.
/// </summary>
~IniWriter ()
{
Dispose (false);
}
/// <summary>
/// Returns the value of a key.
/// </summary>
private string GetKeyValue (string text)
{
string result;
if (useValueQuotes) {
result = MassageValue ('"' + text + '"');
} else {
result = MassageValue (text);
}
return result;
}
/// <summary>
/// Validates whether a key can be written.
/// </summary>
private void ValidateStateKey ()
{
ValidateState ();
switch (writeState)
{
case IniWriteState.BeforeFirstSection:
case IniWriteState.Start:
throw new InvalidOperationException ("The WriteState is not Section");
case IniWriteState.Closed:
throw new InvalidOperationException ("The writer is closed");
}
}
/// <summary>
/// Validates the state to determine if the item can be written.
/// </summary>
private void ValidateState ()
{
if (writeState == IniWriteState.Closed) {
throw new InvalidOperationException ("The writer is closed");
}
}
/// <summary>
/// Returns a formatted comment.
/// </summary>
private string Comment (string text)
{
return (text == null) ? "" : (" " + commentDelimiter + " " + text);
}
/// <summary>
/// Writes data to the writer.
/// </summary>
private void Write (string value)
{
textWriter.Write (indentationBuffer.ToString () + value);
}
/// <summary>
/// Writes a full line to the writer.
/// </summary>
private void WriteLine (string value)
{
Write (value + eol);
}
/// <summary>
/// Fixes the incoming value to prevent illegal characters from
/// hurting the integrity of the INI file.
/// </summary>
private string MassageValue (string text)
{
return text.Replace ("\n", "");
}
#endregion
}
}

View File

@@ -0,0 +1,199 @@
using System;
using System.Collections;
namespace Nini.Util
{
//[Serializable]
/// <include file='OrderedList.xml' path='//Class[@name="OrderedList"]/docs/*' />
public class OrderedList : ICollection, IDictionary, IEnumerable
{
#region Private variables
Hashtable table = new Hashtable ();
ArrayList list = new ArrayList ();
#endregion
#region Public properties
/// <include file='OrderedList.xml' path='//Property[@name="Count"]/docs/*' />
public int Count
{
get { return list.Count; }
}
/// <include file='OrderedList.xml' path='//Property[@name="IsFixedSize"]/docs/*' />
public bool IsFixedSize
{
get { return false; }
}
/// <include file='OrderedList.xml' path='//Property[@name="IsReadOnly"]/docs/*' />
public bool IsReadOnly
{
get { return false; }
}
/// <include file='OrderedList.xml' path='//Property[@name="IsSynchronized"]/docs/*' />
public bool IsSynchronized
{
get { return false; }
}
/// <include file='OrderedList.xml' path='//Property[@name="ItemIndex"]/docs/*' />
public object this[int index]
{
get { return ((DictionaryEntry) list[index]).Value; }
set
{
if (index < 0 || index >= Count)
throw new ArgumentOutOfRangeException ("index");
object key = ((DictionaryEntry) list[index]).Key;
list[index] = new DictionaryEntry (key, value);
table[key] = value;
}
}
/// <include file='OrderedList.xml' path='//Property[@name="ItemKey"]/docs/*' />
public object this[object key]
{
get { return table[key]; }
set
{
if (table.Contains (key))
{
table[key] = value;
table[IndexOf (key)] = new DictionaryEntry (key, value);
return;
}
Add (key, value);
}
}
/// <include file='OrderedList.xml' path='//Property[@name="Keys"]/docs/*' />
public ICollection Keys
{
get
{
ArrayList retList = new ArrayList ();
for (int i = 0; i < list.Count; i++)
{
retList.Add ( ((DictionaryEntry)list[i]).Key );
}
return retList;
}
}
/// <include file='OrderedList.xml' path='//Property[@name="Values"]/docs/*' />
public ICollection Values
{
get
{
ArrayList retList = new ArrayList ();
for (int i = 0; i < list.Count; i++)
{
retList.Add ( ((DictionaryEntry)list[i]).Value );
}
return retList;
}
}
/// <include file='OrderedList.xml' path='//Property[@name="SyncRoot"]/docs/*' />
public object SyncRoot
{
get { return this; }
}
#endregion
#region Public methods
/// <include file='OrderedList.xml' path='//Method[@name="Add"]/docs/*' />
public void Add (object key, object value)
{
table.Add (key, value);
list.Add (new DictionaryEntry (key, value));
}
/// <include file='OrderedList.xml' path='//Method[@name="Clear"]/docs/*' />
public void Clear ()
{
table.Clear ();
list.Clear ();
}
/// <include file='OrderedList.xml' path='//Method[@name="Contains"]/docs/*' />
public bool Contains (object key)
{
return table.Contains (key);
}
/// <include file='OrderedList.xml' path='//Method[@name="CopyTo"]/docs/*' />
public void CopyTo (Array array, int index)
{
table.CopyTo (array, index);
}
/// <include file='OrderedList.xml' path='//Method[@name="CopyToStrong"]/docs/*' />
public void CopyTo (DictionaryEntry[] array, int index)
{
table.CopyTo (array, index);
}
/// <include file='OrderedList.xml' path='//Method[@name="Insert"]/docs/*' />
public void Insert (int index, object key, object value)
{
if (index > Count)
throw new ArgumentOutOfRangeException ("index");
table.Add (key, value);
list.Insert (index, new DictionaryEntry (key, value));
}
/// <include file='OrderedList.xml' path='//Method[@name="Remove"]/docs/*' />
public void Remove (object key)
{
table.Remove (key);
list.RemoveAt (IndexOf (key));
}
/// <include file='OrderedList.xml' path='//Method[@name="RemoveAt"]/docs/*' />
public void RemoveAt (int index)
{
if (index >= Count)
throw new ArgumentOutOfRangeException ("index");
table.Remove ( ((DictionaryEntry)list[index]).Key );
list.RemoveAt (index);
}
/// <include file='OrderedList.xml' path='//Method[@name="GetEnumerator"]/docs/*' />
public IEnumerator GetEnumerator ()
{
return new OrderedListEnumerator (list);
}
/// <include file='OrderedList.xml' path='//Method[@name="GetDictionaryEnumerator"]/docs/*' />
IDictionaryEnumerator IDictionary.GetEnumerator ()
{
return new OrderedListEnumerator (list);
}
/// <include file='OrderedList.xml' path='//Method[@name="GetIEnumerator"]/docs/*' />
IEnumerator IEnumerable.GetEnumerator ()
{
return new OrderedListEnumerator (list);
}
#endregion
#region Private variables
private int IndexOf (object key)
{
for (int i = 0; i < list.Count; i++)
{
if (((DictionaryEntry) list[i]).Key.Equals (key))
{
return i;
}
}
return -1;
}
#endregion
}
}

View File

@@ -0,0 +1,86 @@
using System;
using System.Collections;
namespace Nini.Util
{
/// <include file='OrderedListEnumerator.xml' path='//Class[@name="OrderedListEnumerator"]/docs/*' />
public class OrderedListEnumerator : IDictionaryEnumerator
{
#region Private variables
int index = -1;
ArrayList list;
#endregion
#region Constructors
/// <summary>
/// Instantiates an ordered list enumerator with an ArrayList.
/// </summary>
internal OrderedListEnumerator (ArrayList arrayList)
{
list = arrayList;
}
#endregion
#region Public properties
/// <include file='OrderedListEnumerator.xml' path='//Property[@name="Current"]/docs/*' />
object IEnumerator.Current
{
get
{
if (index < 0 || index >= list.Count)
throw new InvalidOperationException ();
return list[index];
}
}
/// <include file='OrderedListEnumerator.xml' path='//Property[@name="CurrentStrong"]/docs/*' />
public DictionaryEntry Current
{
get
{
if (index < 0 || index >= list.Count)
throw new InvalidOperationException ();
return (DictionaryEntry)list[index];
}
}
/// <include file='OrderedListEnumerator.xml' path='//Property[@name="Entry"]/docs/*' />
public DictionaryEntry Entry
{
get { return (DictionaryEntry) Current; }
}
/// <include file='OrderedListEnumerator.xml' path='//Property[@name="Key"]/docs/*' />
public object Key
{
get { return Entry.Key; }
}
/// <include file='OrderedListEnumerator.xml' path='//Property[@name="Value"]/docs/*' />
public object Value
{
get { return Entry.Value; }
}
#endregion
#region Public methods
/// <include file='OrderedListEnumerator.xml' path='//Method[@name="MoveNext"]/docs/*' />
public bool MoveNext ()
{
index++;
if (index >= list.Count)
return false;
return true;
}
/// <include file='OrderedListEnumerator.xml' path='//Method[@name="Reset"]/docs/*' />
public void Reset ()
{
index = -1;
}
#endregion
}
}

View File

@@ -0,0 +1,199 @@
using System;
using System.Collections;
namespace ExtensionLoader.Util
{
//[Serializable]
/// <include file='OrderedList.xml' path='//Class[@name="OrderedList"]/docs/*' />
public class OrderedList : ICollection, IDictionary, IEnumerable
{
#region Private variables
Hashtable table = new Hashtable ();
ArrayList list = new ArrayList ();
#endregion
#region Public properties
/// <include file='OrderedList.xml' path='//Property[@name="Count"]/docs/*' />
public int Count
{
get { return list.Count; }
}
/// <include file='OrderedList.xml' path='//Property[@name="IsFixedSize"]/docs/*' />
public bool IsFixedSize
{
get { return false; }
}
/// <include file='OrderedList.xml' path='//Property[@name="IsReadOnly"]/docs/*' />
public bool IsReadOnly
{
get { return false; }
}
/// <include file='OrderedList.xml' path='//Property[@name="IsSynchronized"]/docs/*' />
public bool IsSynchronized
{
get { return false; }
}
/// <include file='OrderedList.xml' path='//Property[@name="ItemIndex"]/docs/*' />
public object this[int index]
{
get { return ((DictionaryEntry) list[index]).Value; }
set
{
if (index < 0 || index >= Count)
throw new ArgumentOutOfRangeException ("index");
object key = ((DictionaryEntry) list[index]).Key;
list[index] = new DictionaryEntry (key, value);
table[key] = value;
}
}
/// <include file='OrderedList.xml' path='//Property[@name="ItemKey"]/docs/*' />
public object this[object key]
{
get { return table[key]; }
set
{
if (table.Contains (key))
{
table[key] = value;
table[IndexOf (key)] = new DictionaryEntry (key, value);
return;
}
Add (key, value);
}
}
/// <include file='OrderedList.xml' path='//Property[@name="Keys"]/docs/*' />
public ICollection Keys
{
get
{
ArrayList retList = new ArrayList ();
for (int i = 0; i < list.Count; i++)
{
retList.Add ( ((DictionaryEntry)list[i]).Key );
}
return retList;
}
}
/// <include file='OrderedList.xml' path='//Property[@name="Values"]/docs/*' />
public ICollection Values
{
get
{
ArrayList retList = new ArrayList ();
for (int i = 0; i < list.Count; i++)
{
retList.Add ( ((DictionaryEntry)list[i]).Value );
}
return retList;
}
}
/// <include file='OrderedList.xml' path='//Property[@name="SyncRoot"]/docs/*' />
public object SyncRoot
{
get { return this; }
}
#endregion
#region Public methods
/// <include file='OrderedList.xml' path='//Method[@name="Add"]/docs/*' />
public void Add (object key, object value)
{
table.Add (key, value);
list.Add (new DictionaryEntry (key, value));
}
/// <include file='OrderedList.xml' path='//Method[@name="Clear"]/docs/*' />
public void Clear ()
{
table.Clear ();
list.Clear ();
}
/// <include file='OrderedList.xml' path='//Method[@name="Contains"]/docs/*' />
public bool Contains (object key)
{
return table.Contains (key);
}
/// <include file='OrderedList.xml' path='//Method[@name="CopyTo"]/docs/*' />
public void CopyTo (Array array, int index)
{
table.CopyTo (array, index);
}
/// <include file='OrderedList.xml' path='//Method[@name="CopyToStrong"]/docs/*' />
public void CopyTo (DictionaryEntry[] array, int index)
{
table.CopyTo (array, index);
}
/// <include file='OrderedList.xml' path='//Method[@name="Insert"]/docs/*' />
public void Insert (int index, object key, object value)
{
if (index > Count)
throw new ArgumentOutOfRangeException ("index");
table.Add (key, value);
list.Insert (index, new DictionaryEntry (key, value));
}
/// <include file='OrderedList.xml' path='//Method[@name="Remove"]/docs/*' />
public void Remove (object key)
{
table.Remove (key);
list.RemoveAt (IndexOf (key));
}
/// <include file='OrderedList.xml' path='//Method[@name="RemoveAt"]/docs/*' />
public void RemoveAt (int index)
{
if (index >= Count)
throw new ArgumentOutOfRangeException ("index");
table.Remove ( ((DictionaryEntry)list[index]).Key );
list.RemoveAt (index);
}
/// <include file='OrderedList.xml' path='//Method[@name="GetEnumerator"]/docs/*' />
public IEnumerator GetEnumerator ()
{
return new OrderedListEnumerator (list);
}
/// <include file='OrderedList.xml' path='//Method[@name="GetDictionaryEnumerator"]/docs/*' />
IDictionaryEnumerator IDictionary.GetEnumerator ()
{
return new OrderedListEnumerator (list);
}
/// <include file='OrderedList.xml' path='//Method[@name="GetIEnumerator"]/docs/*' />
IEnumerator IEnumerable.GetEnumerator ()
{
return new OrderedListEnumerator (list);
}
#endregion
#region Private variables
private int IndexOf (object key)
{
for (int i = 0; i < list.Count; i++)
{
if (((DictionaryEntry) list[i]).Key.Equals (key))
{
return i;
}
}
return -1;
}
#endregion
}
}

View File

@@ -0,0 +1,86 @@
using System;
using System.Collections;
namespace ExtensionLoader.Util
{
/// <include file='OrderedListEnumerator.xml' path='//Class[@name="OrderedListEnumerator"]/docs/*' />
public class OrderedListEnumerator : IDictionaryEnumerator
{
#region Private variables
int index = -1;
ArrayList list;
#endregion
#region Constructors
/// <summary>
/// Instantiates an ordered list enumerator with an ArrayList.
/// </summary>
internal OrderedListEnumerator (ArrayList arrayList)
{
list = arrayList;
}
#endregion
#region Public properties
/// <include file='OrderedListEnumerator.xml' path='//Property[@name="Current"]/docs/*' />
object IEnumerator.Current
{
get
{
if (index < 0 || index >= list.Count)
throw new InvalidOperationException ();
return list[index];
}
}
/// <include file='OrderedListEnumerator.xml' path='//Property[@name="CurrentStrong"]/docs/*' />
public DictionaryEntry Current
{
get
{
if (index < 0 || index >= list.Count)
throw new InvalidOperationException ();
return (DictionaryEntry)list[index];
}
}
/// <include file='OrderedListEnumerator.xml' path='//Property[@name="Entry"]/docs/*' />
public DictionaryEntry Entry
{
get { return (DictionaryEntry) Current; }
}
/// <include file='OrderedListEnumerator.xml' path='//Property[@name="Key"]/docs/*' />
public object Key
{
get { return Entry.Key; }
}
/// <include file='OrderedListEnumerator.xml' path='//Property[@name="Value"]/docs/*' />
public object Value
{
get { return Entry.Value; }
}
#endregion
#region Public methods
/// <include file='OrderedListEnumerator.xml' path='//Method[@name="MoveNext"]/docs/*' />
public bool MoveNext ()
{
index++;
if (index >= list.Count)
return false;
return true;
}
/// <include file='OrderedListEnumerator.xml' path='//Method[@name="Reset"]/docs/*' />
public void Reset ()
{
index = -1;
}
#endregion
}
}