diff --git a/SabreTools.Core/Enums.cs b/SabreTools.Core/Enums.cs index d65e7211..8c1590db 100644 --- a/SabreTools.Core/Enums.cs +++ b/SabreTools.Core/Enums.cs @@ -736,170 +736,6 @@ namespace SabreTools.Core #endregion - #region Fields - - // TODO: This should move to Models like the rest - /// - /// List of valid field types within a DatHeader - /// - public enum DatHeaderField - { - /// - /// This is a fake flag that is used for filter only - /// - NULL = 0, - - /// Used in ClrMamePro, DOSCenter, Logiqx, and RomCenter - [Mapping("author")] - Author, - - /// Used in Logiqx - [Mapping("biosmode", "bios_mode")] - BiosMode, - - /// Used in Logiqx - [Mapping("build")] - Build, - - /// Used with OfflineList - [Mapping("canopen", "can_open")] - CanOpen, - - /// Used in ClrMamePro and Logiqx - [Mapping("category")] - Category, - - /// Used in ClrMamePro, DOSCenter, Logiqx, and RomCenter - [Mapping("comment")] - Comment, - - /// Used in ClrMamePro, DOSCenter, Logiqx, OpenMSX, and RomCenter - [Mapping("date", "timestamp", "time_stamp")] - Date, - - /// Used in Logiqx and ListXML - [Mapping("debug")] - Debug, - - /// Used in ClrMamePro, DOSCenter, ListXML, Logiqx, OpenMSX, RomCenter, Separated Value, and Software List - [Mapping("desc", "description")] - Description, - - /// Used in ClrMamePro, Logiqx, and RomCenter - [Mapping("email", "e_mail")] - Email, - - /// Used in AttractMode, OfflineList, and Separated Value - [Mapping("file", "filename", "file_name")] - FileName, - - /// Used in ClrMamePro, Logiqx, and RomCenter - [Mapping("forcemerging", "force_merging")] - ForceMerging, - - /// Used in Logiqx - [Mapping("forcenodump", "force_nodump")] - ForceNodump, - - /// Used in ClrMamePro and Logiqx - [Mapping("forcepacking", "force_packing")] - ForcePacking, - - /// Used in ClrMamePro and Logiqx - [Mapping("header", "headerskipper", "header_skipper", "skipper")] - HeaderSkipper, - - /// Used in ClrMamePro, DOSCenter, Logiqx, and RomCenter - [Mapping("homepage", "home_page")] - Homepage, - - /// Used in Logiqx - [Mapping("id", "nointroid", "no_intro_id")] - ID, - - /// Used with OfflineList; Part of "Info" object - [Mapping("info_default", "infos_default")] - Info_Default, - - /// Used with OfflineList; Part of "Info" object - [Mapping("info_isnamingoption", "info_is_naming_option", "infos_isnamingoption", "infos_is_naming_option")] - Info_IsNamingOption, - - /// Used with OfflineList; Part of "Info" object - [Mapping("info_name", "infos_name")] - Info_Name, - - /// Used with OfflineList; Part of "Info" object - [Mapping("info_visible", "infos_visible")] - Info_Visible, - - /// Used in Logiqx - [Mapping("lockbiosmode", "lockbios_mode", "lock_biosmode", "lock_bios_mode")] - LockBiosMode, - - /// Used in Logiqx - [Mapping("lockrommode", "lockrom_mode", "lock_rommode", "lock_rom_mode")] - LockRomMode, - - /// Used in Logiqx - [Mapping("locksamplemode", "locksample_mode", "lock_samplemode", "lock_sample_mode")] - LockSampleMode, - - /// Used in ListXML - [Mapping("mameconfig", "mame_config")] - MameConfig, - - /// Used in ClrMamePro, DOSCenter, ListXML, Logiqx, OfflineList, OpenMSX, RomCenter, Separated Value, and Software List - [Mapping("dat", "datname", "dat_name", "internalname", "internal_name")] - Name, - - /// Used with RomCenter - [Mapping("rcversion", "rc_version", "romcenterversion", "romcenter_version", "rom_center_version")] - RomCenterVersion, - - /// Used in Logiqx - [Mapping("rommode", "rom_mode")] - RomMode, - - /// Used with OfflineList - [Mapping("romtitle", "rom_title")] - RomTitle, - - /// Used with ClrMamePro and Logiqx - [Mapping("root", "rootdir", "root_dir", "rootdirectory", "root_directory")] - RootDir, - - /// Used in Logiqx - [Mapping("samplemode", "sample_mode")] - SampleMode, - - /// Used with OfflineList - [Mapping("screenshotheight", "screenshotsheight", "screenshot_height", "screenshots_height")] - ScreenshotsHeight, - - /// Used with OfflineList - [Mapping("screenshotwidth", "screenshotswidth", "screenshot_width", "screenshots_width")] - ScreenshotsWidth, - - /// Used with Logiqx, OfflineList, and RomCenter; "plugin" is used for RomCenter - [Mapping("system", "plugin")] - System, - - /// Used with ClrMamePro, Logiqx, and OfflineList - [Mapping("dattype", "type", "superdat")] - Type, - - /// Used with ClrMamePro, Logiqx, OfflineList, and RomCenter - [Mapping("url")] - Url, - - /// Used with ClrMamePro, DOSCenter, ListXML, Logiqx, OfflineList, and RomCenter - [Mapping("version")] - Version, - } - - #endregion - #region Logging /// diff --git a/SabreTools.Core/Tools/Converters.cs b/SabreTools.Core/Tools/Converters.cs index 2b898ed6..957688d2 100644 --- a/SabreTools.Core/Tools/Converters.cs +++ b/SabreTools.Core/Tools/Converters.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text.RegularExpressions; namespace SabreTools.Core.Tools { @@ -9,36 +8,6 @@ namespace SabreTools.Core.Tools { #region String to Enum - /// - /// Get DatHeaderField value from input string - /// - /// String to get value from - /// DatHeaderField value corresponding to the string - public static DatHeaderField AsDatHeaderField(this string? input) - { - // If the input is empty, we return null - if (string.IsNullOrEmpty(input)) - return DatHeaderField.NULL; - - // Normalize the input - input = input!.ToLowerInvariant(); - - // Create regex - string headerRegex = @"^(dat|header|datheader)[.\-_\s]"; - - // If we don't have a header field, skip - if (!Regex.IsMatch(input, headerRegex)) - return DatHeaderField.NULL; - - // Replace the match and re-normalize - string headerInput = Regex.Replace(input, headerRegex, string.Empty) - .Replace(' ', '_') - .Replace('-', '_') - .Replace('.', '_'); - - return AsEnumValue(headerInput); - } - /// /// Get bool? value from input string /// diff --git a/SabreTools.DatFiles/DatHeader.cs b/SabreTools.DatFiles/DatHeader.cs index 1dd99af3..5577fcd8 100644 --- a/SabreTools.DatFiles/DatHeader.cs +++ b/SabreTools.DatFiles/DatHeader.cs @@ -6,6 +6,7 @@ using Newtonsoft.Json; using SabreTools.Core; using SabreTools.Core.Tools; using SabreTools.DatFiles.Formats; +using SabreTools.Filter; namespace SabreTools.DatFiles { @@ -360,58 +361,29 @@ namespace SabreTools.DatFiles #region Manipulation + /// + /// Runs a filter and determines if it passes or not + /// + /// Filter runner to use for checking + /// True if the Machine passes the filter, false otherwise + public bool PassesFilter(FilterRunner filterRunner) => filterRunner.Run(_header); + /// /// Remove a field from the header /// /// Field to remove /// True if the removal was successful, false otherwise public bool RemoveField(string fieldName) - { - DatHeaderField datHeaderField = fieldName.AsDatHeaderField(); - switch (datHeaderField) - { - case DatHeaderField.Author: SetFieldValue(Models.Metadata.Header.AuthorKey, null); break; - case DatHeaderField.BiosMode: SetFieldValue(Models.Metadata.Header.BiosModeKey, MergingFlag.None); break; - case DatHeaderField.Build: SetFieldValue(Models.Metadata.Header.BuildKey, null); break; - case DatHeaderField.CanOpen: SetFieldValue(Models.Metadata.Header.CanOpenKey, null); break; - case DatHeaderField.Category: SetFieldValue(Models.Metadata.Header.CategoryKey, null); break; - case DatHeaderField.Comment: SetFieldValue(Models.Metadata.Header.CommentKey, null); break; - case DatHeaderField.Date: SetFieldValue(Models.Metadata.Header.DateKey, null); break; - case DatHeaderField.Debug: SetFieldValue(Models.Metadata.Header.DebugKey, null); break; - case DatHeaderField.Description: SetFieldValue(Models.Metadata.Header.DescriptionKey, null); break; - case DatHeaderField.Email: SetFieldValue(Models.Metadata.Header.EmailKey, null); break; - case DatHeaderField.FileName: FileName = null; break; - case DatHeaderField.ForceMerging: SetFieldValue(Models.Metadata.Header.ForceMergingKey, MergingFlag.None); break; - case DatHeaderField.ForceNodump: SetFieldValue(Models.Metadata.Header.ForceNodumpKey, NodumpFlag.None); break; - case DatHeaderField.ForcePacking: SetFieldValue(Models.Metadata.Header.ForcePackingKey, PackingFlag.None); break; - case DatHeaderField.HeaderSkipper: SetFieldValue(Models.Metadata.Header.HeaderKey, null); break; - case DatHeaderField.Homepage: SetFieldValue(Models.Metadata.Header.HomepageKey, null); break; - case DatHeaderField.ID: SetFieldValue(Models.Metadata.Header.IdKey, null); break; - // case DatHeaderField.Info_Default: Info_Default = null; break; - // case DatHeaderField.Info_IsNamingOption: Info_IsNamingOption = null; break; - // case DatHeaderField.Info_Name: Info_Name = null; break; - // case DatHeaderField.Info_Visible: Info_Visible = null; break; - case DatHeaderField.LockBiosMode: SetFieldValue(Models.Metadata.Header.LockBiosModeKey, null); break; - case DatHeaderField.LockRomMode: SetFieldValue(Models.Metadata.Header.LockRomModeKey, null); break; - case DatHeaderField.LockSampleMode: SetFieldValue(Models.Metadata.Header.LockSampleModeKey, null); break; - case DatHeaderField.MameConfig: SetFieldValue(Models.Metadata.Header.MameConfigKey, null); break; - case DatHeaderField.Name: SetFieldValue(Models.Metadata.Header.NameKey, null); break; - case DatHeaderField.RomCenterVersion: SetFieldValue(Models.Metadata.Header.DatVersionKey, null); break; - case DatHeaderField.RomMode: SetFieldValue(Models.Metadata.Header.RomModeKey, MergingFlag.None); break; - case DatHeaderField.RomTitle: SetFieldValue(Models.Metadata.Header.RomTitleKey, null); break; - case DatHeaderField.RootDir: SetFieldValue(Models.Metadata.Header.RootDirKey, null); break; - case DatHeaderField.SampleMode: SetFieldValue(Models.Metadata.Header.SampleModeKey, MergingFlag.None); break; - case DatHeaderField.ScreenshotsHeight: SetFieldValue(Models.Metadata.Header.ScreenshotsHeightKey, null); break; - case DatHeaderField.ScreenshotsWidth: SetFieldValue(Models.Metadata.Header.ScreenshotsWidthKey, null); break; - case DatHeaderField.System: SetFieldValue(Models.Metadata.Header.SystemKey, null); break; - case DatHeaderField.Type: SetFieldValue(Models.Metadata.Header.TypeKey, null); break; - case DatHeaderField.Url: SetFieldValue(Models.Metadata.Header.UrlKey, null); break; - case DatHeaderField.Version: SetFieldValue(Models.Metadata.Header.VersionKey, null); break; - default: return false; - } + => FieldManipulator.RemoveField(_header, fieldName); - return true; - } + /// + /// Replace a field from another DatHeader + /// + /// DatHeader to replace field from + /// Field to replace + /// True if the replacement was successful, false otherwise + public bool ReplaceField(DatHeader? other, string? fieldName) + => FieldManipulator.ReplaceField(other?._header, _header, fieldName); /// /// Set a field in the header from a mapping string @@ -421,52 +393,7 @@ namespace SabreTools.DatFiles /// True if the setting was successful, false otherwise /// This only performs minimal validation before setting public bool SetField(string? fieldName, string value) - { - DatHeaderField datHeaderField = fieldName.AsDatHeaderField(); - switch (datHeaderField) - { - case DatHeaderField.Author: SetFieldValue(Models.Metadata.Header.AuthorKey, value); break; - case DatHeaderField.BiosMode: SetFieldValue(Models.Metadata.Header.BiosModeKey, value.AsEnumValue()); break; - case DatHeaderField.Build: SetFieldValue(Models.Metadata.Header.BuildKey, value); break; - case DatHeaderField.CanOpen: SetFieldValue(Models.Metadata.Header.CanOpenKey,[.. value.Split(',')]); break; - case DatHeaderField.Category: SetFieldValue(Models.Metadata.Header.CategoryKey, value); break; - case DatHeaderField.Comment: SetFieldValue(Models.Metadata.Header.CommentKey, value); break; - case DatHeaderField.Date: SetFieldValue(Models.Metadata.Header.DateKey, value); break; - case DatHeaderField.Debug: SetFieldValue(Models.Metadata.Header.DebugKey, value.AsYesNo()); break; - case DatHeaderField.Description: SetFieldValue(Models.Metadata.Header.DescriptionKey, value); break; - case DatHeaderField.Email: SetFieldValue(Models.Metadata.Header.EmailKey, value); break; - case DatHeaderField.FileName: FileName = value; break; - case DatHeaderField.ForceMerging: SetFieldValue(Models.Metadata.Header.ForceMergingKey, value.AsEnumValue()); break; - case DatHeaderField.ForceNodump: SetFieldValue(Models.Metadata.Header.ForceNodumpKey, value.AsEnumValue()); break; - case DatHeaderField.ForcePacking: SetFieldValue(Models.Metadata.Header.ForcePackingKey, value.AsEnumValue()); break; - case DatHeaderField.HeaderSkipper: SetFieldValue(Models.Metadata.Header.HeaderKey, value); break; - case DatHeaderField.Homepage: SetFieldValue(Models.Metadata.Header.HomepageKey, value); break; - case DatHeaderField.ID: SetFieldValue(Models.Metadata.Header.IdKey, value); break; - // case DatHeaderField.Info_Default: Info_Default = value; break; - // case DatHeaderField.Info_IsNamingOption: Info_IsNamingOption = value; break; - // case DatHeaderField.Info_Name: Info_Name = value; break; - // case DatHeaderField.Info_Visible: Info_Visible = value; break; - case DatHeaderField.LockBiosMode: SetFieldValue(Models.Metadata.Header.LockBiosModeKey, value.AsYesNo()); break; - case DatHeaderField.LockRomMode: SetFieldValue(Models.Metadata.Header.LockRomModeKey, value.AsYesNo()); break; - case DatHeaderField.LockSampleMode: SetFieldValue(Models.Metadata.Header.LockSampleModeKey, value.AsYesNo()); break; - case DatHeaderField.MameConfig: SetFieldValue(Models.Metadata.Header.MameConfigKey, value); break; - case DatHeaderField.Name: SetFieldValue(Models.Metadata.Header.NameKey, value); break; - case DatHeaderField.RomCenterVersion: SetFieldValue(Models.Metadata.Header.DatVersionKey, value); break; - case DatHeaderField.RomMode: SetFieldValue(Models.Metadata.Header.RomModeKey, value.AsEnumValue()); break; - case DatHeaderField.RomTitle: SetFieldValue(Models.Metadata.Header.RomTitleKey, value); break; - case DatHeaderField.RootDir: SetFieldValue(Models.Metadata.Header.RootDirKey, value); break; - case DatHeaderField.SampleMode: SetFieldValue(Models.Metadata.Header.SampleModeKey, value.AsEnumValue()); break; - case DatHeaderField.ScreenshotsHeight: SetFieldValue(Models.Metadata.Header.ScreenshotsHeightKey, value); break; - case DatHeaderField.ScreenshotsWidth: SetFieldValue(Models.Metadata.Header.ScreenshotsWidthKey, value); break; - case DatHeaderField.System: SetFieldValue(Models.Metadata.Header.SystemKey, value); break; - case DatHeaderField.Type: SetFieldValue(Models.Metadata.Header.TypeKey, value); break; - case DatHeaderField.Url: SetFieldValue(Models.Metadata.Header.UrlKey, value); break; - case DatHeaderField.Version: SetFieldValue(Models.Metadata.Header.VersionKey, value); break; - default: return false; - } - - return true; - } + => FieldManipulator.SetField(_header, fieldName, value); #endregion diff --git a/SabreTools.DatItems/DatItem.cs b/SabreTools.DatItems/DatItem.cs index 539ee348..4a7d900c 100644 --- a/SabreTools.DatItems/DatItem.cs +++ b/SabreTools.DatItems/DatItem.cs @@ -273,12 +273,16 @@ namespace SabreTools.DatItems // If the duplicate is external already or should be, set it #if NETFRAMEWORK - if ((lastItem.GetFieldValue(DatItem.DupeTypeKey) & DupeType.External) != 0 || lastItem?.GetFieldValue(DatItem.SourceKey)?.Index != GetFieldValue(DatItem.SourceKey)?.Index) + if ((lastItem.GetFieldValue(DatItem.DupeTypeKey) & DupeType.External) != 0 + || lastItem?.GetFieldValue(DatItem.SourceKey)?.Index != GetFieldValue(DatItem.SourceKey)?.Index) #else - if (lastItem.GetFieldValue(DatItem.DupeTypeKey).HasFlag(DupeType.External) || lastItem?.GetFieldValue(DatItem.SourceKey)?.Index != GetFieldValue(DatItem.SourceKey)?.Index) + if (lastItem.GetFieldValue(DatItem.DupeTypeKey).HasFlag(DupeType.External) + || lastItem?.GetFieldValue(DatItem.SourceKey)?.Index != GetFieldValue(DatItem.SourceKey)?.Index) #endif { - if (lastItem?.GetFieldValue(DatItem.MachineKey)?.GetFieldValue(Models.Metadata.Machine.NameKey) == GetFieldValue(DatItem.MachineKey)?.GetFieldValue(Models.Metadata.Machine.NameKey) && lastItem?.GetName() == GetName()) + var currentMachine = GetFieldValue(DatItem.MachineKey); + var lastMachine = lastItem?.GetFieldValue(DatItem.MachineKey); + if (lastMachine?.GetFieldValue(Models.Metadata.Machine.NameKey) == currentMachine?.GetFieldValue(Models.Metadata.Machine.NameKey) && lastItem?.GetName() == GetName()) output = DupeType.External | DupeType.All; else output = DupeType.External | DupeType.Hash; @@ -287,7 +291,9 @@ namespace SabreTools.DatItems // Otherwise, it's considered an internal dupe else { - if (lastItem?.GetFieldValue(DatItem.MachineKey)?.GetFieldValue(Models.Metadata.Machine.NameKey) == GetFieldValue(DatItem.MachineKey)?.GetFieldValue(Models.Metadata.Machine.NameKey) && lastItem?.GetName() == GetName()) + var currentMachine = GetFieldValue(DatItem.MachineKey); + var lastMachine = lastItem?.GetFieldValue(DatItem.MachineKey); + if (lastMachine?.GetFieldValue(Models.Metadata.Machine.NameKey) == currentMachine?.GetFieldValue(Models.Metadata.Machine.NameKey) && lastItem?.GetName() == GetName()) output = DupeType.Internal | DupeType.All; else output = DupeType.Internal | DupeType.Hash; diff --git a/SabreTools.DatItems/Machine.cs b/SabreTools.DatItems/Machine.cs index 13f20912..c950227d 100644 --- a/SabreTools.DatItems/Machine.cs +++ b/SabreTools.DatItems/Machine.cs @@ -152,17 +152,8 @@ namespace SabreTools.DatItems #region Constructors - /// - /// Create a new Machine object - /// - public Machine() - { - } + public Machine() { } - /// - /// Create a new Machine object from an existing metadata model - /// - /// Machine metadata model public Machine(Models.Metadata.Machine machine) { // Get all fields to automatically copy without processing @@ -178,12 +169,7 @@ namespace SabreTools.DatItems _machine[fieldName] = machine[fieldName]; } } - - /// - /// Create a new Machine object with the included information - /// - /// Name of the machine - /// Description of the machine + public Machine(string name, string description) { SetFieldValue(Models.Metadata.Machine.NameKey, name); diff --git a/SabreTools.Test/Core/ConvertersTests.cs b/SabreTools.Test/Core/ConvertersTests.cs index 83206535..d7f0e14c 100644 --- a/SabreTools.Test/Core/ConvertersTests.cs +++ b/SabreTools.Test/Core/ConvertersTests.cs @@ -41,30 +41,6 @@ namespace SabreTools.Test.Core Assert.Equal(expected, actual); } - [Theory] - [InlineData(null, DatHeaderField.NULL)] - [InlineData("datname", DatHeaderField.NULL)] - [InlineData("dat-datname", DatHeaderField.Name)] - [InlineData("dat.datname", DatHeaderField.Name)] - [InlineData("dat_datname", DatHeaderField.Name)] - [InlineData("dat datname", DatHeaderField.Name)] - [InlineData("datheader-datname", DatHeaderField.Name)] - [InlineData("datheader.datname", DatHeaderField.Name)] - [InlineData("datheader_datname", DatHeaderField.Name)] - [InlineData("datheader datname", DatHeaderField.Name)] - [InlineData("header-datname", DatHeaderField.Name)] - [InlineData("header.datname", DatHeaderField.Name)] - [InlineData("header_datname", DatHeaderField.Name)] - [InlineData("header datname", DatHeaderField.Name)] - [InlineData("DAT.DATNAME", DatHeaderField.Name)] - [InlineData("dAt.DAtnamE", DatHeaderField.Name)] - public void AsDatHeaderFieldProcessingTest(string? field, DatHeaderField expected) - { - // TODO: Write new test for all supported fields - DatHeaderField actual = field.AsDatHeaderField(); - Assert.Equal(expected, actual); - } - [Theory] [InlineData(null, DeviceType.NULL)] [InlineData("unknown", DeviceType.Unknown)] @@ -749,7 +725,6 @@ namespace SabreTools.Test.Core [Theory] [InlineData(ChipType.NULL, 2)] [InlineData(ControlType.NULL, 15)] - [InlineData(DatHeaderField.NULL, 94)] [InlineData(DeviceType.NULL, 21)] [InlineData(DisplayType.NULL, 5)] [InlineData(Endianness.NULL, 2)] diff --git a/SabreTools/Features/Batch.cs b/SabreTools/Features/Batch.cs index 7f9ec511..c025d7d2 100644 --- a/SabreTools/Features/Batch.cs +++ b/SabreTools/Features/Batch.cs @@ -706,7 +706,7 @@ Reset the internal state: reset();"; /// public override void Process(BatchState batchState) { - Remover remover = new(); + var remover = new Remover(); remover.PopulateExclusionsFromList(Arguments); remover.ApplyRemovals(batchState.DatFile); } @@ -802,10 +802,11 @@ Reset the internal state: reset();"; return (false, message); } - DatHeaderField field = Arguments[0].AsDatHeaderField(); - + // Read in the individual arguments + (string? type, string? key) = FilterParser.ParseFilterId(Arguments[0]); + // If we had an invalid input, log and continue - if (field == DatHeaderField.NULL) + if ((type == null || !string.Equals(type, Models.Metadata.MetadataFile.HeaderKey, StringComparison.OrdinalIgnoreCase)) && key == null) { string message = $"{Arguments[0]} was an invalid field name"; return (false, message);