diff --git a/SabreTools.Library/DatFiles/ClrMamePro.cs b/SabreTools.Library/DatFiles/ClrMamePro.cs index 1fd27ba6..1fe4c21c 100644 --- a/SabreTools.Library/DatFiles/ClrMamePro.cs +++ b/SabreTools.Library/DatFiles/ClrMamePro.cs @@ -15,13 +15,24 @@ namespace SabreTools.Library.DatFiles /// internal class ClrMamePro : DatFile { + #region Fields + + /// + /// Get whether to assume quote usage on read and write or not + /// + public bool Quotes { get; set; } = true; + + #endregion + /// /// Constructor designed for casting a base DatFile /// /// Parent DatFile to copy from - public ClrMamePro(DatFile datFile) + /// Enable quotes on read and write, false otherwise + public ClrMamePro(DatFile datFile, bool quotes) : base(datFile) { + Quotes = quotes; } /// @@ -37,7 +48,8 @@ namespace SabreTools.Library.DatFiles Encoding enc = FileExtensions.GetEncoding(filename); ClrMameProReader cmpr = new ClrMameProReader(FileExtensions.TryOpenRead(filename), enc) { - DosCenter = false + DosCenter = false, + Quotes = Quotes, }; while (!cmpr.EndOfStream) @@ -445,7 +457,7 @@ namespace SabreTools.Library.DatFiles ClrMameProWriter cmpw = new ClrMameProWriter(fs, new UTF8Encoding(false)) { - Quotes = true + Quotes = Quotes }; // Write out the header diff --git a/SabreTools.Library/DatFiles/DatFile.cs b/SabreTools.Library/DatFiles/DatFile.cs index 8682ca80..187d2271 100644 --- a/SabreTools.Library/DatFiles/DatFile.cs +++ b/SabreTools.Library/DatFiles/DatFile.cs @@ -65,8 +65,9 @@ namespace SabreTools.Library.DatFiles /// /// Format of the DAT to be created /// DatFile containing the information to use in specific operations + /// For relevant types, assume the usage of quotes /// DatFile of the specific internal type that corresponds to the inputs - public static DatFile Create(DatFormat? datFormat = null, DatFile baseDat = null) + public static DatFile Create(DatFormat? datFormat = null, DatFile baseDat = null, bool quotes = true) { switch (datFormat) { @@ -74,7 +75,7 @@ namespace SabreTools.Library.DatFiles return new AttractMode(baseDat); case DatFormat.ClrMamePro: - return new ClrMamePro(baseDat); + return new ClrMamePro(baseDat, quotes); case DatFormat.CSV: return new SeparatedValue(baseDat, ','); @@ -1819,16 +1820,18 @@ namespace SabreTools.Library.DatFiles /// Index ID for the DAT /// True if full pathnames are to be kept, false otherwise (default) /// True if original extension should be kept, false otherwise (default) + /// True if quotes are assumed in supported types (default), false otherwise /// True if the error that is thrown should be thrown back to the caller, false otherwise public void Parse( string filename, int indexId = 0, bool keep = false, bool keepext = false, + bool quotes = true, bool throwOnError = false) { ParentablePath path = new ParentablePath(filename.Trim('"')); - Parse(path, indexId, keep, keepext, throwOnError); + Parse(path, indexId, keep, keepext, quotes, throwOnError); } /// @@ -1838,12 +1841,14 @@ namespace SabreTools.Library.DatFiles /// Index ID for the DAT /// True if full pathnames are to be kept, false otherwise (default) /// True if original extension should be kept, false otherwise (default) + /// True if quotes are assumed in supported types (default), false otherwise /// True if the error that is thrown should be thrown back to the caller, false otherwise public void Parse( ParentablePath filename, int indexId = 0, bool keep = false, bool keepext = false, + bool quotes = true, bool throwOnError = false) { // Get the current path from the filename @@ -1863,7 +1868,7 @@ namespace SabreTools.Library.DatFiles // Now parse the correct type of DAT try { - Create(currentPath.GetDatFormat(), this)?.ParseFile(currentPath, indexId, keep, throwOnError); + Create(currentPath.GetDatFormat(), this, quotes)?.ParseFile(currentPath, indexId, keep, throwOnError); } catch (Exception ex) { @@ -3484,9 +3489,15 @@ namespace SabreTools.Library.DatFiles /// Set the output directory (current directory on null) /// True if files should be overwritten (default), false if they should be renamed instead /// True if blank roms should be skipped on output, false otherwise (default) + /// True if quotes are assumed in supported types (default), false otherwise /// True if the error that is thrown should be thrown back to the caller, false otherwise /// True if the DAT was written correctly, false otherwise - public bool Write(string outDir, bool overwrite = true, bool ignoreblanks = false, bool throwOnError = false) + public bool Write( + string outDir, + bool overwrite = true, + bool ignoreblanks = false, + bool quotes = true, + bool throwOnError = false) { // If we have nothing writable, abort if (!HasWritable()) @@ -3525,7 +3536,7 @@ namespace SabreTools.Library.DatFiles string outfile = outfiles[datFormat]; try { - Create(datFormat, this)?.WriteToFile(outfile, ignoreblanks, throwOnError); + Create(datFormat, this, quotes)?.WriteToFile(outfile, ignoreblanks, throwOnError); } catch (Exception ex) { diff --git a/SabreTools.Library/Data/Constants.cs b/SabreTools.Library/Data/Constants.cs index 6b07eb2e..63e2943c 100644 --- a/SabreTools.Library/Data/Constants.cs +++ b/SabreTools.Library/Data/Constants.cs @@ -526,7 +526,7 @@ namespace SabreTools.Library.Data public const string XmlPattern = @"<(.*?)>(.*?)"; public const string HeaderPatternCMP = @"(^.*?) \($"; - public const string InternalPatternCMP = @"(^.*?) (\(.+\))$"; + public const string InternalPatternCMP = @"(^\S*?) (\(.+\))$"; public const string InternalPatternAttributesCMP = @"[^\s""]+|""[^""]*"""; //public const string InternalPatternAttributesCMP = @"([^\s]*""[^""]+""[^\s]*)|[^""]?\w+[^""]?"; public const string ItemPatternCMP = @"^\s*(\S*?) (.*)"; diff --git a/SabreTools.Library/IO/ClrMameProReader.cs b/SabreTools.Library/IO/ClrMameProReader.cs index 85e4dfad..86e1b6aa 100644 --- a/SabreTools.Library/IO/ClrMameProReader.cs +++ b/SabreTools.Library/IO/ClrMameProReader.cs @@ -42,6 +42,17 @@ namespace SabreTools.Library.IO /// public bool DosCenter { get; set; } = false; + /// + /// Get if quotes should surround attribute values + /// + /// + /// If this is disabled, then a special bit of code will be + /// invoked to deal with unquoted, multi-part names. This can + /// backfire in a lot of circumstances, so don't disable this + /// unless you know what you're doing + /// + public bool Quotes { get; set; } = true; + /// /// Current row type /// @@ -166,6 +177,22 @@ namespace SabreTools.Library.IO value = linegc[++i].Replace("\"", string.Empty); } } + // Special case for assumed unquoted values (only affects `name`) + else if (!Quotes && key == "name") + { + while (++i < linegc.Length + && linegc[i] != "merge" + && linegc[i] != "size" + && linegc[i] != "crc" + && linegc[i] != "md5" + && linegc[i] != "sha1") + { + value += $" {linegc[i]}"; + } + + value = value.Trim(); + i--; + } else { // Special cases for standalone statuses