diff --git a/SabreTools.Core/Filter/FieldManipulator.cs b/SabreTools.Core/Filter/FieldManipulator.cs
index 9b6113f9..e1b8b288 100644
--- a/SabreTools.Core/Filter/FieldManipulator.cs
+++ b/SabreTools.Core/Filter/FieldManipulator.cs
@@ -1,6 +1,5 @@
using System;
using System.Linq;
-using System.Text.RegularExpressions;
using SabreTools.Core.Tools;
using SabreTools.Models.Metadata;
@@ -8,36 +7,6 @@ namespace SabreTools.Core.Filter
{
public static class FieldManipulator
{
- ///
- /// Regex pattern to match scene dates
- ///
- private const string _sceneDateRegex = @"([0-9]{2}\.[0-9]{2}\.[0-9]{2}-)(.*?-.*?)";
-
- ///
- /// Replace the machine name with the description
- ///
- /// Original machine name on success, null on error
- public static string? DescriptionToName(Machine? machine)
- {
- // If the machine is missing, we can't do anything
- if (machine == null)
- return null;
-
- // Get both the current name and description
- string? name = machine.ReadString(Header.NameKey);
- string? description = machine.ReadString(Header.DescriptionKey);
-
- // Sanitize the description string
- description = description?
- .Replace('/', '_')
- .Replace("\"", "''")
- .Replace(":", " -");
-
- // Replace the name with the description
- machine[Header.NameKey] = description;
- return name;
- }
-
///
/// Remove a field from a given DictionaryBase
///
@@ -96,27 +65,5 @@ namespace SabreTools.Core.Filter
dictionaryBase[fieldName!] = value;
return true;
}
-
- ///
- /// Strip the dates from the beginning of scene-style machine name and description
- ///
- public static bool StripSceneDates(Machine? machine)
- {
- // If the machine is missing, we can't do anything
- if (machine == null)
- return false;
-
- // Strip dates from the name field
- string? name = machine.ReadString(Header.NameKey);
- if (name != null && Regex.IsMatch(name, _sceneDateRegex))
- machine[Header.NameKey] = Regex.Replace(name, _sceneDateRegex, @"$2");
-
- // Strip dates from the description field
- string? description = machine.ReadString(Header.DescriptionKey);
- if (description != null && Regex.IsMatch(description, _sceneDateRegex))
- machine[Header.DescriptionKey] = Regex.Replace(description, _sceneDateRegex, @"$2");
-
- return true;
- }
}
}
\ No newline at end of file
diff --git a/SabreTools.Core/Filter/FilterObject.cs b/SabreTools.Core/Filter/FilterObject.cs
index c7acc7d0..e0ae74a0 100644
--- a/SabreTools.Core/Filter/FilterObject.cs
+++ b/SabreTools.Core/Filter/FilterObject.cs
@@ -14,26 +14,24 @@ namespace SabreTools.Core.Filter
///
/// Key name for the filter
///
- public string[] Key { get; }
+ public readonly string[] Key;
///
/// Value to match in the filter
///
- public string? Value { get; }
+ public readonly string? Value;
///
/// Operation on how to match the filter
///
- public Operation Operation { get; }
+ public readonly Operation Operation;
public FilterObject(string filterString)
{
- (string? keyItem, Operation operation, string? value) = SplitFilterString(filterString);
- if (keyItem == null)
+ if (!SplitFilterString(filterString, out var keyItem, out Operation operation, out var value))
throw new ArgumentOutOfRangeException(nameof(filterString));
- (string? itemName, string? fieldName) = FilterParser.ParseFilterId(keyItem);
- if (itemName == null || fieldName == null)
+ if (!FilterParser.ParseFilterId(keyItem, out var itemName, out var fieldName))
throw new ArgumentOutOfRangeException(nameof(filterString));
Key = [itemName, fieldName];
@@ -43,8 +41,7 @@ namespace SabreTools.Core.Filter
public FilterObject(string itemField, string? value, string? operation)
{
- (string? itemName, string? fieldName) = FilterParser.ParseFilterId(itemField);
- if (itemName == null || fieldName == null)
+ if (!FilterParser.ParseFilterId(itemField, out var itemName, out var fieldName))
throw new ArgumentOutOfRangeException(nameof(value));
Key = [itemName, fieldName];
@@ -54,11 +51,10 @@ namespace SabreTools.Core.Filter
public FilterObject(string itemField, string? value, Operation operation)
{
- (string? itemName, string? fieldName) = FilterParser.ParseFilterId(itemField);
- if (itemName == null || fieldName == null)
+ if (!FilterParser.ParseFilterId(itemField, out var itemName, out var fieldName))
throw new ArgumentOutOfRangeException(nameof(value));
- Key = [itemName, fieldName];
+ Key = [itemName!, fieldName!];
Value = value;
Operation = operation;
}
@@ -396,10 +392,13 @@ namespace SabreTools.Core.Filter
///
/// Derive a key, operation, and value from the input string, if possible
///
- private static (string?, Operation, string?) SplitFilterString(string? filterString)
+ private static bool SplitFilterString(string? filterString, out string? key, out Operation operation, out string? value)
{
+ // Set default values
+ key = null; operation = Operation.NONE; value = null;
+
if (filterString == null)
- return (null, Operation.NONE, null);
+ return false;
// Trim quotations, if necessary
if (filterString.StartsWith("\""))
@@ -408,13 +407,13 @@ namespace SabreTools.Core.Filter
// Split the string using regex
var match = Regex.Match(filterString, @"^(?[a-zA-Z.]+)(?[=!:><]{1,2})(?.*)$");
if (!match.Success)
- return (null, Operation.NONE, null);
+ return false;
- string itemField = match.Groups["itemField"].Value;
- Operation operation = GetOperation(match.Groups["operation"].Value);
- string value = match.Groups["value"].Value;
+ key = match.Groups["itemField"].Value;
+ operation = GetOperation(match.Groups["operation"].Value);
+ value = match.Groups["value"].Value;
- return (itemField, operation, value);
+ return true;
}
#endregion
diff --git a/SabreTools.Core/Filter/FilterParser.cs b/SabreTools.Core/Filter/FilterParser.cs
index b28b4884..2f112f66 100644
--- a/SabreTools.Core/Filter/FilterParser.cs
+++ b/SabreTools.Core/Filter/FilterParser.cs
@@ -10,125 +10,166 @@ namespace SabreTools.Core.Filter
///
/// Parse a filter ID string into the item name and field name, if possible
///
- public static (string?, string?) ParseFilterId(string itemFieldString)
+ public static bool ParseFilterId(string? itemFieldString, out string itemName, out string fieldName)
{
+ // Set default values
+ itemName = string.Empty; fieldName = string.Empty;
+
// If we don't have a filter ID, we can't do anything
- if (string.IsNullOrEmpty(itemFieldString))
- return (null, null);
+ if (itemFieldString == null)
+ return false;
// If we only have one part, we can't do anything
string[] splitFilter = itemFieldString.Split('.');
if (splitFilter.Length != 2)
- return (null, null);
+ return false;
- return ParseFilterId(splitFilter[0], splitFilter[1]);
+ // Set and sanitize the filter ID
+ itemName = splitFilter[0];
+ fieldName = splitFilter[1];
+ return ParseFilterId(ref itemName, ref fieldName);
}
///
/// Parse a filter ID string into the item name and field name, if possible
///
- public static (string?, string?) ParseFilterId(string itemName, string? fieldName)
+ public static bool ParseFilterId(ref string itemName, ref string fieldName)
{
// If we don't have a filter ID, we can't do anything
if (string.IsNullOrEmpty(itemName) || string.IsNullOrEmpty(fieldName))
- return (null, null);
+ return false;
// Return santized values based on the split ID
return itemName.ToLowerInvariant() switch
{
// Header
- "header" => ParseHeaderFilterId(fieldName!),
+ "header" => ParseHeaderFilterId(ref itemName, ref fieldName),
// Machine
- "game" => ParseMachineFilterId(fieldName!),
- "machine" => ParseMachineFilterId(fieldName!),
- "resource" => ParseMachineFilterId(fieldName!),
- "set" => ParseMachineFilterId(fieldName!),
+ "game" => ParseMachineFilterId(ref itemName, ref fieldName),
+ "machine" => ParseMachineFilterId(ref itemName, ref fieldName),
+ "resource" => ParseMachineFilterId(ref itemName, ref fieldName),
+ "set" => ParseMachineFilterId(ref itemName, ref fieldName),
// DatItem
- "datitem" => ParseDatItemFilterId(fieldName!),
- "item" => ParseDatItemFilterId(fieldName!),
- _ => ParseDatItemFilterId(itemName, fieldName!),
+ "datitem" => ParseDatItemFilterId(ref itemName, ref fieldName),
+ "item" => ParseDatItemFilterId(ref itemName, ref fieldName),
+ _ => ParseDatItemFilterId(ref itemName, ref fieldName),
};
}
///
/// Parse and validate header fields
///
- private static (string?, string?) ParseHeaderFilterId(string fieldName)
+ private static bool ParseHeaderFilterId(ref string itemName, ref string fieldName)
{
// Get the set of constants
var constants = TypeHelper.GetConstants(typeof(Header));
if (constants == null)
- return (null, null);
+ return false;
// Get if there's a match to the constant
- string? constantMatch = constants.FirstOrDefault(c => string.Equals(c, fieldName, StringComparison.OrdinalIgnoreCase));
+ string localFieldName = fieldName;
+ string? constantMatch = constants.FirstOrDefault(c => string.Equals(c, localFieldName, StringComparison.OrdinalIgnoreCase));
if (constantMatch == null)
- return (null, null);
+ return false;
// Return the sanitized ID
- return (MetadataFile.HeaderKey, constantMatch);
+ itemName = MetadataFile.HeaderKey;
+ fieldName = constantMatch;
+ return true;
}
///
/// Parse and validate machine/game fields
///
- private static (string?, string?) ParseMachineFilterId(string fieldName)
+ private static bool ParseMachineFilterId(ref string itemName, ref string fieldName)
{
// Get the set of constants
var constants = TypeHelper.GetConstants(typeof(Machine));
if (constants == null)
- return (null, null);
+ return false;
// Get if there's a match to the constant
- string? constantMatch = constants.FirstOrDefault(c => string.Equals(c, fieldName, StringComparison.OrdinalIgnoreCase));
+ string localFieldName = fieldName;
+ string? constantMatch = constants.FirstOrDefault(c => string.Equals(c, localFieldName, StringComparison.OrdinalIgnoreCase));
if (constantMatch == null)
- return (null, null);
+ return false;
// Return the sanitized ID
- return (MetadataFile.MachineKey, constantMatch);
+ itemName = MetadataFile.MachineKey;
+ fieldName = constantMatch;
+ return true;
}
///
/// Parse and validate item fields
///
- private static (string?, string?) ParseDatItemFilterId(string fieldName)
+ private static bool ParseDatItemFilterId(ref string itemName, ref string fieldName)
{
- // Get all item types
- var itemTypes = TypeHelper.GetDatItemTypeNames();
+ // Special case if the item name is reserved
+ if (string.Equals(itemName, "datitem", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(itemName, "item", StringComparison.OrdinalIgnoreCase))
+ {
+ // Get all item types
+ var itemTypes = TypeHelper.GetDatItemTypeNames();
- // If we get any matches
- string? match = itemTypes.FirstOrDefault(t => t != null && ParseDatItemFilterId(t, fieldName) != (null, null));
- if (match != null)
- return ("item", ParseDatItemFilterId(match, fieldName).Item2);
+ // If we get any matches
+ string localFieldName = fieldName;
+ string? matchedType = itemTypes.FirstOrDefault(t => DatItemContainsField(t, localFieldName));
+ if (matchedType != null)
+ {
+ // Check for a matching field
+ string? matchedField = GetMatchingField(matchedType, fieldName);
+ if (matchedField == null)
+ return false;
+
+ itemName = "item";
+ fieldName = matchedField;
+ return true;
+ }
+ }
+ else
+ {
+ // Check for a matching field
+ string? matchedField = GetMatchingField(itemName, fieldName);
+ if (matchedField == null)
+ return false;
+
+ itemName = itemName.ToLowerInvariant();
+ fieldName = matchedField;
+ return true;
+ }
// Nothing was found
- return (null, null);
+ return false;
}
///
- /// Parse and validate item fields
+ /// Determine if an item type contains a field
///
- private static (string?, string?) ParseDatItemFilterId(string itemName, string fieldName)
+ private static bool DatItemContainsField(string itemName, string fieldName)
+ => GetMatchingField(itemName, fieldName) != null;
+
+ ///
+ /// Determine if an item type contains a field
+ ///
+ private static string? GetMatchingField(string itemName, string fieldName)
{
// Get the correct item type
var itemType = TypeHelper.GetDatItemType(itemName.ToLowerInvariant());
if (itemType == null)
- return (null, null);
+ return null;
// Get the set of constants
var constants = TypeHelper.GetConstants(itemType);
if (constants == null)
- return (null, null);
+ return null;
// Get if there's a match to the constant
- string? constantMatch = constants.FirstOrDefault(c => string.Equals(c, fieldName, StringComparison.OrdinalIgnoreCase));
- if (constantMatch == null)
- return (null, null);
-
- // Return the sanitized ID
- return (itemName.ToLowerInvariant(), constantMatch);
+ string localFieldName = fieldName;
+ string? constantMatch = constants.FirstOrDefault(c => string.Equals(c, localFieldName, StringComparison.OrdinalIgnoreCase));
+ return constantMatch;
}
}
}
diff --git a/SabreTools.Core/Filter/FilterRunner.cs b/SabreTools.Core/Filter/FilterRunner.cs
index bdf36da2..32e19503 100644
--- a/SabreTools.Core/Filter/FilterRunner.cs
+++ b/SabreTools.Core/Filter/FilterRunner.cs
@@ -20,7 +20,7 @@ namespace SabreTools.Core.Filter
if (filters == null)
throw new ArgumentNullException(nameof(filters));
- this.Filters = filters;
+ Filters = filters;
}
public FilterRunner(string[]? filterStrings)
@@ -34,7 +34,7 @@ namespace SabreTools.Core.Filter
filters.Add(new FilterObject(filterString));
}
- this.Filters = [.. filters];
+ Filters = [.. filters];
}
///
@@ -51,7 +51,7 @@ namespace SabreTools.Core.Filter
};
// Loop through and run each filter in order
- foreach (var filter in this.Filters)
+ foreach (var filter in Filters)
{
// If the filter isn't for this object type, skip
if (filter.Key[0] != itemName)
diff --git a/SabreTools.Core/Tools/TypeHelper.cs b/SabreTools.Core/Tools/TypeHelper.cs
index 53fca007..cd719d96 100644
--- a/SabreTools.Core/Tools/TypeHelper.cs
+++ b/SabreTools.Core/Tools/TypeHelper.cs
@@ -42,7 +42,7 @@ namespace SabreTools.Core.Tools
///
/// Attempt to get all DatItem types
///
- public static string?[] GetDatItemTypeNames()
+ public static string[] GetDatItemTypeNames()
{
List typeNames = [];
diff --git a/SabreTools.DatFiles/Setter.cs b/SabreTools.DatFiles/Setter.cs
index 44de8922..747c83e2 100644
--- a/SabreTools.DatFiles/Setter.cs
+++ b/SabreTools.DatFiles/Setter.cs
@@ -114,8 +114,7 @@ namespace SabreTools.DatFiles
return false;
// Get the parser pair out of it, if possible
- (string? type, string? key) = FilterParser.ParseFilterId(field);
- if (type == null || key == null)
+ if (!FilterParser.ParseFilterId(field, out string type, out string key))
return false;
switch (type)
diff --git a/SabreTools.Filtering/ExtraIni.cs b/SabreTools.Filtering/ExtraIni.cs
index 59bb153b..771f8b6a 100644
--- a/SabreTools.Filtering/ExtraIni.cs
+++ b/SabreTools.Filtering/ExtraIni.cs
@@ -68,7 +68,8 @@ namespace SabreTools.Filtering
string fieldString = inputTrimmed.Split(':')[0].ToLowerInvariant().Trim('"', ' ', '\t');
string fileString = inputTrimmed.Substring(fieldString.Length + 1).Trim('"', ' ', '\t');
- item.FieldName = FilterParser.ParseFilterId(fieldString);
+ FilterParser.ParseFilterId(fieldString, out string itemName, out string fieldName);
+ item.FieldName = (itemName, fieldName);
if (item.PopulateFromFile(fileString))
Items.Add(item);
}
diff --git a/SabreTools.Filtering/Remover.cs b/SabreTools.Filtering/Remover.cs
index f64d2ba7..506cb1c4 100644
--- a/SabreTools.Filtering/Remover.cs
+++ b/SabreTools.Filtering/Remover.cs
@@ -92,8 +92,7 @@ namespace SabreTools.Filtering
return false;
// Get the parser pair out of it, if possible
- (string? type, string? key) = FilterParser.ParseFilterId(field);
- if (type == null || key == null)
+ if (!FilterParser.ParseFilterId(field, out string type, out string key))
return false;
switch (type)
diff --git a/SabreTools/Features/BaseFeature.cs b/SabreTools/Features/BaseFeature.cs
index d0817b9a..ca476b97 100644
--- a/SabreTools/Features/BaseFeature.cs
+++ b/SabreTools/Features/BaseFeature.cs
@@ -2023,9 +2023,13 @@ Some special strings that can be used:
List updateFields = [];
foreach (string fieldName in GetList(features, UpdateFieldListValue))
{
- (string? itemType, string? key) = FilterParser.ParseFilterId(fieldName);
- if (itemType == Models.Metadata.MetadataFile.MachineKey && key != null)
- updateFields.Add(key);
+ // Ensure the field is valid
+ if (!FilterParser.ParseFilterId(fieldName, out string itemType, out string key))
+ continue;
+ if (itemType != Models.Metadata.MetadataFile.MachineKey)
+ continue;
+
+ updateFields.Add(key);
}
return updateFields;
@@ -2039,14 +2043,16 @@ Some special strings that can be used:
Dictionary> updateFields = [];
foreach (string fieldName in GetList(features, UpdateFieldListValue))
{
- (string? itemType, string? key) = FilterParser.ParseFilterId(fieldName);
- if (itemType != null && itemType != Models.Metadata.MetadataFile.HeaderKey && itemType != Models.Metadata.MetadataFile.MachineKey && key != null)
- {
- if (!updateFields.ContainsKey(itemType))
- updateFields[itemType] = [];
+ // Ensure the field is valid
+ if (!FilterParser.ParseFilterId(fieldName, out string itemType, out string key))
+ continue;
+ if (itemType == Models.Metadata.MetadataFile.HeaderKey || itemType == Models.Metadata.MetadataFile.MachineKey)
+ continue;
- updateFields[itemType].Add(key);
- }
+ if (!updateFields.ContainsKey(itemType))
+ updateFields[itemType] = [];
+
+ updateFields[itemType].Add(key);
}
return updateFields;
diff --git a/SabreTools/Features/Batch.cs b/SabreTools/Features/Batch.cs
index 5e11300f..0b588ffd 100644
--- a/SabreTools/Features/Batch.cs
+++ b/SabreTools/Features/Batch.cs
@@ -315,11 +315,11 @@ Reset the internal state: reset();";
}
// Read in the individual arguments
- (string? type, string? key) = FilterParser.ParseFilterId(Arguments[0]);
+ bool parsed = FilterParser.ParseFilterId(Arguments[0], out _, out _);
string extraFile = Arguments[1];
// If we had an invalid input, log and continue
- if (type == null && key == null)
+ if (!parsed)
{
string message = $"{Arguments[0]} was an invalid field name";
return (false, message);
@@ -337,12 +337,12 @@ Reset the internal state: reset();";
public override void Process(BatchState batchState)
{
// Read in the individual arguments
- (string?, string?) fieldName = FilterParser.ParseFilterId(Arguments[0]);
+ FilterParser.ParseFilterId(Arguments[0], out string itemName, out string fieldName);
string extraFile = Arguments[1];
// Create the extra INI
var extraIni = new ExtraIni();
- var extraIniItem = new ExtraIniItem() { FieldName = fieldName };
+ var extraIniItem = new ExtraIniItem() { FieldName = (itemName, fieldName) };
extraIniItem.PopulateFromFile(extraFile);
extraIni.Items.Add(extraIniItem);
@@ -376,7 +376,7 @@ Reset the internal state: reset();";
}
// Read in the individual arguments
- (string? type, string? key) = FilterParser.ParseFilterId(Arguments[0]);
+ bool parsed = FilterParser.ParseFilterId(Arguments[0], out _, out _);
bool? filterRemove = false;
if (Arguments.Count >= 3)
filterRemove = Arguments[2].AsYesNo();
@@ -385,7 +385,7 @@ Reset the internal state: reset();";
filterPerMachine = Arguments[3].AsYesNo();
// If we had an invalid input, log and continue
- if (type == null && key == null)
+ if (!parsed)
{
string message = $"{Arguments[0]} was an invalid field name";
return (false, message);
@@ -805,10 +805,10 @@ Reset the internal state: reset();";
}
// Read in the individual arguments
- (string? type, string? key) = FilterParser.ParseFilterId(Arguments[0]);
+ bool parsed = FilterParser.ParseFilterId(Arguments[0], out string type, out _);
// If we had an invalid input, log and continue
- if ((type == null || !string.Equals(type, Models.Metadata.MetadataFile.HeaderKey, StringComparison.OrdinalIgnoreCase)) && key == null)
+ if (!parsed || !string.Equals(type, Models.Metadata.MetadataFile.HeaderKey, StringComparison.OrdinalIgnoreCase))
{
string message = $"{Arguments[0]} was an invalid field name";
return (false, message);