#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 { /// public class IniConfigSource : ConfigSourceBase { #region Private variables IniDocument iniDocument = null; string savePath = null; bool caseSensitive = true; #endregion #region Public properties #endregion #region Constructors /// public IniConfigSource () { iniDocument = new IniDocument (); } /// public IniConfigSource (string filePath) { Load (filePath); } /// public IniConfigSource (TextReader reader) { Load (reader); } /// public IniConfigSource (IniDocument document) { Load (document); } /// public IniConfigSource (Stream stream) { Load (stream); } #endregion #region Public properties /// public bool CaseSensitive { get { return caseSensitive; } set { caseSensitive = value; } } /// public string SavePath { get { return savePath; } } #endregion #region Public methods /// public void Load (string filePath) { Load (new StreamReader (filePath)); this.savePath = filePath; } /// public void Load (TextReader reader) { Load (new IniDocument (reader)); } /// public void Load (IniDocument document) { this.Configs.Clear (); this.Merge (this); // required for SaveAll iniDocument = document; Load (); } /// public void Load (Stream stream) { Load (new StreamReader (stream)); } /// public override void Save () { if (!IsSavable ()) { throw new ArgumentException ("Source cannot be saved in this state"); } MergeConfigsIntoDocument (); iniDocument.Save (this.savePath); base.Save (); } /// public void Save (string path) { this.savePath = path; this.Save (); } /// public void Save (TextWriter writer) { MergeConfigsIntoDocument (); iniDocument.Save (writer); savePath = null; OnSaved (new EventArgs ()); } /// public void Save (Stream stream) { MergeConfigsIntoDocument (); iniDocument.Save (stream); savePath = null; OnSaved (new EventArgs ()); } /// 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 (); } /// public override string ToString () { MergeConfigsIntoDocument (); StringWriter writer = new StringWriter (); iniDocument.Save (writer); return writer.ToString (); } #endregion #region Private methods /// /// Merges all of the configs from the config collection into the /// IniDocument before it is saved. /// 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])); } } } /// /// Removes all INI sections that were removed as configs. /// 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); } } } /// /// Removes all INI keys that were removed as config keys. /// 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); } } } } /// /// Loads the configuration file. /// 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); } } /// /// Merges the IniDocument into the Configs when the document is /// reloaded. /// 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); } } /// /// Removes all configs that are not in the newly loaded INI doc. /// 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); } } } /// /// Removes all INI keys that were removed as config keys. /// 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); } } /// /// Returns true if this instance is savable. /// private bool IsSavable () { return (this.savePath != null); } #endregion } }