diff --git a/SabreTools.Metadata.Filter.Test/FilterObjectTests.cs b/SabreTools.Metadata.Filter.Test/FilterObjectTests.cs
index b96571ae..5a679f5d 100644
--- a/SabreTools.Metadata.Filter.Test/FilterObjectTests.cs
+++ b/SabreTools.Metadata.Filter.Test/FilterObjectTests.cs
@@ -472,5 +472,223 @@ namespace SabreTools.Metadata.Filter.Test
}
#endregion
+
+ #region Adjuster
+
+ [Theory]
+ [InlineData("adjuster.default", "yes")]
+ [InlineData("adjuster.name", "name")]
+ public void Matches_Adjsuter(string itemField, string value)
+ {
+ var filter = new FilterObject(itemField, value, Operation.Equals);
+ Adjuster obj = new Adjuster
+ {
+ Default = true,
+ Name = "name",
+ };
+
+ bool actual = filter.Matches(obj);
+ Assert.True(actual);
+ }
+
+ #endregion
+
+ #region Analog
+
+ [Theory]
+ [InlineData("analog.mask", "mask")]
+ public void Matches_Analog(string itemField, string value)
+ {
+ var filter = new FilterObject(itemField, value, Operation.Equals);
+ Analog obj = new Analog
+ {
+ Mask = "mask",
+ };
+
+ bool actual = filter.Matches(obj);
+ Assert.True(actual);
+ }
+
+ #endregion
+
+ #region Archive
+
+ [Theory]
+ [InlineData("archive.additional", "additional")]
+ [InlineData("archive.adult", "1")]
+ [InlineData("archive.alt", "1")]
+ [InlineData("archive.bios", "1")]
+ [InlineData("archive.categories", "categories")]
+ [InlineData("archive.clone", "clone")]
+ [InlineData("archive.clonetag", "clone")]
+ [InlineData("archive.complete", "1")]
+ [InlineData("archive.dat", "1")]
+ [InlineData("archive.datternote", "datternote")]
+ [InlineData("archive.description", "description")]
+ [InlineData("archive.devstatus", "devstatus")]
+ [InlineData("archive.gameid1", "gameid1")]
+ [InlineData("archive.gameid2", "gameid2")]
+ [InlineData("archive.langchecked", "langchecked")]
+ [InlineData("archive.languages", "languages")]
+ [InlineData("archive.licensed", "1")]
+ [InlineData("archive.listed", "1")]
+ [InlineData("archive.mergeof", "mergeof")]
+ [InlineData("archive.mergename", "mergename")]
+ [InlineData("archive.name", "name")]
+ [InlineData("archive.namealt", "namealt")]
+ [InlineData("archive.number", "number")]
+ [InlineData("archive.physical", "1")]
+ [InlineData("archive.pirate", "1")]
+ [InlineData("archive.private", "1")]
+ [InlineData("archive.region", "region")]
+ [InlineData("archive.regparent", "regparent")]
+ [InlineData("archive.showlang", "1")]
+ [InlineData("archive.special1", "special1")]
+ [InlineData("archive.special2", "special2")]
+ [InlineData("archive.stickynote", "stickynote")]
+ [InlineData("archive.version1", "version1")]
+ [InlineData("archive.version2", "version2")]
+ public void Matches_Archive(string itemField, string value)
+ {
+ var filter = new FilterObject(itemField, value, Operation.Equals);
+ Archive obj = new Archive
+ {
+ Additional = "additional",
+ Adult = true,
+ Alt = true,
+ Bios = true,
+ Categories = "categories",
+ CloneTag = "clone",
+ Complete = true,
+ Dat = true,
+ DatterNote = "datternote",
+ Description = "description",
+ DevStatus = "devstatus",
+ GameId1 = "gameid1",
+ GameId2 = "gameid2",
+ LangChecked = "langchecked",
+ Languages = "languages",
+ Licensed = true,
+ Listed = true,
+ MergeOf = "mergeof",
+ MergeName = "mergename",
+ Name = "name",
+ NameAlt = "namealt",
+ Number = "number",
+ Physical = true,
+ Pirate = true,
+ Private = true,
+ Region = "region",
+ RegParent = "regparent",
+ ShowLang = true,
+ Special1 = "special1",
+ Special2 = "special2",
+ StickyNote = "stickynote",
+ Version1 = "version1",
+ Version2 = "version2",
+ };
+
+ bool actual = filter.Matches(obj);
+ Assert.True(actual);
+ }
+
+ #endregion
+
+ #region BiosSet
+
+ [Theory]
+ [InlineData("biosset.default", "yes")]
+ [InlineData("biosset.description", "description")]
+ [InlineData("biosset.name", "name")]
+ public void Matches_BiosSet(string itemField, string value)
+ {
+ var filter = new FilterObject(itemField, value, Operation.Equals);
+ BiosSet obj = new BiosSet
+ {
+ Default = true,
+ Description = "description",
+ Name = "name",
+ };
+
+ bool actual = filter.Matches(obj);
+ Assert.True(actual);
+ }
+
+ #endregion
+
+ #region Chip
+
+ [Theory]
+ [InlineData("chip.type", "audio")]
+ [InlineData("chip.chiptype", "audio")]
+ [InlineData("chip.clock", "12345")]
+ [InlineData("chip.flags", "flags")]
+ [InlineData("chip.name", "name")]
+ [InlineData("chip.soundonly", "yes")]
+ [InlineData("chip.tag", "tag")]
+ public void Matches_Chip(string itemField, string value)
+ {
+ var filter = new FilterObject(itemField, value, Operation.Equals);
+ Chip obj = new Chip
+ {
+ ChipType = ChipType.Audio,
+ Clock = 12345,
+ Flags = "flags",
+ Name = "name",
+ SoundOnly = true,
+ Tag = "tag",
+ };
+
+ bool actual = filter.Matches(obj);
+ Assert.True(actual);
+ }
+
+ #endregion
+
+ #region Condition
+
+ [Theory]
+ [InlineData("condition.mask", "mask")]
+ [InlineData("condition.relation", "ne")]
+ [InlineData("condition.tag", "tag")]
+ [InlineData("condition.value", "value")]
+ public void Matches_Condition(string itemField, string value)
+ {
+ var filter = new FilterObject(itemField, value, Operation.Equals);
+ Condition obj = new Condition
+ {
+ Mask = "mask",
+ Relation = Relation.NotEqual,
+ Tag = "tag",
+ Value = "value",
+ };
+
+ bool actual = filter.Matches(obj);
+ Assert.True(actual);
+ }
+
+ #endregion
+
+ #region Configuration
+
+ [Theory]
+ [InlineData("configuration.mask", "mask")]
+ [InlineData("configuration.name", "name")]
+ [InlineData("configuration.tag", "tag")]
+ public void Matches_Configuration(string itemField, string value)
+ {
+ var filter = new FilterObject(itemField, value, Operation.Equals);
+ Configuration obj = new Configuration
+ {
+ Mask = "mask",
+ Name = "name",
+ Tag = "tag",
+ };
+
+ bool actual = filter.Matches(obj);
+ Assert.True(actual);
+ }
+
+ #endregion
}
}
diff --git a/SabreTools.Metadata.Filter/FilterKey.cs b/SabreTools.Metadata.Filter/FilterKey.cs
index 7666d353..64442a27 100644
--- a/SabreTools.Metadata.Filter/FilterKey.cs
+++ b/SabreTools.Metadata.Filter/FilterKey.cs
@@ -10,6 +10,8 @@ namespace SabreTools.Metadata.Filter
///
public class FilterKey
{
+ #region Properties
+
///
/// Item name associated with the filter
///
@@ -20,6 +22,10 @@ namespace SabreTools.Metadata.Filter
///
public readonly string FieldName;
+ #endregion
+
+ #region Constants
+
///
/// Cached item type names for filter selection
///
@@ -29,6 +35,111 @@ namespace SabreTools.Metadata.Filter
private static readonly string[] _datItemTypeNames = Enum.GetNames(typeof(ItemType));
#endif
+ ///
+ /// Known keys for Adjuster
+ ///
+ private static readonly string[] _adjusterKeys =
+ [
+ "default",
+ "name"
+ ];
+
+ ///
+ /// Known keys for Analog
+ ///
+ private static readonly string[] _analogKeys =
+ [
+ "mask"
+ ];
+
+ ///
+ /// Known keys for Archive
+ ///
+ private static readonly string[] _archiveKeys =
+ [
+ "additional",
+ "adult",
+ "alt",
+ "bios",
+ "categories",
+ "clone",
+ "clonetag",
+ "complete",
+ "dat",
+ "datternote",
+ "description",
+ "devstatus",
+ "gameid1",
+ "gameid2",
+ "langchecked",
+ "languages",
+ "licensed",
+ "listed",
+ "mergeof",
+ "mergename",
+ "name",
+ "namealt",
+ "number",
+ "physical",
+ "pirate",
+ "private",
+ "region",
+ "regparent",
+ "showlang",
+ "special1",
+ "special2",
+ "stickynote",
+ "version1",
+ "version2",
+ ];
+
+ ///
+ /// Known keys for BiosSet
+ ///
+ private static readonly string[] _biossetKeys =
+ [
+ "default",
+ "description",
+ "name",
+ ];
+
+ ///
+ /// Known keys for Chip
+ ///
+ private static readonly string[] _chipKeys =
+ [
+ "chiptype",
+ "clock",
+ "flags",
+ "name",
+ "soundonly",
+ "tag",
+ "type",
+ ];
+
+ ///
+ /// Known keys for Condition
+ ///
+ private static readonly string[] _conditionKeys =
+ [
+ "mask",
+ "relation",
+ "tag",
+ "value",
+ ];
+
+ ///
+ /// Known keys for Configuration
+ ///
+ private static readonly string[] _configurationKeys =
+ [
+ "mask",
+ "name",
+ "tag",
+ ];
+
+ #endregion
+
///
/// Validating combined key constructor
///
@@ -202,13 +313,34 @@ namespace SabreTools.Metadata.Filter
///
private static string? GetMatchingField(string itemName, string fieldName)
{
- // Get the correct item type
- var itemType = GetDatItemType(itemName.ToLowerInvariant());
- if (itemType is null)
- return null;
-
// Get the set of properties
- var properties = GetProperties(itemType);
+ string[]? properties = itemName.ToLowerInvariant() switch
+ {
+ "adjuster" => _adjusterKeys,
+ "analog" => _analogKeys,
+ "archive" => _archiveKeys,
+ "biosset" => _biossetKeys,
+ "chip" => _chipKeys,
+ "condition" => _conditionKeys,
+ "configuration" => _configurationKeys,
+ _ => null,
+ };
+
+ // TODO: Remove this fallback path
+ if (properties is null)
+ {
+ // Get the correct item type
+ var itemType = GetDatItemType(itemName.ToLowerInvariant());
+ if (itemType is null)
+ return null;
+
+ properties = GetProperties(itemType);
+
+ // Special cases for mismatched names
+ if (properties is not null && itemType == typeof(Rom))
+ properties = [.. properties, "crc"];
+ }
+
if (properties is null)
return null;
diff --git a/SabreTools.Metadata.Filter/FilterObject.cs b/SabreTools.Metadata.Filter/FilterObject.cs
index cee98f14..def15fcf 100644
--- a/SabreTools.Metadata.Filter/FilterObject.cs
+++ b/SabreTools.Metadata.Filter/FilterObject.cs
@@ -455,6 +455,7 @@ namespace SabreTools.Metadata.Filter
checkValue = obj.Categories;
return true;
case "clone":
+ case "clonetag":
checkValue = obj.CloneTag;
return true;
case "complete":
@@ -577,6 +578,7 @@ namespace SabreTools.Metadata.Filter
{
switch (fieldName)
{
+ case "chiptype":
case "type":
checkValue = obj.ChipType?.AsStringValue();
return true;