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