diff --git a/SabreTools.Library/DatFiles/ClrMamePro.cs b/SabreTools.Library/DatFiles/ClrMamePro.cs index 5ad32231..4114150d 100644 --- a/SabreTools.Library/DatFiles/ClrMamePro.cs +++ b/SabreTools.Library/DatFiles/ClrMamePro.cs @@ -241,6 +241,9 @@ namespace SabreTools.Library.DatFiles case "manufacturer": machine.Manufacturer = itemVal; break; + case "category": + machine.Category = itemVal; + break; case "cloneof": machine.CloneOf = itemVal; break; @@ -634,6 +637,8 @@ namespace SabreTools.Library.DatFiles cmpw.WriteStandalone("year", datItem.Year); if (!string.IsNullOrWhiteSpace(datItem.GetField(Field.Manufacturer, DatHeader.ExcludeFields))) cmpw.WriteStandalone("manufacturer", datItem.Manufacturer); + if (!string.IsNullOrWhiteSpace(datItem.GetField(Field.Category, DatHeader.ExcludeFields))) + cmpw.WriteStandalone("category", datItem.Category); cmpw.Flush(); } diff --git a/SabreTools.Library/DatFiles/DatFile.cs b/SabreTools.Library/DatFiles/DatFile.cs index bbd33c5d..3abcc10c 100644 --- a/SabreTools.Library/DatFiles/DatFile.cs +++ b/SabreTools.Library/DatFiles/DatFile.cs @@ -1147,6 +1147,9 @@ namespace SabreTools.Library.DatFiles if (updateFields.Contains(Field.Publisher)) newDatItem.Publisher = firstDupe.Publisher; + if (updateFields.Contains(Field.Category)) + newDatItem.Category = firstDupe.Category; + if (updateFields.Contains(Field.RomOf)) newDatItem.RomOf = firstDupe.RomOf; @@ -3659,6 +3662,7 @@ namespace SabreTools.Library.DatFiles name = item.Name, manufacturer = item.Manufacturer, publisher = item.Publisher, + category = item.Category, crc = string.Empty, md5 = string.Empty, ripemd160 = string.Empty, @@ -3709,6 +3713,7 @@ namespace SabreTools.Library.DatFiles .Replace("%name%", name) .Replace("%manufacturer%", manufacturer) .Replace("%publisher%", publisher) + .Replace("%category%", category) .Replace("%crc%", crc) .Replace("%md5%", md5) .Replace("%ripemd160%", ripemd160) diff --git a/SabreTools.Library/DatFiles/Filter.cs b/SabreTools.Library/DatFiles/Filter.cs index c2cc7555..de9ef15c 100644 --- a/SabreTools.Library/DatFiles/Filter.cs +++ b/SabreTools.Library/DatFiles/Filter.cs @@ -15,138 +15,284 @@ namespace SabreTools.Library.DatFiles /// /// Represents the filtering operations that need to be performed on a set of items, usually a DAT /// - /// TODO: Can this use `Field` instead of explicit filters? + /// TODO: Can clever use of Filtering allow for easier external splitting methods? public class Filter { - #region Pubically facing variables + #region Private instance variables #region Machine Filters /// /// Include or exclude machine names /// - public FilterItem MachineName { get; set; } = new FilterItem(); + private FilterItem MachineName = new FilterItem(); /// - /// Include romof and cloneof when filtering machine names + /// Include or exclude machine comments /// - public FilterItem IncludeOfInGame { get; set; } = new FilterItem() { Neutral = false }; + private FilterItem Comment = new FilterItem(); /// /// Include or exclude machine descriptions /// - public FilterItem MachineDescription { get; set; } = new FilterItem(); + private FilterItem MachineDescription = new FilterItem(); /// - /// Include or exclude machine types + /// Include or exclude machine years /// - public FilterItem MachineTypes { get; set; } = new FilterItem() { Positive = MachineType.NULL, Negative = MachineType.NULL }; + private FilterItem Year = new FilterItem(); + + /// + /// Include or exclude machine manufacturers + /// + private FilterItem Manufacturer = new FilterItem(); + + /// + /// Include or exclude machine publishers + /// + private FilterItem Publisher = new FilterItem(); + + /// + /// Include or exclude machine categories + /// + private FilterItem Category = new FilterItem(); + + /// + /// Include or exclude machine romof + /// + private FilterItem RomOf = new FilterItem(); + + /// + /// Include or exclude machine cloneof + /// + private FilterItem CloneOf = new FilterItem(); + + /// + /// Include or exclude machine sampleof + /// + private FilterItem SampleOf = new FilterItem(); + + /// + /// Include or exclude items with the "Supported" tag + /// + private FilterItem Supported = new FilterItem() { Neutral = null }; + + /// + /// Include or exclude machine source file + /// + private FilterItem SourceFile = new FilterItem(); /// /// Include or exclude items with the "Runnable" tag /// - public FilterItem Runnable { get; set; } = new FilterItem() { Neutral = null }; + private FilterItem Runnable = new FilterItem() { Neutral = null }; + + /// + /// Include or exclude machine board + /// + private FilterItem Board = new FilterItem(); + + /// + /// Include or exclude machine rebuildto + /// + private FilterItem RebuildTo = new FilterItem(); + + // TODO: Machine.Devices - List + // TODO: Machine.SlotOptions - List + // TODO: Machine.Infos - List> + + /// + /// Include or exclude machine types + /// + private FilterItem MachineTypes = new FilterItem() { Positive = MachineType.NULL, Negative = MachineType.NULL }; #endregion #region DatItem Filters - /// - /// Include or exclude item names - /// - public FilterItem ItemName { get; set; } = new FilterItem(); - /// /// Include or exclude item types /// - public FilterItem ItemTypes { get; set; } = new FilterItem(); + private FilterItem ItemTypes = new FilterItem(); + + /// + /// Include or exclude item names + /// + private FilterItem ItemName = new FilterItem(); + + // TODO: DatItem.Features - List> + + /// + /// Include or exclude part names + /// + private FilterItem PartName = new FilterItem(); + + /// + /// Include or exclude part interfaces + /// + private FilterItem PartInterface = new FilterItem(); + + /// + /// Include or exclude area names + /// + private FilterItem AreaName = new FilterItem(); + + /// + /// Include or exclude area sizes + /// + /// Positive means "Greater than or equal", Negative means "Less than or equal", Neutral means "Equal" + private FilterItem AreaSize = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + + /// + /// Include or exclude items with the "Default" tag + /// + private FilterItem Default = new FilterItem() { Neutral = null }; + + /// + /// Include or exclude descriptions + /// + private FilterItem Description = new FilterItem(); /// /// Include or exclude item sizes /// /// Positive means "Greater than or equal", Negative means "Less than or equal", Neutral means "Equal" - public FilterItem Size { get; set; } = new FilterItem() { Positive = -1, Negative = -1, Neutral = -1 }; + private FilterItem Size = new FilterItem() { Positive = -1, Negative = -1, Neutral = -1 }; /// /// Include or exclude CRC32 hashes /// - public FilterItem CRC { get; set; } = new FilterItem(); + private FilterItem CRC = new FilterItem(); /// /// Include or exclude MD5 hashes /// - public FilterItem MD5 { get; set; } = new FilterItem(); + private FilterItem MD5 = new FilterItem(); #if NET_FRAMEWORK /// /// Include or exclude RIPEMD160 hashes /// - public FilterItem RIPEMD160 { get; set; } = new FilterItem(); + private FilterItem RIPEMD160 = new FilterItem(); #endif /// /// Include or exclude SHA-1 hashes /// - public FilterItem SHA1 { get; set; } = new FilterItem(); + private FilterItem SHA1 = new FilterItem(); /// /// Include or exclude SHA-256 hashes /// - public FilterItem SHA256 { get; set; } = new FilterItem(); + private FilterItem SHA256 = new FilterItem(); /// /// Include or exclude SHA-384 hashes /// - public FilterItem SHA384 { get; set; } = new FilterItem(); + private FilterItem SHA384 = new FilterItem(); /// /// Include or exclude SHA-512 hashes /// - public FilterItem SHA512 { get; set; } = new FilterItem(); + private FilterItem SHA512 = new FilterItem(); + + /// + /// Include or exclude merge tags + /// + private FilterItem MergeTag = new FilterItem(); + + /// + /// Include or exclude regions + /// + private FilterItem Region = new FilterItem(); + + /// + /// Include or exclude indexes + /// + private FilterItem Index = new FilterItem(); + + /// + /// Include or exclude items with the "Writable" tag + /// + private FilterItem Writable = new FilterItem() { Neutral = null }; + + /// + /// Include or exclude items with the "Writable" tag + /// + private FilterItem Optional = new FilterItem() { Neutral = null }; /// /// Include or exclude item statuses /// - public FilterItem ItemStatuses { get; set; } = new FilterItem() { Positive = ItemStatus.NULL, Negative = ItemStatus.NULL }; + private FilterItem Status = new FilterItem() { Positive = ItemStatus.NULL, Negative = ItemStatus.NULL }; + + /// + /// Include or exclude languages + /// + private FilterItem Language = new FilterItem(); + + /// + /// Include or exclude dates + /// + private FilterItem Date = new FilterItem(); + + /// + /// Include or exclude bioses + /// + private FilterItem Bios = new FilterItem(); + + /// + /// Include or exclude offsets + /// + private FilterItem Offset = new FilterItem(); #endregion - #region Manipulation Filters + #endregion // Private instance variables + + #region Pubically facing variables + + #region Manipulation Flags /// /// Clean all names to WoD standards /// - public FilterItem Clean { get; set; } = new FilterItem() { Neutral = false }; + public bool Clean { get; set; } /// /// Set Machine Description from Machine Name /// - public FilterItem DescriptionAsName { get; set; } = new FilterItem() { Neutral = false }; + public bool DescriptionAsName { get; set; } + + /// + /// Include romof and cloneof when filtering machine names + /// + public bool IncludeOfInGame { get; set; } /// /// Internally split a DatFile /// - public FilterItem InternalSplit { get; set; } = new FilterItem() { Neutral = SplitType.None }; + public SplitType InternalSplit { get; set; } /// /// Remove all unicode characters /// - public FilterItem RemoveUnicode { get; set; } = new FilterItem() { Neutral = false }; - - /// - /// Change all machine names to "!" - /// - public FilterItem Single { get; set; } = new FilterItem() { Neutral = false }; - - /// - /// Trim total machine and item name to not exceed NTFS limits - /// - public FilterItem Trim { get; set; } = new FilterItem() { Neutral = false }; + public bool RemoveUnicode { get; set; } /// /// Include root directory when determing trim sizes /// - public FilterItem Root { get; set; } = new FilterItem() { Neutral = null }; + public string Root { get; set; } + + /// + /// Change all machine names to "!" + /// + public bool Single { get; set; } + + /// + /// Trim total machine and item name to not exceed NTFS limits + /// + public bool Trim { get; set; } #endregion @@ -154,6 +300,456 @@ namespace SabreTools.Library.DatFiles #region Instance methods + #region Filter Population + + /// + /// Populate the filters object using a set of key:value filters + /// + /// List of key:value where ~key/!key is negated + public void PopulateFromList(List filters) + { + foreach (string filterPair in filters) + { + string filterPairTrimmed = filterPair.Trim('"', ' ', '\t'); + bool negate = filterPairTrimmed.StartsWith("!") + || filterPairTrimmed.StartsWith("~") + || filterPairTrimmed.StartsWith("not-"); + filterPairTrimmed = filterPairTrimmed.TrimStart('!', '~'); + filterPairTrimmed = filterPairTrimmed.StartsWith("not-") ? filterPairTrimmed.Substring(4) : filterPairTrimmed; + + string filterFieldString = filterPairTrimmed.Split(':')[0].ToLowerInvariant().Trim('"', ' ', '\t'); + string filterValue = filterPairTrimmed.Substring(filterFieldString.Length + 1).Trim('"', ' ', '\t'); + + Field filterField = filterFieldString.AsField(); + SetFilter(filterField, filterValue, negate); + } + } + + /// + /// Set multiple filters from key + /// + /// Key for the filter to be set + /// List of values for the filter + /// True if negative filter, false otherwise + public void SetFilter(Field key, List values, bool negate) + { + foreach (string value in values) + { + SetFilter(key, value, negate); + } + } + + /// + /// Set a single filter from key + /// + /// Key for the filter to be set + /// Value of the filter + /// True if negative filter, false otherwise + public void SetFilter(Field key, string value, bool negate) + { + switch (key) + { + #region Machine Filters + + case Field.MachineName: + if (negate) + MachineName.NegativeSet.Add(value); + else + MachineName.PositiveSet.Add(value); + break; + + case Field.Comment: + if (negate) + Comment.NegativeSet.Add(value); + else + Comment.PositiveSet.Add(value); + break; + + case Field.Description: + if (negate) + MachineDescription.NegativeSet.Add(value); + else + MachineDescription.PositiveSet.Add(value); + break; + + case Field.Year: + if (negate) + Year.NegativeSet.Add(value); + else + Year.PositiveSet.Add(value); + break; + + case Field.Manufacturer: + if (negate) + Manufacturer.NegativeSet.Add(value); + else + Manufacturer.PositiveSet.Add(value); + break; + + case Field.Publisher: + if (negate) + Publisher.NegativeSet.Add(value); + else + Publisher.PositiveSet.Add(value); + break; + + case Field.Category: + if (negate) + Category.NegativeSet.Add(value); + else + Category.PositiveSet.Add(value); + break; + + case Field.RomOf: + if (negate) + RomOf.NegativeSet.Add(value); + else + RomOf.PositiveSet.Add(value); + break; + + case Field.CloneOf: + if (negate) + CloneOf.NegativeSet.Add(value); + else + CloneOf.PositiveSet.Add(value); + break; + + case Field.SampleOf: + if (negate) + SampleOf.NegativeSet.Add(value); + else + SampleOf.PositiveSet.Add(value); + break; + + case Field.Supported: + if (negate || value.Equals("false", StringComparison.OrdinalIgnoreCase)) + Supported.Neutral = false; + else + Supported.Neutral = true; + break; + + case Field.SourceFile: + if (negate) + SourceFile.NegativeSet.Add(value); + else + SourceFile.PositiveSet.Add(value); + break; + + case Field.Runnable: + if (negate || value.Equals("false", StringComparison.OrdinalIgnoreCase)) + Runnable.Neutral = false; + else + Runnable.Neutral = true; + break; + + case Field.Board: + if (negate) + Board.NegativeSet.Add(value); + else + Board.PositiveSet.Add(value); + break; + + case Field.RebuildTo: + if (negate) + RebuildTo.NegativeSet.Add(value); + else + RebuildTo.PositiveSet.Add(value); + break; + + case Field.MachineType: + if (negate) + MachineTypes.Negative |= value.AsMachineType(); + else + MachineTypes.Positive |= value.AsMachineType(); + break; + + #endregion + + #region DatItem Filters + + case Field.ItemType: + if (value.AsItemType() == null) + return; + + if (negate) + ItemTypes.NegativeSet.Add(value); + else + ItemTypes.PositiveSet.Add(value); + break; + + case Field.Name: + if (negate) + ItemName.NegativeSet.Add(value); + else + ItemName.PositiveSet.Add(value); + break; + + case Field.PartName: + if (negate) + PartName.NegativeSet.Add(value); + else + PartName.PositiveSet.Add(value); + break; + + case Field.PartInterface: + if (negate) + PartInterface.NegativeSet.Add(value); + else + PartInterface.PositiveSet.Add(value); + break; + + case Field.AreaName: + if (negate) + AreaName.NegativeSet.Add(value); + else + AreaName.PositiveSet.Add(value); + break; + + case Field.AreaSize: + bool? asOperation = null; + if (value.StartsWith(">")) + asOperation = true; + else if (value.StartsWith("<")) + asOperation = false; + else if (value.StartsWith("=")) + asOperation = null; + + string areasizeString = value.TrimStart('>', '<', '='); + if (!Int64.TryParse(areasizeString, out long areasize)) + return; + + // Equal + if (asOperation == null && !negate) + { + AreaSize.Neutral = areasize; + } + + // Not Equal + else if (asOperation == null && negate) + { + AreaSize.Negative = areasize - 1; + AreaSize.Positive = areasize + 1; + } + + // Greater Than or Equal + else if (asOperation == true && !negate) + { + AreaSize.Positive = areasize; + } + + // Strictly Less Than + else if (asOperation == true && negate) + { + AreaSize.Negative = areasize - 1; + } + + // Less Than or Equal + else if (asOperation == false && !negate) + { + AreaSize.Negative = areasize; + } + + // Strictly Greater Than + else if (asOperation == false && negate) + { + AreaSize.Positive = areasize + 1; + } + + break; + + case Field.Default: + if (negate || value.Equals("false", StringComparison.OrdinalIgnoreCase)) + Default.Neutral = false; + else + Default.Neutral = true; + break; + + case Field.BiosDescription: + if (negate) + Description.NegativeSet.Add(value); + else + Description.PositiveSet.Add(value); + break; + + case Field.Size: + bool? sOperation = null; + if (value.StartsWith(">")) + sOperation = true; + else if (value.StartsWith("<")) + sOperation = false; + else if (value.StartsWith("=")) + sOperation = null; + + string sizeString = value.TrimStart('>', '<', '='); + if (!Int64.TryParse(sizeString, out long size)) + return; + + // Equal + if (sOperation == null && !negate) + { + Size.Neutral = size; + } + + // Not Equal + else if (sOperation == null && negate) + { + Size.Negative = size - 1; + Size.Positive = size + 1; + } + + // Greater Than or Equal + else if (sOperation == true && !negate) + { + Size.Positive = size; + } + + // Strictly Less Than + else if (sOperation == true && negate) + { + Size.Negative = size - 1; + } + + // Less Than or Equal + else if (sOperation == false && !negate) + { + Size.Negative = size; + } + + // Strictly Greater Than + else if (sOperation == false && negate) + { + Size.Positive = size + 1; + } + + break; + + case Field.CRC: + if (negate) + CRC.NegativeSet.Add(value); + else + CRC.PositiveSet.Add(value); + break; + + case Field.MD5: + if (negate) + MD5.NegativeSet.Add(value); + else + MD5.PositiveSet.Add(value); + break; + +#if NET_FRAMEWORK + case Field.RIPEMD160: + if (negate) + RIPEMD160.NegativeSet.Add(value); + else + RIPEMD160.PositiveSet.Add(value); + break; +#endif + + case Field.SHA1: + if (negate) + SHA1.NegativeSet.Add(value); + else + SHA1.PositiveSet.Add(value); + break; + + case Field.SHA256: + if (negate) + SHA256.NegativeSet.Add(value); + else + SHA256.PositiveSet.Add(value); + break; + + case Field.SHA384: + if (negate) + SHA384.NegativeSet.Add(value); + else + SHA384.PositiveSet.Add(value); + break; + + case Field.SHA512: + if (negate) + SHA512.NegativeSet.Add(value); + else + SHA512.PositiveSet.Add(value); + break; + + case Field.Merge: + if (negate) + MergeTag.NegativeSet.Add(value); + else + MergeTag.PositiveSet.Add(value); + break; + + case Field.Region: + if (negate) + Region.NegativeSet.Add(value); + else + Region.PositiveSet.Add(value); + break; + + case Field.Index: + if (negate) + Index.NegativeSet.Add(value); + else + Index.PositiveSet.Add(value); + break; + + case Field.Writable: + if (negate || value.Equals("false", StringComparison.OrdinalIgnoreCase)) + Writable.Neutral = false; + else + Writable.Neutral = true; + break; + + case Field.Optional: + if (negate || value.Equals("false", StringComparison.OrdinalIgnoreCase)) + Optional.Neutral = false; + else + Optional.Neutral = true; + break; + + case Field.Status: + if (negate) + Status.Negative |= value.AsItemStatus(); + else + Status.Positive |= value.AsItemStatus(); + break; + + case Field.Language: + if (negate) + Language.NegativeSet.Add(value); + else + Language.PositiveSet.Add(value); + break; + + case Field.Date: + if (negate) + Date.NegativeSet.Add(value); + else + Date.PositiveSet.Add(value); + break; + + case Field.Bios: + if (negate) + Bios.NegativeSet.Add(value); + else + Bios.PositiveSet.Add(value); + break; + + case Field.Offset: + if (negate) + Offset.NegativeSet.Add(value); + else + Offset.PositiveSet.Add(value); + break; + + #endregion + } + } + + #endregion + /// /// Filter a DatFile using the inputs /// @@ -177,7 +773,7 @@ namespace SabreTools.Library.DatFiles if (ItemPasses(item)) { // If we're stripping unicode characters, do so from all relevant things - if (this.RemoveUnicode.Neutral) + if (this.RemoveUnicode) { item.Name = Sanitizer.RemoveUnicodeCharacters(item.Name); item.MachineName = Sanitizer.RemoveUnicodeCharacters(item.MachineName); @@ -185,21 +781,21 @@ namespace SabreTools.Library.DatFiles } // If we're in cleaning mode, do so from all relevant things - if (this.Clean.Neutral) + if (this.Clean) { item.MachineName = Sanitizer.CleanGameName(item.MachineName); item.MachineDescription = Sanitizer.CleanGameName(item.MachineDescription); } // If we are in single game mode, rename all games - if (this.Single.Neutral) + if (this.Single) item.MachineName = "!"; // If we are in NTFS trim mode, trim the game name - if (this.Trim.Neutral) + if (this.Trim) { // Windows max name length is 260 - int usableLength = 260 - item.MachineName.Length - this.Root.Neutral.Length; + int usableLength = 260 - item.MachineName.Length - this.Root.Length; if (item.Name.Length > usableLength) { string ext = Path.GetExtension(item.Name); @@ -221,15 +817,15 @@ namespace SabreTools.Library.DatFiles } // Process description to machine name - if (this.DescriptionAsName.Neutral) + if (this.DescriptionAsName) MachineDescriptionToName(datFile); // If we are using tags from the DAT, set the proper input for split type unless overridden - if (useTags && this.InternalSplit.Neutral == SplitType.None) - this.InternalSplit.Neutral = datFile.DatHeader.ForceMerging.AsSplitType(); + if (useTags && this.InternalSplit == SplitType.None) + this.InternalSplit = datFile.DatHeader.ForceMerging.AsSplitType(); // Run internal splitting - ProcessSplitType(datFile, this.InternalSplit.Neutral); + ProcessSplitType(datFile, this.InternalSplit); // We remove any blanks, if we aren't supposed to have any if (!datFile.DatHeader.KeepEmptyGames) @@ -261,6 +857,114 @@ namespace SabreTools.Library.DatFiles return true; } + /// + /// Filter a DatFile outputting to a new DatFile + /// + /// DatFile to filter + /// True if DatFile tags override splitting, false otherwise + /// True if the DatFile was filtered, false on error + public DatFile FilterTo(DatFile datFile, bool useTags) + { + DatFile outDat = DatFile.Create(datFile.DatHeader); + + try + { + // Loop over every key in the dictionary + List keys = datFile.Keys; + foreach (string key in keys) + { + // For every item in the current key + List items = datFile[key]; + List newitems = new List(); + foreach (DatItem item in items) + { + // If the rom passes the filter, include it + if (ItemPasses(item)) + { + // If we're stripping unicode characters, do so from all relevant things + if (this.RemoveUnicode) + { + item.Name = Sanitizer.RemoveUnicodeCharacters(item.Name); + item.MachineName = Sanitizer.RemoveUnicodeCharacters(item.MachineName); + item.MachineDescription = Sanitizer.RemoveUnicodeCharacters(item.MachineDescription); + } + + // If we're in cleaning mode, do so from all relevant things + if (this.Clean) + { + item.MachineName = Sanitizer.CleanGameName(item.MachineName); + item.MachineDescription = Sanitizer.CleanGameName(item.MachineDescription); + } + + // If we are in single game mode, rename all games + if (this.Single) + item.MachineName = "!"; + + // If we are in NTFS trim mode, trim the game name + if (this.Trim) + { + // Windows max name length is 260 + int usableLength = 260 - item.MachineName.Length - this.Root.Length; + if (item.Name.Length > usableLength) + { + string ext = Path.GetExtension(item.Name); + item.Name = item.Name.Substring(0, usableLength - ext.Length); + item.Name += ext; + } + } + + // Lock the list and add the item back + lock (newitems) + { + newitems.Add(item); + } + } + } + + outDat.AddRange(key, newitems); + } + + // Process description to machine name + if (this.DescriptionAsName) + MachineDescriptionToName(outDat); + + // If we are using tags from the DAT, set the proper input for split type unless overridden + if (useTags && this.InternalSplit == SplitType.None) + this.InternalSplit = outDat.DatHeader.ForceMerging.AsSplitType(); + + // Run internal splitting + ProcessSplitType(outDat, this.InternalSplit); + + // We remove any blanks, if we aren't supposed to have any + if (!outDat.DatHeader.KeepEmptyGames) + { + foreach (string key in outDat.Keys) + { + List items = outDat[key]; + List newitems = items.Where(i => i.ItemType != ItemType.Blank).ToList(); + + outDat.Remove(key); + outDat.AddRange(key, newitems); + } + } + + // If we are removing scene dates, do that now + if (outDat.DatHeader.SceneDateStrip) + StripSceneDatesFromItems(outDat); + + // Run the one rom per game logic, if required + if (outDat.DatHeader.OneRom) + OneRomPerGame(outDat); + } + catch (Exception ex) + { + Globals.Logger.Error(ex.ToString()); + return null; + } + + return outDat; + } + /// /// Check to see if a DatItem passes the filter /// @@ -272,131 +976,11 @@ namespace SabreTools.Library.DatFiles if (item == null) return false; - // Filter on machine type - if (this.MachineTypes.MatchesPositive(MachineType.NULL, item.MachineType) == false) - return false; - if (this.MachineTypes.MatchesNegative(MachineType.NULL, item.MachineType) == true) - return false; - - // Filter on machine runability - if (this.Runnable.MatchesNeutral(null, item.Runnable) == false) - return false; - - // Take care of Rom and Disk specific differences - if (item.ItemType == ItemType.Rom) - { - Rom rom = (Rom)item; - - // Filter on status - if (this.ItemStatuses.MatchesPositive(ItemStatus.NULL, rom.ItemStatus) == false) - return false; - if (this.ItemStatuses.MatchesNegative(ItemStatus.NULL, rom.ItemStatus) == true) - return false; - - // Filter on rom size - if (this.Size.MatchesNeutral(-1, rom.Size) == false) - return false; - else if (this.Size.MatchesPositive(-1, rom.Size) == false) - return false; - else if (this.Size.MatchesNegative(-1, rom.Size) == false) - return false; - - // Filter on CRC - if (this.CRC.MatchesPositiveSet(rom.CRC) == false) - return false; - if (this.CRC.MatchesNegativeSet(rom.CRC) == true) - return false; - - // Filter on MD5 - if (this.MD5.MatchesPositiveSet(rom.MD5) == false) - return false; - if (this.MD5.MatchesNegativeSet(rom.MD5) == true) - return false; - -#if NET_FRAMEWORK - // Filter on RIPEMD160 - if (this.RIPEMD160.MatchesPositiveSet(rom.RIPEMD160) == false) - return false; - if (this.RIPEMD160.MatchesNegativeSet(rom.RIPEMD160) == true) - return false; -#endif - - // Filter on SHA-1 - if (this.SHA1.MatchesPositiveSet(rom.SHA1) == false) - return false; - if (this.SHA1.MatchesNegativeSet(rom.SHA1) == true) - return false; - - // Filter on SHA-256 - if (this.SHA256.MatchesPositiveSet(rom.SHA256) == false) - return false; - if (this.SHA256.MatchesNegativeSet(rom.SHA256) == true) - return false; - - // Filter on SHA-384 - if (this.SHA384.MatchesPositiveSet(rom.SHA384) == false) - return false; - if (this.SHA384.MatchesNegativeSet(rom.SHA384) == true) - return false; - - // Filter on SHA-512 - if (this.SHA512.MatchesPositiveSet(rom.SHA512) == false) - return false; - if (this.SHA512.MatchesNegativeSet(rom.SHA512) == true) - return false; - } - else if (item.ItemType == ItemType.Disk) - { - Disk rom = (Disk)item; - - // Filter on status - if (this.ItemStatuses.MatchesPositive(ItemStatus.NULL, rom.ItemStatus) == false) - return false; - if (this.ItemStatuses.MatchesNegative(ItemStatus.NULL, rom.ItemStatus) == true) - return false; - - // Filter on MD5 - if (this.MD5.MatchesPositiveSet(rom.MD5) == false) - return false; - if (this.MD5.MatchesNegativeSet(rom.MD5) == true) - return false; - -#if NET_FRAMEWORK - // Filter on RIPEMD160 - if (this.RIPEMD160.MatchesPositiveSet(rom.RIPEMD160) == false) - return false; - if (this.RIPEMD160.MatchesNegativeSet(rom.RIPEMD160) == true) - return false; -#endif - - // Filter on SHA-1 - if (this.SHA1.MatchesPositiveSet(rom.SHA1) == false) - return false; - if (this.SHA1.MatchesNegativeSet(rom.SHA1) == true) - return false; - - // Filter on SHA-256 - if (this.SHA256.MatchesPositiveSet(rom.SHA256) == false) - return false; - if (this.SHA256.MatchesNegativeSet(rom.SHA256) == true) - return false; - - // Filter on SHA-384 - if (this.SHA384.MatchesPositiveSet(rom.SHA384) == false) - return false; - if (this.SHA384.MatchesNegativeSet(rom.SHA384) == true) - return false; - - // Filter on SHA-512 - if (this.SHA512.MatchesPositiveSet(rom.SHA512) == false) - return false; - if (this.SHA512.MatchesNegativeSet(rom.SHA512) == true) - return false; - } + #region Machine Filters // Filter on machine name bool? machineNameFound = this.MachineName.MatchesPositiveSet(item.MachineName); - if (this.IncludeOfInGame.Neutral) + if (this.IncludeOfInGame) { machineNameFound |= (this.MachineName.MatchesPositiveSet(item.CloneOf) == true); machineNameFound |= (this.MachineName.MatchesPositiveSet(item.RomOf) == true); @@ -405,7 +989,7 @@ namespace SabreTools.Library.DatFiles return false; machineNameFound = this.MachineName.MatchesNegativeSet(item.MachineName); - if (this.IncludeOfInGame.Neutral) + if (this.IncludeOfInGame) { machineNameFound |= (this.MachineName.MatchesNegativeSet(item.CloneOf) == true); machineNameFound |= (this.MachineName.MatchesNegativeSet(item.RomOf) == true); @@ -413,19 +997,98 @@ namespace SabreTools.Library.DatFiles if (machineNameFound == false) return false; + // Filter on comment + if (this.Comment.MatchesPositiveSet(item.Comment) == false) + return false; + if (this.Comment.MatchesNegativeSet(item.Comment) == true) + return false; + // Filter on machine description if (this.MachineDescription.MatchesPositiveSet(item.MachineDescription) == false) return false; if (this.MachineDescription.MatchesNegativeSet(item.MachineDescription) == true) return false; - // Filter on item name - if (this.ItemName.MatchesPositiveSet(item.Name) == false) + // Filter on year + if (this.Year.MatchesPositiveSet(item.Year) == false) return false; - if (this.ItemName.MatchesNegativeSet(item.Name) == true) + if (this.Year.MatchesNegativeSet(item.Year) == true) return false; + // Filter on manufacturer + if (this.Manufacturer.MatchesPositiveSet(item.Manufacturer) == false) + return false; + if (this.Manufacturer.MatchesNegativeSet(item.Manufacturer) == true) + return false; + + // Filter on publisher + if (this.Publisher.MatchesPositiveSet(item.Publisher) == false) + return false; + if (this.Publisher.MatchesNegativeSet(item.Publisher) == true) + return false; + + // Filter on category + if (this.Category.MatchesPositiveSet(item.Category) == false) + return false; + if (this.Category.MatchesNegativeSet(item.Category) == true) + return false; + + // Filter on romof + if (this.RomOf.MatchesPositiveSet(item.RomOf) == false) + return false; + if (this.RomOf.MatchesNegativeSet(item.RomOf) == true) + return false; + + // Filter on cloneof + if (this.CloneOf.MatchesPositiveSet(item.CloneOf) == false) + return false; + if (this.CloneOf.MatchesNegativeSet(item.CloneOf) == true) + return false; + + // Filter on sampleof + if (this.SampleOf.MatchesPositiveSet(item.SampleOf) == false) + return false; + if (this.SampleOf.MatchesNegativeSet(item.SampleOf) == true) + return false; + + // Filter on supported + if (this.Supported.MatchesNeutral(null, item.Supported) == false) + return false; + + // Filter on source file + if (this.SourceFile.MatchesPositiveSet(item.SourceFile) == false) + return false; + if (this.SourceFile.MatchesNegativeSet(item.SourceFile) == true) + return false; + + // Filter on runnable + if (this.Runnable.MatchesNeutral(null, item.Runnable) == false) + return false; + + // Filter on board + if (this.Board.MatchesPositiveSet(item.Board) == false) + return false; + if (this.Board.MatchesNegativeSet(item.Board) == true) + return false; + + // Filter on rebuildto + if (this.RebuildTo.MatchesPositiveSet(item.RebuildTo) == false) + return false; + if (this.RebuildTo.MatchesNegativeSet(item.RebuildTo) == true) + return false; + + // Filter on machine type + if (this.MachineTypes.MatchesPositive(MachineType.NULL, item.MachineType) == false) + return false; + if (this.MachineTypes.MatchesNegative(MachineType.NULL, item.MachineType) == true) + return false; + + #endregion + + #region DatItem Filters + // Filter on item type + // TODO: Remove default filtering at some point if (this.ItemTypes.PositiveSet.Count == 0 && this.ItemTypes.NegativeSet.Count == 0 && item.ItemType != ItemType.Rom && item.ItemType != ItemType.Disk && item.ItemType != ItemType.Blank) return false; @@ -434,6 +1097,268 @@ namespace SabreTools.Library.DatFiles if (this.ItemTypes.MatchesNegativeSet(item.ItemType.ToString()) == true) return false; + // Filter on item name + if (this.ItemName.MatchesPositiveSet(item.Name) == false) + return false; + if (this.ItemName.MatchesNegativeSet(item.Name) == true) + return false; + + // Filter on part name + if (this.PartName.MatchesPositiveSet(item.PartName) == false) + return false; + if (this.PartName.MatchesNegativeSet(item.PartName) == true) + return false; + + // Filter on part interface + if (this.PartInterface.MatchesPositiveSet(item.PartInterface) == false) + return false; + if (this.PartInterface.MatchesNegativeSet(item.PartInterface) == true) + return false; + + // Filter on area name + if (this.AreaName.MatchesPositiveSet(item.AreaName) == false) + return false; + if (this.AreaName.MatchesNegativeSet(item.AreaName) == true) + return false; + + // Filter on area size + if (this.AreaSize.MatchesNeutral(null, item.AreaSize) == false) + return false; + else if (this.AreaSize.MatchesPositive(null, item.AreaSize) == false) + return false; + else if (this.AreaSize.MatchesNegative(null, item.AreaSize) == false) + return false; + + // Take care of item-specific differences + switch (item.ItemType) + { + case ItemType.Archive: + // Archive has no special fields + break; + + case ItemType.BiosSet: + BiosSet biosSet = (BiosSet)item; + + // Filter on description + if (this.Description.MatchesNeutral(null, biosSet.Description) == false) + return false; + + // Filter on default + if (this.Default.MatchesNeutral(null, biosSet.Default) == false) + return false; + + break; + + case ItemType.Blank: + // Blank has no special fields + break; + + case ItemType.Disk: + Disk disk = (Disk)item; + + // Filter on MD5 + if (this.MD5.MatchesPositiveSet(disk.MD5) == false) + return false; + if (this.MD5.MatchesNegativeSet(disk.MD5) == true) + return false; + +#if NET_FRAMEWORK + // Filter on RIPEMD160 + if (this.RIPEMD160.MatchesPositiveSet(disk.RIPEMD160) == false) + return false; + if (this.RIPEMD160.MatchesNegativeSet(disk.RIPEMD160) == true) + return false; +#endif + + // Filter on SHA-1 + if (this.SHA1.MatchesPositiveSet(disk.SHA1) == false) + return false; + if (this.SHA1.MatchesNegativeSet(disk.SHA1) == true) + return false; + + // Filter on SHA-256 + if (this.SHA256.MatchesPositiveSet(disk.SHA256) == false) + return false; + if (this.SHA256.MatchesNegativeSet(disk.SHA256) == true) + return false; + + // Filter on SHA-384 + if (this.SHA384.MatchesPositiveSet(disk.SHA384) == false) + return false; + if (this.SHA384.MatchesNegativeSet(disk.SHA384) == true) + return false; + + // Filter on SHA-512 + if (this.SHA512.MatchesPositiveSet(disk.SHA512) == false) + return false; + if (this.SHA512.MatchesNegativeSet(disk.SHA512) == true) + return false; + + // Filter on merge tag + if (this.MergeTag.MatchesPositiveSet(disk.MergeTag) == false) + return false; + if (this.MergeTag.MatchesNegativeSet(disk.MergeTag) == true) + return false; + + // Filter on region + if (this.Region.MatchesPositiveSet(disk.Region) == false) + return false; + if (this.Region.MatchesNegativeSet(disk.Region) == true) + return false; + + // Filter on index + if (this.Index.MatchesPositiveSet(disk.Index) == false) + return false; + if (this.Index.MatchesNegativeSet(disk.Index) == true) + return false; + + // Filter on writable + if (this.Writable.MatchesNeutral(null, disk.Writable) == false) + return false; + + // Filter on status + if (this.Status.MatchesPositive(ItemStatus.NULL, disk.ItemStatus) == false) + return false; + if (this.Status.MatchesNegative(ItemStatus.NULL, disk.ItemStatus) == true) + return false; + + // Filter on optional + if (this.Optional.MatchesNeutral(null, disk.Optional) == false) + return false; + + break; + + case ItemType.Release: + Release release = (Release)item; + + // Filter on region + if (this.Region.MatchesPositiveSet(release.Region) == false) + return false; + if (this.Region.MatchesNegativeSet(release.Region) == true) + return false; + + // Filter on language + if (this.Language.MatchesPositiveSet(release.Language) == false) + return false; + if (this.Language.MatchesNegativeSet(release.Language) == true) + return false; + + // Filter on date + if (this.Date.MatchesPositiveSet(release.Date) == false) + return false; + if (this.Date.MatchesNegativeSet(release.Date) == true) + return false; + + // Filter on default + if (this.Default.MatchesNeutral(null, release.Default) == false) + return false; + + break; + + case ItemType.Rom: + Rom rom = (Rom)item; + + // Filter on bios + if (this.Bios.MatchesPositiveSet(rom.Bios) == false) + return false; + if (this.Bios.MatchesNegativeSet(rom.Bios) == true) + return false; + + // Filter on rom size + if (this.Size.MatchesNeutral(-1, rom.Size) == false) + return false; + else if (this.Size.MatchesPositive(-1, rom.Size) == false) + return false; + else if (this.Size.MatchesNegative(-1, rom.Size) == false) + return false; + + // Filter on CRC + if (this.CRC.MatchesPositiveSet(rom.CRC) == false) + return false; + if (this.CRC.MatchesNegativeSet(rom.CRC) == true) + return false; + + // Filter on MD5 + if (this.MD5.MatchesPositiveSet(rom.MD5) == false) + return false; + if (this.MD5.MatchesNegativeSet(rom.MD5) == true) + return false; + +#if NET_FRAMEWORK + // Filter on RIPEMD160 + if (this.RIPEMD160.MatchesPositiveSet(rom.RIPEMD160) == false) + return false; + if (this.RIPEMD160.MatchesNegativeSet(rom.RIPEMD160) == true) + return false; +#endif + + // Filter on SHA-1 + if (this.SHA1.MatchesPositiveSet(rom.SHA1) == false) + return false; + if (this.SHA1.MatchesNegativeSet(rom.SHA1) == true) + return false; + + // Filter on SHA-256 + if (this.SHA256.MatchesPositiveSet(rom.SHA256) == false) + return false; + if (this.SHA256.MatchesNegativeSet(rom.SHA256) == true) + return false; + + // Filter on SHA-384 + if (this.SHA384.MatchesPositiveSet(rom.SHA384) == false) + return false; + if (this.SHA384.MatchesNegativeSet(rom.SHA384) == true) + return false; + + // Filter on SHA-512 + if (this.SHA512.MatchesPositiveSet(rom.SHA512) == false) + return false; + if (this.SHA512.MatchesNegativeSet(rom.SHA512) == true) + return false; + + // Filter on merge tag + if (this.MergeTag.MatchesPositiveSet(rom.MergeTag) == false) + return false; + if (this.MergeTag.MatchesNegativeSet(rom.MergeTag) == true) + return false; + + // Filter on region + if (this.Region.MatchesPositiveSet(rom.Region) == false) + return false; + if (this.Region.MatchesNegativeSet(rom.Region) == true) + return false; + + // Filter on offset + if (this.Offset.MatchesPositiveSet(rom.Offset) == false) + return false; + if (this.Offset.MatchesNegativeSet(rom.Offset) == true) + return false; + + // Filter on date + if (this.Date.MatchesPositiveSet(rom.Date) == false) + return false; + if (this.Date.MatchesNegativeSet(rom.Date) == true) + return false; + + // Filter on status + if (this.Status.MatchesPositive(ItemStatus.NULL, rom.ItemStatus) == false) + return false; + if (this.Status.MatchesNegative(ItemStatus.NULL, rom.ItemStatus) == true) + return false; + + // Filter on optional + if (this.Optional.MatchesNeutral(null, rom.Optional) == false) + return false; + + break; + + case ItemType.Sample: + // Sample has no special fields + break; + } + + #endregion + return true; } @@ -639,7 +1564,7 @@ namespace SabreTools.Library.DatFiles continue; // If the game (is/is not) a bios, we want to continue - if (dev ^ (datFile[game][0].MachineType.HasFlag(MachineType.Device))) + if (dev ^ (datFile[game][0].MachineType.HasFlag(Data.MachineType.Device))) continue; // If the game has no devices, we continue @@ -801,14 +1726,14 @@ namespace SabreTools.Library.DatFiles foreach (DatItem item in items) { // If the disk doesn't have a valid merge tag OR the merged file doesn't exist in the parent, then add it - if (item.ItemType == ItemType.Disk && (((Disk)item).MergeTag == null || !datFile[parent].Select(i => i.Name).Contains(((Disk)item).MergeTag))) + if (item.ItemType == Data.ItemType.Disk && (((Disk)item).MergeTag == null || !datFile[parent].Select(i => i.Name).Contains(((Disk)item).MergeTag))) { item.CopyMachineInformation(copyFrom); datFile.Add(parent, item); } // Otherwise, if the parent doesn't already contain the non-disk (or a merge-equivalent), add it - else if (item.ItemType != ItemType.Disk && !datFile[parent].Contains(item)) + else if (item.ItemType != Data.ItemType.Disk && !datFile[parent].Contains(item)) { // Rename the child so it's in a subfolder item.Name = $"{item.MachineName}\\{item.Name}"; @@ -836,8 +1761,8 @@ namespace SabreTools.Library.DatFiles foreach (string game in games) { if (datFile[game].Count > 0 - && (datFile[game][0].MachineType.HasFlag(MachineType.Bios) - || datFile[game][0].MachineType.HasFlag(MachineType.Device))) + && (datFile[game][0].MachineType.HasFlag(Data.MachineType.Bios) + || datFile[game][0].MachineType.HasFlag(Data.MachineType.Device))) { datFile.Remove(game); } @@ -860,7 +1785,7 @@ namespace SabreTools.Library.DatFiles continue; // If the game (is/is not) a bios, we want to continue - if (bios ^ datFile[game][0].MachineType.HasFlag(MachineType.Bios)) + if (bios ^ datFile[game][0].MachineType.HasFlag(Data.MachineType.Bios)) continue; // Determine if the game has a parent or not diff --git a/SabreTools.Library/DatFiles/Json.cs b/SabreTools.Library/DatFiles/Json.cs index 2af6f384..43846891 100644 --- a/SabreTools.Library/DatFiles/Json.cs +++ b/SabreTools.Library/DatFiles/Json.cs @@ -317,6 +317,10 @@ namespace SabreTools.Library.DatFiles machine.Publisher = jtr.ReadAsString(); break; + case "category": + machine.Category = jtr.ReadAsString(); + break; + case "romof": machine.RomOf = jtr.ReadAsString(); break; @@ -1023,6 +1027,11 @@ namespace SabreTools.Library.DatFiles jtw.WritePropertyName("publisher"); jtw.WriteValue(datItem.Publisher); } + if (!string.IsNullOrWhiteSpace(datItem.GetField(Field.Category, DatHeader.ExcludeFields))) + { + jtw.WritePropertyName("category"); + jtw.WriteValue(datItem.Category); + } if (!string.IsNullOrWhiteSpace(datItem.GetField(Field.RomOf, DatHeader.ExcludeFields)) && !string.Equals(datItem.MachineName, datItem.RomOf, StringComparison.OrdinalIgnoreCase)) { jtw.WritePropertyName("romof"); diff --git a/SabreTools.Library/DatFiles/Listxml.cs b/SabreTools.Library/DatFiles/Listxml.cs index 72aafb96..f3330ac6 100644 --- a/SabreTools.Library/DatFiles/Listxml.cs +++ b/SabreTools.Library/DatFiles/Listxml.cs @@ -716,6 +716,8 @@ namespace SabreTools.Library.DatFiles xtw.WriteElementString("year", datItem.Year); if (!string.IsNullOrWhiteSpace(datItem.GetField(Field.Publisher, DatHeader.ExcludeFields))) xtw.WriteElementString("publisher", datItem.Publisher); + if (!string.IsNullOrWhiteSpace(datItem.GetField(Field.Category, DatHeader.ExcludeFields))) + xtw.WriteElementString("category", datItem.Category); if (!DatHeader.ExcludeFields[(int)Field.Infos] && datItem.Infos != null && datItem.Infos.Count > 0) { diff --git a/SabreTools.Library/DatFiles/Logiqx.cs b/SabreTools.Library/DatFiles/Logiqx.cs index 9974af4e..9cda841d 100644 --- a/SabreTools.Library/DatFiles/Logiqx.cs +++ b/SabreTools.Library/DatFiles/Logiqx.cs @@ -377,6 +377,10 @@ namespace SabreTools.Library.DatFiles machine.Publisher = reader.ReadElementContentAsString(); break; + case "category": // Not technically supported but used by some legacy DATs + machine.Category = reader.ReadElementContentAsString(); + break; + case "trurip": // This is special metadata unique to TruRip ReadTruRip(reader.ReadSubtree(), machine); @@ -588,7 +592,7 @@ namespace SabreTools.Library.DatFiles break; case "genre": - reader.ReadElementContentAsString(); + machine.Category = reader.ReadElementContentAsString(); break; case "subgenre": @@ -894,6 +898,8 @@ namespace SabreTools.Library.DatFiles xtw.WriteElementString("publisher", datItem.Publisher); if (!string.IsNullOrWhiteSpace(datItem.GetField(Field.Manufacturer, DatHeader.ExcludeFields))) xtw.WriteElementString("manufacturer", datItem.Manufacturer); + if (!string.IsNullOrWhiteSpace(datItem.GetField(Field.Category, DatHeader.ExcludeFields))) + xtw.WriteElementString("category", datItem.Category); xtw.Flush(); } diff --git a/SabreTools.Library/DatFiles/SeparatedValue.cs b/SabreTools.Library/DatFiles/SeparatedValue.cs index 0d69e64f..7525dbb7 100644 --- a/SabreTools.Library/DatFiles/SeparatedValue.cs +++ b/SabreTools.Library/DatFiles/SeparatedValue.cs @@ -213,6 +213,10 @@ namespace SabreTools.Library.DatFiles machine.Publisher = value; break; + case "Machine.Category": + machine.Category = value; + break; + case "Machine.RomOf": machine.RomOf = value; break; diff --git a/SabreTools.Library/DatFiles/SoftwareList.cs b/SabreTools.Library/DatFiles/SoftwareList.cs index 0a272730..9c8b73d0 100644 --- a/SabreTools.Library/DatFiles/SoftwareList.cs +++ b/SabreTools.Library/DatFiles/SoftwareList.cs @@ -174,6 +174,10 @@ namespace SabreTools.Library.DatFiles machine.Publisher = reader.ReadElementContentAsString(); break; + case "category": + machine.Category = reader.ReadElementContentAsString(); + break; + case "info": machine.Infos.Add(new KeyValuePair(reader.GetAttribute("name"), reader.GetAttribute("value"))); reader.Read(); @@ -717,6 +721,8 @@ namespace SabreTools.Library.DatFiles xtw.WriteElementString("year", datItem.Year); if (!string.IsNullOrWhiteSpace(datItem.GetField(Field.Publisher, DatHeader.ExcludeFields))) xtw.WriteElementString("publisher", datItem.Publisher); + if (!string.IsNullOrWhiteSpace(datItem.GetField(Field.Category, DatHeader.ExcludeFields))) + xtw.WriteElementString("category", datItem.Category); if (!DatHeader.ExcludeFields[(int)Field.Infos] && datItem.Infos != null && datItem.Infos.Count > 0) { diff --git a/SabreTools.Library/DatItems/Archive.cs b/SabreTools.Library/DatItems/Archive.cs index aafb1ee4..aee0343e 100644 --- a/SabreTools.Library/DatItems/Archive.cs +++ b/SabreTools.Library/DatItems/Archive.cs @@ -32,6 +32,7 @@ namespace SabreTools.Library.DatItems Supported = this.Supported, Publisher = this.Publisher, + Category = this.Category, Infos = this.Infos, PartName = this.PartName, PartInterface = this.PartInterface, diff --git a/SabreTools.Library/DatItems/BiosSet.cs b/SabreTools.Library/DatItems/BiosSet.cs index 775aa76d..1f745bab 100644 --- a/SabreTools.Library/DatItems/BiosSet.cs +++ b/SabreTools.Library/DatItems/BiosSet.cs @@ -49,6 +49,7 @@ namespace SabreTools.Library.DatItems Supported = this.Supported, Publisher = this.Publisher, + Category = this.Category, Infos = this.Infos, PartName = this.PartName, PartInterface = this.PartInterface, diff --git a/SabreTools.Library/DatItems/Blank.cs b/SabreTools.Library/DatItems/Blank.cs index b52295c2..993df723 100644 --- a/SabreTools.Library/DatItems/Blank.cs +++ b/SabreTools.Library/DatItems/Blank.cs @@ -32,6 +32,7 @@ namespace SabreTools.Library.DatItems Supported = this.Supported, Publisher = this.Publisher, + Category = this.Category, Infos = this.Infos, PartName = this.PartName, PartInterface = this.PartInterface, diff --git a/SabreTools.Library/DatItems/DatItem.cs b/SabreTools.Library/DatItems/DatItem.cs index 2bb7d6d2..633ac29c 100644 --- a/SabreTools.Library/DatItems/DatItem.cs +++ b/SabreTools.Library/DatItems/DatItem.cs @@ -206,6 +206,32 @@ namespace SabreTools.Library.DatItems } } + /// + /// Machine category, if available + /// + [JsonIgnore] + public string Category + { + get + { + if (_machine == null) + { + _machine = new Machine(); + } + + return _machine.Category; + } + set + { + if (_machine == null) + { + _machine = new Machine(); + } + + _machine.Category = value; + } + } + /// /// Machine romof parent /// @@ -633,6 +659,9 @@ namespace SabreTools.Library.DatItems case Field.Publisher: fieldValue = this.Publisher; break; + case Field.Category: + fieldValue = this.Category; + break; case Field.RomOf: fieldValue = this.RomOf; break; diff --git a/SabreTools.Library/DatItems/Disk.cs b/SabreTools.Library/DatItems/Disk.cs index 615e2a29..04b46b3d 100644 --- a/SabreTools.Library/DatItems/Disk.cs +++ b/SabreTools.Library/DatItems/Disk.cs @@ -173,6 +173,7 @@ namespace SabreTools.Library.DatItems Supported = this.Supported, Publisher = this.Publisher, + Category = this.Category, Infos = this.Infos, PartName = this.PartName, PartInterface = this.PartInterface, @@ -241,6 +242,7 @@ namespace SabreTools.Library.DatItems Year = this.Year, Manufacturer = this.Manufacturer, Publisher = this.Publisher, + Category = this.Category, RomOf = this.RomOf, CloneOf = this.CloneOf, SampleOf = this.SampleOf, diff --git a/SabreTools.Library/DatItems/Machine.cs b/SabreTools.Library/DatItems/Machine.cs index 89ab533b..3b10f24a 100644 --- a/SabreTools.Library/DatItems/Machine.cs +++ b/SabreTools.Library/DatItems/Machine.cs @@ -49,6 +49,12 @@ namespace SabreTools.Library.DatItems [JsonProperty("publisher")] public string Publisher { get; set; } + /// + /// Category, if available + /// + [JsonProperty("category")] + public string Category { get; set; } + /// /// fomof parent /// @@ -138,6 +144,7 @@ namespace SabreTools.Library.DatItems Year = null; Manufacturer = null; Publisher = null; + Category = null; RomOf = null; CloneOf = null; SampleOf = null; @@ -165,6 +172,7 @@ namespace SabreTools.Library.DatItems Year = null; Manufacturer = null; Publisher = null; + Category = null; RomOf = null; CloneOf = null; SampleOf = null; @@ -197,6 +205,7 @@ namespace SabreTools.Library.DatItems Year = this.Year, Manufacturer = this.Manufacturer, Publisher = this.Publisher, + Category = this.Category, RomOf = this.RomOf, CloneOf = this.CloneOf, SampleOf = this.SampleOf, diff --git a/SabreTools.Library/DatItems/Release.cs b/SabreTools.Library/DatItems/Release.cs index b21246b8..fb848720 100644 --- a/SabreTools.Library/DatItems/Release.cs +++ b/SabreTools.Library/DatItems/Release.cs @@ -65,6 +65,7 @@ namespace SabreTools.Library.DatItems Supported = this.Supported, Publisher = this.Publisher, + Category = this.Category, Infos = this.Infos, PartName = this.PartName, PartInterface = this.PartInterface, diff --git a/SabreTools.Library/DatItems/Rom.cs b/SabreTools.Library/DatItems/Rom.cs index bef91677..2ebd12cf 100644 --- a/SabreTools.Library/DatItems/Rom.cs +++ b/SabreTools.Library/DatItems/Rom.cs @@ -220,6 +220,7 @@ namespace SabreTools.Library.DatItems Supported = this.Supported, Publisher = this.Publisher, + Category = this.Category, Infos = this.Infos, PartName = this.PartName, PartInterface = this.PartInterface, diff --git a/SabreTools.Library/DatItems/Sample.cs b/SabreTools.Library/DatItems/Sample.cs index 09e1275f..ad036ad7 100644 --- a/SabreTools.Library/DatItems/Sample.cs +++ b/SabreTools.Library/DatItems/Sample.cs @@ -32,6 +32,7 @@ namespace SabreTools.Library.DatItems Supported = this.Supported, Publisher = this.Publisher, + Category = this.Category, Infos = this.Infos, PartName = this.PartName, PartInterface = this.PartInterface, diff --git a/SabreTools.Library/Data/Enums.cs b/SabreTools.Library/Data/Enums.cs index 8f89d17e..42a4e3e9 100644 --- a/SabreTools.Library/Data/Enums.cs +++ b/SabreTools.Library/Data/Enums.cs @@ -261,7 +261,6 @@ Game, } - /// /// Determines the DAT deduplication type /// @@ -351,6 +350,7 @@ NULL = 0, // Generic DatItem + ItemType, Name, PartName, PartInterface, @@ -365,6 +365,7 @@ Year, Manufacturer, Publisher, + Category, RomOf, CloneOf, SampleOf, diff --git a/SabreTools.Library/README.1ST b/SabreTools.Library/README.1ST index 7f9e890f..634b4bbe 100644 --- a/SabreTools.Library/README.1ST +++ b/SabreTools.Library/README.1ST @@ -334,6 +334,26 @@ Options: compare against the input DATs. This flag forces all CHDs to be treated like regular files. + -fi=, --filter= Filter a game/rom field with the given value(s) + Filter any valid item or machine field from inputs. Filters are input + in the form 'key:value' or '!key:value', where the '!' signifies 'not' + matching. Numeric values may also prefix the 'value' with '>', '<', or + '=' accordingly. Key examples include: romof, category, and game. + Additionally, the user can specify an exact match or full C#-style + regex for pattern matching. Multiple instances of this flag are + allowed. + + -cat=, --category-filter= Filter by category + Include only items with this category in the output. Additionally, + the user can specify an exact match or full C#-style regex for + pattern matching. Multiple instances of this flag are allowed. + + -ncat=, --not-category= Filter by not category + Include only items without this category in the output. + Additionally, the user can specify an exact match or full C#-style + regex for pattern matching. Multiple instances of this flag are + allowed. + -gn=, --game-name= Filter by game name Include only items with this game name in the output. Additionally, the user can specify an exact match or full C#-style regex for @@ -950,6 +970,7 @@ Options: - %name% - Replaced with the Rom name - %manufacturer% - Replaced with game Manufacturer - %publisher% - Replaced with game Publisher + - %category% - Replaced with game Category - %crc% - Replaced with the CRC - %md5% - Replaced with the MD5 - %ripemd160% - Replaced with the RIPEMD160 (.NET Framework 4.8 only) @@ -1276,6 +1297,26 @@ Options: second time, this will skip writing it. This can often speed up the output process. [Both diff-cascade and diff-reverse-cascade] + -fi=, --filter= Filter a game/rom field with the given value(s) + Filter any valid item or machine field from inputs. Filters are input + in the form 'key:value' or '!key:value', where the '!' signifies 'not' + matching. Numeric values may also prefix the 'value' with '>', '<', or + '=' accordingly. Key examples include: romof, category, and game. + Additionally, the user can specify an exact match or full C#-style + regex for pattern matching. Multiple instances of this flag are + allowed. + + -cat=, --category-filter= Filter by category + Include only items with this category in the output. Additionally, + the user can specify an exact match or full C#-style regex for + pattern matching. Multiple instances of this flag are allowed. + + -ncat=, --not-category= Filter by not category + Include only items without this category in the output. + Additionally, the user can specify an exact match or full C#-style + regex for pattern matching. Multiple instances of this flag are + allowed. + -gn=, --game-name= Filter by game name Include only items with this game name in the output. Additionally, the user can specify an exact match or full C#-style regex for @@ -1533,6 +1574,26 @@ Options: parent sets based on the cloneof and romof tags as well as device references. This is incompatible with the other --dat-X flags. + -fi=, --filter= Filter a game/rom field with the given value(s) + Filter any valid item or machine field from inputs. Filters are input + in the form 'key:value' or '!key:value', where the '!' signifies 'not' + matching. Numeric values may also prefix the 'value' with '>', '<', or + '=' accordingly. Key examples include: romof, category, and game. + Additionally, the user can specify an exact match or full C#-style + regex for pattern matching. Multiple instances of this flag are + allowed. + + -cat=, --category-filter= Filter by category + Include only items with this category in the output. Additionally, + the user can specify an exact match or full C#-style regex for + pattern matching. Multiple instances of this flag are allowed. + + -ncat=, --not-category= Filter by not category + Include only items without this category in the output. + Additionally, the user can specify an exact match or full C#-style + regex for pattern matching. Multiple instances of this flag are + allowed. + -gn=, --game-name= Filter by game name Include only items with this game name in the output. Additionally, the user can specify an exact match or full C#-style regex for diff --git a/SabreTools.Library/Tools/Converters.cs b/SabreTools.Library/Tools/Converters.cs index 899f0d30..14fcde20 100644 --- a/SabreTools.Library/Tools/Converters.cs +++ b/SabreTools.Library/Tools/Converters.cs @@ -122,45 +122,78 @@ namespace SabreTools.Library.Tools switch (input?.ToLowerInvariant()) { case "areaname": + case "area-name": return Field.AreaName; case "areasize": + case "area-size": return Field.AreaSize; case "bios": return Field.Bios; case "biosdescription": - case "bios description": + case "bios-description": case "biossetdescription": - case "biosset description": - case "bios set description": + case "biosset-description": + case "bios-set-description": return Field.BiosDescription; case "board": return Field.Board; + case "category": + case "machinecategory": + case "machine-category": + return Field.Category; case "cloneof": return Field.CloneOf; case "comment": return Field.Comment; case "crc": + case "crc32": return Field.CRC; case "default": return Field.Default; case "date": return Field.Date; + case "desc": case "description": + case "gamedesc": + case "gamedescription": + case "game-description": + case "machinedesc": + case "machinedescription": + case "machine-description": return Field.Description; case "devices": return Field.Devices; + case "equal": + case "greater": + case "less": + case "size": + return Field.Size; case "features": return Field.Features; case "gamename": case "machinename": return Field.MachineName; case "gametype": + case "game-type": case "machinetype": + case "machine-type": return Field.MachineType; case "index": return Field.Index; case "infos": return Field.Infos; + case "itemname": + case "item-name": + case "name": + return Field.Name; + case "itemtatus": + case "item-status": + case "status": + return Field.Status; + case "itemtype": + case "item-type": + case "type": + return Field.ItemType; case "language": return Field.Language; case "manufacturer": @@ -168,16 +201,18 @@ namespace SabreTools.Library.Tools case "md5": return Field.MD5; case "merge": + case "mergetag": + case "merge-tag": return Field.Merge; - case "name": - return Field.Name; case "offset": return Field.Offset; case "optional": return Field.Optional; case "partinterface": + case "part-interface": return Field.PartInterface; case "partname": + case "part-name": return Field.PartName; case "publisher": return Field.Publisher; @@ -196,21 +231,23 @@ namespace SabreTools.Library.Tools case "sampleof": return Field.SampleOf; case "sha1": + case "sha-1": return Field.SHA1; case "sha256": + case "sha-256": return Field.SHA256; case "sha384": + case "sha-384": return Field.SHA384; case "sha512": + case "sha-512": return Field.SHA512; - case "size": - return Field.Size; case "slotoptions": + case "slot-options": return Field.SlotOptions; case "sourcefile": + case "source-file": return Field.SourceFile; - case "status": - return Field.Status; case "supported": return Field.Supported; case "writable": diff --git a/SabreTools/SabreTools.Help.cs b/SabreTools/SabreTools.Help.cs index cd2e15db..9582d7ae 100644 --- a/SabreTools/SabreTools.Help.cs +++ b/SabreTools/SabreTools.Help.cs @@ -1269,6 +1269,20 @@ namespace SabreTools } } + public const string CategoryListValue = "category-filter"; + private static Feature CategoryListInput + { + get + { + return new Feature( + CategoryListValue, + new List() { "-cat", "--category-filter" }, + "Filter by Category", + FeatureType.List, + longDescription: "Include only items with this Category in the output. Additionally, the user can specify an exact match or full C#-style regex for pattern matching. Multiple instances of this flag are allowed."); + } + } + public const string CrcListValue = "crc"; private static Feature CrcListInput { @@ -1339,6 +1353,20 @@ namespace SabreTools } } + public const string FilterListValue = "filter"; + private static Feature FilterListInput + { + get + { + return new Feature( + FilterListValue, + new List() { "-fi", "--filter" }, + "Filter a game/rom field with the given value(s)", + FeatureType.List, + longDescription: "Filter any valid item or machine field from inputs. Filters are input in the form 'key:value' or '!key:value', where the '!' signifies 'not' matching. Numeric values may also prefix the 'value' with '>', '<', or '=' accordingly. Key examples include: romof, category, and game. Additionally, the user can specify an exact match or full C#-style regex for pattern matching. Multiple instances of this flag are allowed."); + } + } + public const string GameDescriptionListValue = "game-description"; private static Feature GameDescriptionListInput { @@ -1424,6 +1452,20 @@ Possible values are: None, Bios, Device, Mechanical"); } } + public const string NotCategoryListValue = "not-category"; + private static Feature NotCategoryListInput + { + get + { + return new Feature( + NotCategoryListValue, + new List() { "-ncat", "--not-category" }, + "Filter by not Category", + FeatureType.List, + longDescription: "Include only items without this Category in the output. Additionally, the user can specify an exact match or full C#-style regex for pattern matching. Multiple instances of this flag are allowed."); + } + } + public const string NotCrcListValue = "not-crc"; private static Feature NotCrcListInput { @@ -2055,6 +2097,7 @@ Some special strings that can be used: - %name% - Replaced with the Rom name - %manufacturer% - Replaced with game Manufacturer - %publisher% - Replaced with game Publisher +- %category% - Replaced with game Category - %crc% - Replaced with the CRC - %md5% - Replaced with the MD5" #if NET_FRAMEWORK @@ -2087,6 +2130,7 @@ Some special strings that can be used: - %name% - Replaced with the Rom name - %manufacturer% - Replaced with game Manufacturer - %publisher% - Replaced with game Publisher +- %category% - Replaced with game Category - %crc% - Replaced with the CRC - %md5% - Replaced with the MD5 - %sha1% - Replaced with the SHA-1 @@ -2297,106 +2341,243 @@ Some special strings that can be used: { Filter filter = new Filter(); - // Clean names - filter.Clean.Neutral = GetBoolean(features, CleanValue); + // Use the Filter flag first + List filterPairs = GetList(features, FilterListValue); + filter.PopulateFromList(filterPairs); + + #region Obsoleted Inputs + + // Category + if (features.ContainsKey(NotCategoryListValue)) + { + Globals.Logger.User($"This flag '{NotCategoryListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.Category, GetList(features, NotCategoryListValue), true); + } + if (features.ContainsKey(CategoryListValue)) + { + Globals.Logger.User($"This flag '{CategoryListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.Category, GetList(features, CategoryListValue), false); + } // CRC - filter.CRC.NegativeSet.AddRange(GetList(features, NotCrcListValue)); - filter.CRC.PositiveSet.AddRange(GetList(features, CrcListValue)); - - // Machine description as machine name - filter.DescriptionAsName.Neutral = GetBoolean(features, DescriptionAsNameValue); - - // Include 'of" in game filters - filter.IncludeOfInGame.Neutral = GetBoolean(features, MatchOfTagsValue); - - // Internal splitting - filter.InternalSplit.Neutral = GetSplitType(features); + if (features.ContainsKey(NotCrcListValue)) + { + Globals.Logger.User($"This flag '{NotCrcListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.CRC, GetList(features, NotCrcListValue), true); + } + if (features.ContainsKey(CrcListValue)) + { + Globals.Logger.User($"This flag '{CrcListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.CRC, GetList(features, NotCrcListValue), false); + } // Item name - filter.ItemName.NegativeSet.AddRange(GetList(features, NotItemNameListValue)); - filter.ItemName.PositiveSet.AddRange(GetList(features, ItemNameListValue)); + if (features.ContainsKey(NotItemNameListValue)) + { + Globals.Logger.User($"This flag '{NotItemNameListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.Name, GetList(features, NotItemNameListValue), true); + } + if (features.ContainsKey(ItemNameListValue)) + { + Globals.Logger.User($"This flag '{ItemNameListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.Name, GetList(features, ItemNameListValue), false); + } // Item status - foreach (string stat in GetList(features, NotStatusListValue)) + if (features.ContainsKey(NotStatusListValue)) { - filter.ItemStatuses.Negative |= stat.AsItemStatus(); + Globals.Logger.User($"This flag '{NotStatusListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.Status, GetList(features, NotStatusListValue), true); } - foreach (string stat in GetList(features, StatusListValue)) + if (features.ContainsKey(StatusListValue)) { - filter.ItemStatuses.Positive |= stat.AsItemStatus(); + Globals.Logger.User($"This flag '{StatusListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.Status, GetList(features, StatusListValue), false); } // Item type - filter.ItemTypes.NegativeSet.AddRange(GetList(features, NotItemTypeListValue)); - filter.ItemTypes.PositiveSet.AddRange(GetList(features, ItemTypeListValue)); + if (features.ContainsKey(NotItemTypeListValue)) + { + Globals.Logger.User($"This flag '{NotItemTypeListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.ItemType, GetList(features, NotItemTypeListValue), true); + } + if (features.ContainsKey(ItemTypeListValue)) + { + Globals.Logger.User($"This flag '{ItemTypeListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.ItemType, GetList(features, ItemTypeListValue), false); + } // Machine description - filter.MachineDescription.NegativeSet.AddRange(GetList(features, NotGameDescriptionListValue)); - filter.MachineDescription.PositiveSet.AddRange(GetList(features, GameDescriptionListValue)); + if (features.ContainsKey(NotGameDescriptionListValue)) + { + Globals.Logger.User($"This flag '{NotGameDescriptionListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.Description, GetList(features, NotGameDescriptionListValue), true); + } + if (features.ContainsKey(GameDescriptionListValue)) + { + Globals.Logger.User($"This flag '{GameDescriptionListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.Description, GetList(features, GameDescriptionListValue), false); + } // Machine name - filter.MachineName.NegativeSet.AddRange(GetList(features, NotGameNameListValue)); - filter.MachineName.PositiveSet.AddRange(GetList(features, GameNameListValue)); + if (features.ContainsKey(NotGameNameListValue)) + { + Globals.Logger.User($"This flag '{NotGameNameListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.MachineName, GetList(features, NotGameNameListValue), true); + } + if (features.ContainsKey(GameNameListValue)) + { + Globals.Logger.User($"This flag '{GameNameListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.MachineName, GetList(features, GameNameListValue), false); + } // Machine type - foreach (string mach in GetList(features, NotGameTypeListValue)) + if (features.ContainsKey(NotGameTypeListValue)) { - filter.MachineTypes.Negative |= mach.AsMachineType(); + Globals.Logger.User($"This flag '{NotGameTypeListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.MachineType, GetList(features, NotGameTypeListValue), true); } - foreach (string mach in GetList(features, GameTypeListValue)) + if (features.ContainsKey(GameTypeListValue)) { - filter.MachineTypes.Positive |= mach.AsMachineType(); + Globals.Logger.User($"This flag '{GameTypeListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.MachineType, GetList(features, GameTypeListValue), false); } // MD5 - filter.MD5.NegativeSet.AddRange(GetList(features, NotMd5ListValue)); - filter.MD5.PositiveSet.AddRange(GetList(features, Md5ListValue)); - - // Remove unicode characters - filter.RemoveUnicode.Neutral = GetBoolean(features, RemoveUnicodeValue); + if (features.ContainsKey(NotMd5ListValue)) + { + Globals.Logger.User($"This flag '{NotMd5ListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.MD5, GetList(features, NotMd5ListValue), true); + } + if (features.ContainsKey(Md5ListValue)) + { + Globals.Logger.User($"This flag '{Md5ListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.MD5, GetList(features, Md5ListValue), false); + } #if NET_FRAMEWORK // RIPEMD160 - filter.RIPEMD160.NegativeSet.AddRange(GetList(features, NotRipeMd160ListValue)); - filter.RIPEMD160.PositiveSet.AddRange(GetList(features, RipeMd160ListValue)); + if (features.ContainsKey(NotRipeMd160ListValue)) + { + Globals.Logger.User($"This flag '{NotRipeMd160ListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.RIPEMD160, GetList(features, NotRipeMd160ListValue), true); + } + if (features.ContainsKey(RipeMd160ListValue)) + { + Globals.Logger.User($"This flag '{RipeMd160ListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.RIPEMD160, GetList(features, RipeMd160ListValue), false); + } #endif - // Root directory - filter.Root.Neutral = GetString(features, RootDirStringValue); - // Runnable - if (GetBoolean(features, NotRunnableValue)) - filter.Runnable.Neutral = false; - if (GetBoolean(features, RunnableValue)) - filter.Runnable.Neutral = true; + if (features.ContainsKey(NotRunnableValue)) + { + Globals.Logger.User($"This flag '{NotRunnableValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.Runnable, string.Empty, true); + } + if (features.ContainsKey(RunnableValue)) + { + Globals.Logger.User($"This flag '{RunnableValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.Runnable, string.Empty, false); + } - // SHA-1 - filter.SHA1.NegativeSet.AddRange(GetList(features, NotSha1ListValue)); - filter.SHA1.PositiveSet.AddRange(GetList(features, Sha1ListValue)); + // SHA1 + if (features.ContainsKey(NotSha1ListValue)) + { + Globals.Logger.User($"This flag '{NotSha1ListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.SHA1, GetList(features, NotSha1ListValue), true); + } + if (features.ContainsKey(Sha1ListValue)) + { + Globals.Logger.User($"This flag '{Sha1ListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.SHA1, GetList(features, Sha1ListValue), false); + } - // SHA-256 - filter.SHA256.NegativeSet.AddRange(GetList(features, NotSha256ListValue)); - filter.SHA256.PositiveSet.AddRange(GetList(features, Sha256ListValue)); + // SHA256 + if (features.ContainsKey(NotSha256ListValue)) + { + Globals.Logger.User($"This flag '{NotSha256ListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.SHA256, GetList(features, NotSha256ListValue), true); + } + if (features.ContainsKey(Sha256ListValue)) + { + Globals.Logger.User($"This flag '{Sha256ListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.SHA256, GetList(features, Sha256ListValue), false); + } - // SHA-384 - filter.SHA384.NegativeSet.AddRange(GetList(features, NotSha384ListValue)); - filter.SHA384.PositiveSet.AddRange(GetList(features, Sha384ListValue)); + // SHA384 + if (features.ContainsKey(NotSha384ListValue)) + { + Globals.Logger.User($"This flag '{NotSha384ListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.SHA384, GetList(features, NotSha384ListValue), true); + } + if (features.ContainsKey(Sha384ListValue)) + { + Globals.Logger.User($"This flag '{Sha384ListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.SHA384, GetList(features, Sha384ListValue), false); + } - // SHA-512 - filter.SHA512.NegativeSet.AddRange(GetList(features, NotSha512ListValue)); - filter.SHA512.PositiveSet.AddRange(GetList(features, Sha512ListValue)); - - // Single game in output - filter.Single.Neutral = GetBoolean(features, SingleSetValue); + // SHA512 + if (features.ContainsKey(NotSha512ListValue)) + { + Globals.Logger.User($"This flag '{NotSha512ListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.SHA512, GetList(features, NotSha512ListValue), true); + } + if (features.ContainsKey(Sha512ListValue)) + { + Globals.Logger.User($"This flag '{Sha512ListValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + filter.SetFilter(Field.SHA512, GetList(features, Sha512ListValue), false); + } // Size - filter.Size.Negative = Sanitizer.ToSize(GetString(features, LessStringValue)); - filter.Size.Neutral = Sanitizer.ToSize(GetString(features, EqualStringValue)); - filter.Size.Positive = Sanitizer.ToSize(GetString(features, GreaterStringValue)); + if (features.ContainsKey(LessStringValue)) + { + Globals.Logger.User($"This flag '{LessStringValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + var value = Sanitizer.ToSize(GetString(features, LessStringValue)); + filter.SetFilter(Field.Size, $"<{value}", false); + } + if (features.ContainsKey(EqualStringValue)) + { + Globals.Logger.User($"This flag '{EqualStringValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + var value = Sanitizer.ToSize(GetString(features, EqualStringValue)); + filter.SetFilter(Field.Size, $"={value}", false); + } + if (features.ContainsKey(GreaterStringValue)) + { + Globals.Logger.User($"This flag '{GreaterStringValue}' is deprecated, please use {string.Join(", ", FilterListInput.Flags)} instead"); + var value = Sanitizer.ToSize(GetString(features, GreaterStringValue)); + filter.SetFilter(Field.Size, $">{value}", false); + } + + #endregion + + #region Filter manipulation flags + + // Clean names + filter.Clean = GetBoolean(features, CleanValue); + + // Machine description as machine name + filter.DescriptionAsName = GetBoolean(features, DescriptionAsNameValue); + + // Include 'of" in game filters + filter.IncludeOfInGame = GetBoolean(features, MatchOfTagsValue); + + // Internal splitting + filter.InternalSplit = GetSplitType(features); + + // Remove unicode characters + filter.RemoveUnicode = GetBoolean(features, RemoveUnicodeValue); + + // Root directory + filter.Root = GetString(features, RootDirStringValue); + + // Single game in output + filter.Single = GetBoolean(features, SingleSetValue); // Trim to NTFS length - filter.Trim.Neutral = GetBoolean(features, TrimValue); + filter.Trim = GetBoolean(features, TrimValue); + + #endregion return filter; } @@ -2714,6 +2895,9 @@ Some special strings that can be used: AddFeature(CopyFilesFlag); AddFeature(HeaderStringInput); AddFeature(ChdsAsFilesFlag); + AddFeature(FilterListInput); + AddFeature(CategoryListInput); + AddFeature(NotCategoryListInput); AddFeature(GameNameListInput); AddFeature(NotGameNameListInput); AddFeature(GameDescriptionListInput); @@ -3238,6 +3422,9 @@ The stats that are outputted are as follows: this[DiffCascadeFlag].AddFeature(SkipFirstOutputFlag); AddFeature(DiffReverseCascadeFlag); this[DiffReverseCascadeFlag].AddFeature(SkipFirstOutputFlag); + AddFeature(FilterListInput); + AddFeature(CategoryListInput); + AddFeature(NotCategoryListInput); AddFeature(GameNameListInput); AddFeature(NotGameNameListInput); AddFeature(GameDescriptionListInput); @@ -3369,6 +3556,9 @@ The stats that are outputted are as follows: AddFeature(DatDeviceNonMergedFlag); AddFeature(DatNonMergedFlag); AddFeature(DatFullNonMergedFlag); + AddFeature(FilterListInput); + AddFeature(CategoryListInput); + AddFeature(NotCategoryListInput); AddFeature(GameNameListInput); AddFeature(NotGameNameListInput); AddFeature(GameDescriptionListInput);