//https://rms0.org?a=r1 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Net; namespace RMSoftware.IO { /// /// Provides a configuration system that reads and writes in the INI File language. /// Supports reading from internet resources. /// public class INIFile { #region internal string FilePath; List lines = new List(); bool busy = false; bool _GeneratedNewFile = false; bool FromInternet = false; bool Streamed = false; /// /// Returns the local filename and location. /// /// /// public string GetFileName() { if (FromInternet) { throw new InvalidOperationException("Attempted to return a local file while using an internet resource."); } return FilePath; } #endregion #region public public List Categories = new List(); /// /// Returns true if a new file had to be created. /// public bool GeneratedNewFile { get { return _GeneratedNewFile; } } #endregion public INIFile(string pathOrURL) { _GeneratedNewFile = false; FromInternet = (pathOrURL.StartsWith("http://") || pathOrURL.StartsWith("https://")); if (!FromInternet) { FilePath = pathOrURL; VerifyFile(pathOrURL); readFromFile(pathOrURL); } if (FromInternet) { readFromInternet(pathOrURL); } ProcessLines(); } public INIFile(byte[] rawData) { Streamed = true; using (MemoryStream dataStream = new MemoryStream(rawData)) { using (StreamReader sr = new StreamReader(dataStream)) { string line = ""; while (true) { line = sr.ReadLine(); if (line != null) { if (!line.StartsWith("#") && !line.StartsWith(";")) { if (!string.IsNullOrWhiteSpace(line)) { lines.Add(line); } } } if (sr.EndOfStream) { break; } } } } ProcessLines(); } #region Public Methods /// /// Creates a new INI entry in an existing category. If the category doesn't exist, an argument exception is thrown. /// If the entry exists in that category, an argument exception is thrown. /// /// The name of the category to place entry (Enter it without the brackets '[]' please.) /// The name of the new entry /// The value for the entry. /// /// /// public void CreateEntry(string category, string entry, object entryValue) { if (FromInternet || Streamed) { throw (new InvalidOperationException("You Cannot modify stream")); } if (string.IsNullOrWhiteSpace(category)) { throw (new ArgumentNullException("The category must be contain at least one non-whitespace character.")); } if (string.IsNullOrWhiteSpace(entry)) { throw (new ArgumentNullException("The entry name must be contain at least one non-whitespace character.")); } INICategory cat = GetCategoryByName(category); if (cat == null) { throw (new ArgumentException("The category doesn't exist. Please check your spelling and casing.")); } foreach (INIEntry item in cat.Entries) { if (item.Name == entry) { throw (new ArgumentException("The entry you specified already exists.")); } } cat.Entries.Add(new INIEntry(entry, entryValue.ToString())); } /// /// Creates a new INI Category /// /// The name of the new category. (Enter it without the brackets '[]' please.) /// /// public void CreateCategory(string c) { string category = c.ToLower(); if (FromInternet || Streamed) { throw (new InvalidOperationException("You Cannot modify stream")); } if (string.IsNullOrWhiteSpace(category)) { throw (new ArgumentNullException("The category must be contain at least one non-whitespace character.")); } foreach (INICategory item in Categories) { if (item.Name == category) { throw (new ArgumentException("That category already exists")); } } Categories.Add(new INICategory(category)); } /// /// Deletes INI entry in an existing category. If the category doesn't exist, an argument exception is thrown. /// If the entry Doesn't exists in that category, an argument exception is thrown. /// /// The name of the category to remove entry from (Enter it without the brackets '[]' please.) /// The name of the entry /// /// public void DeleteEntry(string category, string entry) { if (FromInternet || Streamed) { throw (new InvalidOperationException("You Cannot modify stream")); } if (string.IsNullOrWhiteSpace(category)) { throw (new ArgumentNullException("The category must be contain at least one non-whitespace character.")); } if (string.IsNullOrWhiteSpace(entry)) { throw (new ArgumentNullException("The entry name must be contain at least one non-whitespace character.")); } INICategory cat = GetCategoryByName(category); if (cat == null) { throw (new ArgumentException("The category doesn't exist. Please check your spelling and casing.")); } cat.Entries.Remove(cat.GetEntryByName(entry)); } /// /// Deletes an INI Category /// /// The name of the category to delete. (Enter it without the brackets '[]' please.) /// /// public void DeleteCategory(string c) { string category = c.ToLower(); if (FromInternet || Streamed) { throw (new InvalidOperationException("You Cannot modify stream")); } if (string.IsNullOrWhiteSpace(category)) { throw (new ArgumentNullException("The category must be contain at least one non-whitespace character.")); } Categories.Remove(GetCategoryByName(category)); } /// /// Writes the configuration to disk. /// public void SaveConfiguration() { if (FromInternet || Streamed) { throw (new InvalidOperationException("Internet or streamed configurations cannot be saved. Read Only.")); } if (busy) { return; } busy = true; VerifyFile(FilePath); int index = 0; using (FileStream fs = new FileStream(FilePath,FileMode.Truncate,FileAccess.Write)) { using(StreamWriter sw = new StreamWriter(fs)) { sw.WriteLine("#File Generated by the RMSoftware.IO Library."); sw.WriteLine("#Creation Timestamp: {0}", DateTime.Now.ToString()); sw.WriteLine(); foreach (INICategory item in Categories) { if (index > 0) { sw.WriteLine(); } sw.WriteLine(item.ToString()); index++; foreach (INIEntry entry in item.Entries) { sw.WriteLine(entry.ToString()); } } } } busy = false; } /// /// Checks for the existence of a specified category. if none is found, returns false. /// /// /// public bool CheckForCategory(string category) { if (GetCategoryByName(category) == null) { return false; } else { return true; } } public INICategory GetCategoryByName(string name) { foreach (INICategory item in Categories) { if (item.Name.ToLower() == name.ToLower())//case doesn't matter anymore it defaults to lowercase... so If something is added and it already exists in another case style, it will return the item. { return item; } } return null; //instead of errors. //throw (new ArgumentException("The name provided did not match any categories available.")); } #endregion #region Private Methods private void VerifyFile(string path) { string pathfull = Path.GetFullPath(path); if (!Directory.Exists(Path.GetDirectoryName(pathfull))) //The directory does not exist. Impossible for the file to exist. { //Console.WriteLine("DIRECTORY NOT FOUND. " + Path.GetDirectoryName(path)); Directory.CreateDirectory(Path.GetDirectoryName(pathfull)); //Console.WriteLine("FILE NOT FOUND. " + Path.GetFileName(path)); FileStream fs = File.Create(pathfull); fs.Close(); _GeneratedNewFile = true; } else//The directory exists { //Console.WriteLine("DIRECTORY FOUND. " + Path.GetDirectoryName(path)); if (!File.Exists(pathfull)) //and the file does not exist. { //Console.WriteLine("FILE NOT FOUND. " + Path.GetFileName(path)); FileStream fs = File.Create(pathfull); fs.Close(); _GeneratedNewFile = true; } else { //Console.WriteLine("FILE FOUND. " + Path.GetFileName(path)); } } } void readFromFile(string fromPath) { using (FileStream fs = new FileStream(fromPath, FileMode.Open)) { using (StreamReader sr = new StreamReader(fs)) { string line = ""; while (true) { line = sr.ReadLine(); if (line != null) { if (!line.StartsWith("#") && !line.StartsWith(";")) { if (!string.IsNullOrWhiteSpace(line)) { lines.Add(line); } } } if (sr.EndOfStream) { break; } } } } } /// /// Reads from internet resource /// /// Thrown if we can't connect. /// void readFromInternet(string URL) { try { WebRequest iniRequest = WebRequest.Create(URL); using (Stream Response = iniRequest.GetResponse().GetResponseStream()) { using (StreamReader sr = new StreamReader(Response)) { string line = ""; while (true) { line = sr.ReadLine(); if (line != null) { if (!line.StartsWith("#")) { if (!string.IsNullOrWhiteSpace(line)) { lines.Add(line); } } } if (sr.EndOfStream) { break; } } } } } catch (WebException exc) { throw exc; } } void ProcessLines() { int catIndex = -1; if (lines.Count == 0) { return; } foreach (string line in lines) { if (line.StartsWith("[") && line.EndsWith("]")) { string name = line.Replace("[", "").Replace("]", ""); Categories.Add(new INICategory(name)); catIndex++; } else { string[] splittedString = line.Split('='); string name = splittedString[0]; string v = splittedString[1]; if (splittedString.Length > 2) { for (int i = 2; i < splittedString.Length; i++) { v += "=" + splittedString[i]; } } Categories[catIndex].Entries.Add(new INIEntry(name, v)); } } } #endregion } /// /// Category within INI file. appears as: [Category1] /// public class INICategory { public string Name {get;set;} public List Entries = new List(); /// /// Returns how this would look inside an INI file. /// /// public override string ToString() { return "["+Name+"]"; } /// /// Creates a new category with several objects. /// /// The name of the category /// A collection of entries in a category. public INICategory(string name) { this.Name = name; } /// /// Checks for the existence of an entry. if not found, returns false. /// /// /// public bool CheckForEntry(string entry) { if (GetEntryByName(entry) == null) { return false; } else { return true; } } public INIEntry GetEntryByName(string name) { foreach (INIEntry item in Entries) { if (item.Name == name) { return item; } } //throw (new ArgumentException("The name provided did not match any entries available.")); return null;//rather than errors; } } /// /// Entry inside a category appears as Entry1=hello /// public class INIEntry { /// /// Get and set the name for the entry /// public string Name { get; set; } /// /// Get and set the value of the entry. /// string Value {get;set;} /// /// Returns how this would look inside an INI file. /// /// public override string ToString() { return Name + "=" + Value; } public int GetAsInteger() { try { return int.Parse(Value); } catch (Exception) { throw; } } public double GetAsDouble() { try { return double.Parse(Value); } catch (Exception) { throw; } } public long GetAslong() { try { return long.Parse(Value); } catch (Exception) { throw; } } public ulong GetAsUlong() { try { return ulong.Parse(Value); } catch (Exception) { throw; } } public bool GetAsBool() { try { return bool.Parse(Value); } catch (Exception) { throw; } } public byte GetAsByte() { try { return byte.Parse(Value); } catch (Exception) { throw; } } public string GetAsString() { return Value; } public void SetValue(int value) { Value = value.ToString(); } public void SetValue(double value) { Value = value.ToString(); } public void SetValue(long value) { Value = value.ToString(); } public void SetValue(bool value) { Value = value.ToString(); } public void SetValue(byte value) { Value = value.ToString(); } public void SetValue(string value) { Value = value; } /// /// Creates an INI Entry. /// /// The name for the entry /// The value of the entry. public INIEntry(string name, string value) { Name = name; Value = value; } } }