diff --git a/SabreTools.Library/Filtering/ExtraIni.cs b/SabreTools.Library/Filtering/ExtraIni.cs new file mode 100644 index 00000000..6c91e3ae --- /dev/null +++ b/SabreTools.Library/Filtering/ExtraIni.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace SabreTools.Library.Filtering +{ + public class ExtraIni + { + /// + /// List of extras to apply + /// + public List Items { get; set; } = new List(); + } +} diff --git a/SabreTools.Library/Filtering/ExtraIniItem.cs b/SabreTools.Library/Filtering/ExtraIniItem.cs new file mode 100644 index 00000000..21cdedf6 --- /dev/null +++ b/SabreTools.Library/Filtering/ExtraIniItem.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; + +using SabreTools.Library.Data; +using SabreTools.Library.DatItems; +using SabreTools.Library.IO; +using SabreTools.Library.Tools; + +namespace SabreTools.Library.Filtering +{ + public class ExtraIniItem + { + #region Fields + + /// + /// Field to update with INI information + /// + public Field Field { get; set; } + + /// + /// Mappings from value to machine name + /// + public Dictionary> Mappings { get; set; } = new Dictionary>(); + + #endregion + + #region Extras Population + + /// + /// Populate item using a field:file input + /// + /// Field and file combination + public void PopulateFromInput(string ini) + { + // If we don't even have a possible field and file combination + if (!ini.Contains(":")) + { + Globals.Logger.Warning($"'{ini}` is not a valid INI extras string. Valid INI extras strings are of the form 'key:value'. Please refer to README.1ST or the help feature for more details."); + return; + } + + string iniTrimmed = ini.Trim('"', ' ', '\t'); + string iniFieldString = iniTrimmed.Split(':')[0].ToLowerInvariant().Trim('"', ' ', '\t'); + string iniFileString = iniTrimmed.Substring(iniFieldString.Length + 1).Trim('"', ' ', '\t'); + + Field = iniFieldString.AsField(); + PopulateFromFile(iniFileString); + } + + /// + /// Populate the dictionary from an INI file + /// + /// Path to INI file to populate from + /// + /// The INI file format that is supported here is not exactly the same + /// as a traditional one. This expects a MAME extras format, which usually + /// doesn't contain key value pairs and always at least contains one section + /// called `ROOT_FOLDER`. If that's the name of a section, then we assume + /// the value is boolean. If there's another section name, then that is set + /// as the value instead. + /// + public void PopulateFromFile(string ini) + { + // Prepare all intenral variables + IniReader ir = ini.GetIniReader(false); + bool foundRootFolder = false; + + // If we got a null reader, just return + if (ir == null) + return; + + // Otherwise, read the file to the end + try + { + ir.ReadNextLine(); + while (!ir.EndOfStream) + { + // We don't care about whitespace or comments + if (ir.RowType == IniRowType.None || ir.RowType == IniRowType.Comment) + { + ir.ReadNextLine(); + continue; + } + + // If we have a section, just read it in + if (ir.RowType == IniRowType.SectionHeader) + { + ir.ReadNextLine(); + + // If we've found the start of the extras, set the flag + if (string.Equals(ir.Section, "ROOT_FOLDER", StringComparison.OrdinalIgnoreCase)) + foundRootFolder = true; + + continue; + } + + // If we have a value, then we start populating the dictionary + else if (foundRootFolder) + { + // Get the key and value + string key = ir.Section; + string value = ir.Line.Trim(); + + // Ensure the key exists + if (!Mappings.ContainsKey(key)) + Mappings[key] = new List(); + + // Add the new mapping + Mappings[key].Add(value); + } + } + } + catch (Exception ex) + { + Globals.Logger.Warning($"Exception found while parsing '{ini}': {ex}"); + } + + ir.Dispose(); + } + + #endregion + } +}