diff --git a/SabreTools.Filtering/DatHeaderFilter.cs b/SabreTools.Filtering/DatHeaderFilter.cs new file mode 100644 index 00000000..16a58432 --- /dev/null +++ b/SabreTools.Filtering/DatHeaderFilter.cs @@ -0,0 +1,99 @@ +using System.Collections.Generic; + +using SabreTools.Core; +using SabreTools.Core.Tools; +using SabreTools.Logging; + +namespace SabreTools.Filtering +{ + /// + /// Represents the filtering operations that need to be performed on a DatHeader + /// + /// TODO: Investigate how to reduce the amount of hardcoded filter statements + /// TODO: Add DatHeader filters + public class DatHeaderFilter + { + #region Logging + + /// + /// Logging object + /// + private readonly Logger logger; + + #endregion + + #region Constructors + + /// + /// Constructor + /// + public DatHeaderFilter() + { + logger = new Logger(this); + } + + #endregion + + #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) + { + // If we don't even have a possible filter pair + if (!filterPair.Contains(":")) + { + logger.Warning($"'{filterPair}` is not a valid filter string. Valid filter strings are of the form 'key:value'. Please refer to README.1ST or the help feature for more details."); + continue; + } + + 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'); + + DatHeaderField filterField = filterFieldString.AsDatHeaderField(); + 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(DatHeaderField 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(DatHeaderField key, string value, bool negate) + { + switch (key) + { + // TODO: Add DatHeader filters + } + } + + #endregion + } +} diff --git a/SabreTools.Filtering/DatItemFilter.cs b/SabreTools.Filtering/DatItemFilter.cs new file mode 100644 index 00000000..9df47f71 --- /dev/null +++ b/SabreTools.Filtering/DatItemFilter.cs @@ -0,0 +1,814 @@ +using System; +using System.Collections.Generic; + +using SabreTools.Core; +using SabreTools.Core.Tools; +using SabreTools.Logging; + +namespace SabreTools.Filtering +{ + /// + /// Represents the filtering operations that need to be performed on a set of items, usually a DAT + /// + /// TODO: Can clever use of Filtering allow for easier external splitting methods? + /// TODO: Investigate how to reduce the amount of hardcoded filter statements + public class DatItemFilter + { + #region Fields + + #region Common + + public FilterItem Type { get; private set; } = new FilterItem(); + + #endregion + + #region Item-Specific + + #region Actionable + + // Rom + public FilterItem Name { get; private set; } = new FilterItem(); + public FilterItem Bios { get; private set; } = new FilterItem(); + public FilterItem Size { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem CRC { get; private set; } = new FilterItem(); + public FilterItem MD5 { get; private set; } = new FilterItem(); +#if NET_FRAMEWORK + public FilterItem RIPEMD160 { get; private set; } = new FilterItem(); +#endif + public FilterItem SHA1 { get; private set; } = new FilterItem(); + public FilterItem SHA256 { get; private set; } = new FilterItem(); + public FilterItem SHA384 { get; private set; } = new FilterItem(); + public FilterItem SHA512 { get; private set; } = new FilterItem(); + public FilterItem SpamSum { get; private set; } = new FilterItem(); + public FilterItem Merge { get; private set; } = new FilterItem(); + public FilterItem Region { get; private set; } = new FilterItem(); + public FilterItem Offset { get; private set; } = new FilterItem(); + public FilterItem Date { get; private set; } = new FilterItem(); + public FilterItem Status { get; private set; } = new FilterItem() { Positive = ItemStatus.NULL, Negative = ItemStatus.NULL }; + public FilterItem Optional { get; private set; } = new FilterItem() { Neutral = null }; + public FilterItem Inverted { get; private set; } = new FilterItem(); + + // Rom (AttractMode) + public FilterItem AltName { get; private set; } = new FilterItem(); + public FilterItem AltTitle { get; private set; } = new FilterItem(); + + // Rom (OpenMSX) + public FilterItem Original { get; private set; } = new FilterItem(); + public FilterItem OpenMSXSubType { get; private set; } = new FilterItem() { Positive = Core.OpenMSXSubType.NULL, Negative = Core.OpenMSXSubType.NULL }; + public FilterItem OpenMSXType { get; private set; } = new FilterItem(); + public FilterItem Remark { get; private set; } = new FilterItem(); + public FilterItem Boot { get; private set; } = new FilterItem(); + + // Rom (SoftwareList) + public FilterItem LoadFlag { get; private set; } = new FilterItem() { Positive = Core.LoadFlag.NULL, Negative = Core.LoadFlag.NULL }; + public FilterItem Value { get; private set; } = new FilterItem(); + + // Disk + public FilterItem Index { get; private set; } = new FilterItem(); + public FilterItem Writable { get; private set; } = new FilterItem() { Neutral = null }; + + #endregion + + #region Auxiliary + + // Adjuster + public FilterItem Default { get; private set; } = new FilterItem() { Neutral = null }; + + // Analog + public FilterItem Analog_Mask { get; private set; } = new FilterItem(); + + // BiosSet + public FilterItem Description { get; private set; } = new FilterItem(); + + // Chip + public FilterItem Tag { get; private set; } = new FilterItem(); + public FilterItem ChipType { get; private set; } = new FilterItem() { Positive = Core.ChipType.NULL, Negative = Core.ChipType.NULL }; + public FilterItem Clock { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + + // Condition + public FilterItem Mask { get; private set; } = new FilterItem(); + public FilterItem Relation { get; private set; } = new FilterItem() { Positive = Core.Relation.NULL, Negative = Core.Relation.NULL }; + public FilterItem Condition_Tag { get; private set; } = new FilterItem(); + public FilterItem Condition_Mask { get; private set; } = new FilterItem(); + public FilterItem Condition_Relation { get; private set; } = new FilterItem() { Positive = Core.Relation.NULL, Negative = Core.Relation.NULL }; + public FilterItem Condition_Value { get; private set; } = new FilterItem(); + + // Control + public FilterItem Control_Type { get; private set; } = new FilterItem() { Positive = ControlType.NULL, Negative = ControlType.NULL }; + public FilterItem Control_Player { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem Control_Buttons { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem Control_ReqButtons { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem Control_Minimum { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem Control_Maximum { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem Control_Sensitivity { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem Control_KeyDelta { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem Control_Reverse { get; private set; } = new FilterItem() { Neutral = null }; + public FilterItem Control_Ways { get; private set; } = new FilterItem(); + public FilterItem Control_Ways2 { get; private set; } = new FilterItem(); + public FilterItem Control_Ways3 { get; private set; } = new FilterItem(); + + // DataArea + public FilterItem AreaName { get; private set; } = new FilterItem(); + public FilterItem AreaSize { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem AreaWidth { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem AreaEndianness { get; private set; } = new FilterItem() { Positive = Endianness.NULL, Negative = Endianness.NULL }; + + // Device + public FilterItem DeviceType { get; private set; } = new FilterItem() { Positive = Core.DeviceType.NULL, Negative = Core.DeviceType.NULL }; + public FilterItem FixedImage { get; private set; } = new FilterItem(); + public FilterItem Mandatory { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem Interface { get; private set; } = new FilterItem(); + + // Display + public FilterItem DisplayType { get; private set; } = new FilterItem() { Positive = Core.DisplayType.NULL, Negative = Core.DisplayType.NULL }; + public FilterItem Rotate { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem FlipX { get; private set; } = new FilterItem() { Neutral = null }; + public FilterItem Width { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem Height { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem Refresh { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem PixClock { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem HTotal { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem HBEnd { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem HBStart { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem VTotal { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem VBEnd { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem VBStart { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + + // Driver + public FilterItem SupportStatus { get; private set; } = new FilterItem() { Positive = Core.SupportStatus.NULL, Negative = Core.SupportStatus.NULL }; + public FilterItem EmulationStatus { get; private set; } = new FilterItem() { Positive = Core.SupportStatus.NULL, Negative = Core.SupportStatus.NULL }; + public FilterItem CocktailStatus { get; private set; } = new FilterItem() { Positive = Core.SupportStatus.NULL, Negative = Core.SupportStatus.NULL }; + public FilterItem SaveStateStatus { get; private set; } = new FilterItem() { Positive = Supported.NULL, Negative = Supported.NULL }; + + // Extension + public FilterItem Extension_Name { get; private set; } = new FilterItem(); + + // Feature + public FilterItem FeatureType { get; private set; } = new FilterItem() { Positive = Core.FeatureType.NULL, Negative = Core.FeatureType.NULL }; + public FilterItem FeatureStatus { get; private set; } = new FilterItem() { Positive = Core.FeatureStatus.NULL, Negative = Core.FeatureStatus.NULL }; + public FilterItem FeatureOverall { get; private set; } = new FilterItem() { Positive = Core.FeatureStatus.NULL, Negative = Core.FeatureStatus.NULL }; + + // Input + public FilterItem Service { get; private set; } = new FilterItem() { Neutral = null }; + public FilterItem Tilt { get; private set; } = new FilterItem() { Neutral = null }; + public FilterItem Players { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem Coins { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + + // Instance + public FilterItem Instance_Name { get; private set; } = new FilterItem(); + public FilterItem Instance_BriefName { get; private set; } = new FilterItem(); + + // Location + public FilterItem Location_Name { get; private set; } = new FilterItem(); + public FilterItem Location_Number { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + public FilterItem Location_Inverted { get; private set; } = new FilterItem() { Neutral = null }; + + // Part + public FilterItem Part_Name { get; private set; } = new FilterItem(); + public FilterItem Part_Interface { get; private set; } = new FilterItem(); + + // PartFeature + public FilterItem Part_Feature_Name { get; private set; } = new FilterItem(); + public FilterItem Part_Feature_Value { get; private set; } = new FilterItem(); + + // RamOption + public FilterItem Content { get; private set; } = new FilterItem(); + + // Release + public FilterItem Language { get; private set; } = new FilterItem(); + + // Setting + public FilterItem Setting_Name { get; private set; } = new FilterItem(); + public FilterItem Setting_Value { get; private set; } = new FilterItem(); + public FilterItem Setting_Default { get; private set; } = new FilterItem() { Neutral = null }; + + // SlotOption + public FilterItem SlotOption_Name { get; private set; } = new FilterItem(); + public FilterItem SlotOption_DeviceName { get; private set; } = new FilterItem(); + public FilterItem SlotOption_Default { get; private set; } = new FilterItem() { Neutral = null }; + + // SoftwareList + public FilterItem SoftwareListStatus { get; private set; } = new FilterItem() { Positive = Core.SoftwareListStatus.NULL, Negative = Core.SoftwareListStatus.NULL }; + public FilterItem Filter { get; private set; } = new FilterItem(); + + // Sound + public FilterItem Channels { get; private set; } = new FilterItem() { Positive = null, Negative = null, Neutral = null }; + + #endregion + + #endregion // Item-Specific + + #endregion // Fields + + #region Logging + + /// + /// Logging object + /// + private readonly Logger logger; + + #endregion + + #region Constructors + + /// + /// Constructor + /// + public DatItemFilter() + { + logger = new Logger(this); + } + + #endregion + + #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) + { + // If we don't even have a possible filter pair + if (!filterPair.Contains(":")) + { + logger.Warning($"'{filterPair}` is not a valid filter string. Valid filter strings are of the form 'key:value'. Please refer to README.1ST or the help feature for more details."); + continue; + } + + 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'); + + DatItemField filterField = filterFieldString.AsDatItemField(); + 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(DatItemField 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(DatItemField key, string value, bool negate) + { + switch (key) + { + #region Common + + case DatItemField.Type: + if (value.AsItemType() == null) + return; + + SetStringFilter(Type, value, negate); + break; + + #endregion + + #region Item-Specific + + #region Actionable + + // Rom + case DatItemField.Name: + SetStringFilter(Name, value, negate); + break; + + case DatItemField.Bios: + SetStringFilter(Bios, value, negate); + break; + + case DatItemField.Size: + SetLongFilter(Size, value, negate); + break; + + case DatItemField.CRC: + SetStringFilter(CRC, value, negate); + break; + + case DatItemField.MD5: + SetStringFilter(MD5, value, negate); + break; + +#if NET_FRAMEWORK + case DatItemField.RIPEMD160: + SetStringFilter(RIPEMD160, value, negate); + break; +#endif + + case DatItemField.SHA1: + SetStringFilter(SHA1, value, negate); + break; + + case DatItemField.SHA256: + SetStringFilter(SHA256, value, negate); + break; + + case DatItemField.SHA384: + SetStringFilter(SHA384, value, negate); + break; + + case DatItemField.SHA512: + SetStringFilter(SHA512, value, negate); + break; + + case DatItemField.SpamSum: + SetStringFilter(SpamSum, value, negate); + break; + + case DatItemField.Merge: + SetStringFilter(Merge, value, negate); + break; + + case DatItemField.Region: + SetStringFilter(Region, value, negate); + break; + + case DatItemField.Offset: + SetStringFilter(Offset, value, negate); + break; + + case DatItemField.Date: + SetStringFilter(Date, value, negate); + break; + + case DatItemField.Status: + if (negate) + Status.Negative |= value.AsItemStatus(); + else + Status.Positive |= value.AsItemStatus(); + break; + + case DatItemField.Optional: + SetBooleanFilter(Optional, value, negate); + break; + + case DatItemField.Inverted: + SetBooleanFilter(Inverted, value, negate); + break; + + // Rom (AttractMode) + case DatItemField.AltName: + SetStringFilter(AltName, value, negate); + break; + + case DatItemField.AltTitle: + SetStringFilter(AltTitle, value, negate); + break; + + // Rom (OpenMSX) + case DatItemField.Original: + SetStringFilter(Original, value, negate); + break; + + case DatItemField.OpenMSXSubType: + if (negate) + OpenMSXSubType.Negative |= value.AsOpenMSXSubType(); + else + OpenMSXSubType.Positive |= value.AsOpenMSXSubType(); + break; + + case DatItemField.OpenMSXType: + SetStringFilter(OpenMSXType, value, negate); + break; + + case DatItemField.Remark: + SetStringFilter(Remark, value, negate); + break; + + case DatItemField.Boot: + SetStringFilter(Boot, value, negate); + break; + + // Rom (SoftwareList) + case DatItemField.LoadFlag: + if (negate) + LoadFlag.Negative |= value.AsLoadFlag(); + else + LoadFlag.Positive |= value.AsLoadFlag(); + break; + + case DatItemField.Value: + SetStringFilter(Value, value, negate); + break; + + // Disk + case DatItemField.Index: + SetStringFilter(Index, value, negate); + break; + + case DatItemField.Writable: + SetBooleanFilter(Writable, value, negate); + break; + + #endregion + + #region Auxiliary + + // Adjuster + case DatItemField.Default: + SetBooleanFilter(Default, value, negate); + break; + + // Analog + case DatItemField.Analog_Mask: + SetStringFilter(Analog_Mask, value, negate); + break; + + // BiosSet + case DatItemField.Description: + SetStringFilter(Description, value, negate); + break; + + // Chip + case DatItemField.Tag: + SetStringFilter(Tag, value, negate); + break; + + case DatItemField.ChipType: + if (negate) + ChipType.Negative |= value.AsChipType(); + else + ChipType.Positive |= value.AsChipType(); + break; + + case DatItemField.Clock: + SetLongFilter(Clock, value, negate); + break; + + // Condition + case DatItemField.Mask: + SetStringFilter(Mask, value, negate); + break; + + case DatItemField.Relation: + if (negate) + Relation.Negative |= value.AsRelation(); + else + Relation.Positive |= value.AsRelation(); + break; + + case DatItemField.Condition_Tag: + SetStringFilter(Condition_Tag, value, negate); + break; + + case DatItemField.Condition_Mask: + SetStringFilter(Condition_Mask, value, negate); + break; + + case DatItemField.Condition_Relation: + if (negate) + Condition_Relation.Negative |= value.AsRelation(); + else + Condition_Relation.Positive |= value.AsRelation(); + break; + + case DatItemField.Condition_Value: + SetStringFilter(Condition_Value, value, negate); + break; + + // Control + case DatItemField.Control_Type: + + if (negate) + Control_Type.Negative |= value.AsControlType(); + else + Control_Type.Positive |= value.AsControlType(); + break; + + case DatItemField.Control_Player: + SetLongFilter(Control_Player, value, negate); + break; + + case DatItemField.Control_Buttons: + SetLongFilter(Control_Buttons, value, negate); + break; + + case DatItemField.Control_RequiredButtons: + SetLongFilter(Control_ReqButtons, value, negate); + break; + + case DatItemField.Control_Minimum: + SetLongFilter(Control_Minimum, value, negate); + break; + + case DatItemField.Control_Maximum: + SetLongFilter(Control_Maximum, value, negate); + break; + + case DatItemField.Control_Sensitivity: + SetLongFilter(Control_Sensitivity, value, negate); + break; + + case DatItemField.Control_KeyDelta: + SetLongFilter(Control_KeyDelta, value, negate); + break; + + case DatItemField.Control_Reverse: + SetBooleanFilter(Control_Reverse, value, negate); + break; + + case DatItemField.Control_Ways: + SetStringFilter(Control_Ways, value, negate); + break; + + case DatItemField.Control_Ways2: + SetStringFilter(Control_Ways2, value, negate); + break; + + case DatItemField.Control_Ways3: + SetStringFilter(Control_Ways3, value, negate); + break; + + // DataArea + case DatItemField.AreaName: + SetStringFilter(AreaName, value, negate); + break; + + case DatItemField.AreaSize: + SetLongFilter(AreaSize, value, negate); + break; + + case DatItemField.AreaWidth: + SetLongFilter(AreaWidth, value, negate); + break; + + case DatItemField.AreaEndianness: + if (negate) + AreaEndianness.Negative |= value.AsEndianness(); + else + AreaEndianness.Positive |= value.AsEndianness(); + break; + + // Device + case DatItemField.DeviceType: + if (negate) + DeviceType.Negative |= value.AsDeviceType(); + else + DeviceType.Positive |= value.AsDeviceType(); + break; + + case DatItemField.FixedImage: + SetStringFilter(FixedImage, value, negate); + break; + + case DatItemField.Mandatory: + SetLongFilter(Mandatory, value, negate); + break; + + case DatItemField.Interface: + SetStringFilter(Interface, value, negate); + break; + + // Display + case DatItemField.DisplayType: + if (negate) + DisplayType.Negative |= value.AsDisplayType(); + else + DisplayType.Positive |= value.AsDisplayType(); + break; + + case DatItemField.Rotate: + SetLongFilter(Rotate, value, negate); + break; + + case DatItemField.FlipX: + SetBooleanFilter(FlipX, value, negate); + break; + + case DatItemField.Width: + SetLongFilter(Width, value, negate); + break; + + case DatItemField.Height: + SetLongFilter(Height, value, negate); + break; + + case DatItemField.Refresh: + SetDoubleFilter(Refresh, value, negate); + break; + + case DatItemField.PixClock: + SetLongFilter(PixClock, value, negate); + break; + + case DatItemField.HTotal: + SetLongFilter(HTotal, value, negate); + break; + + case DatItemField.HBEnd: + SetLongFilter(HBEnd, value, negate); + break; + + case DatItemField.HBStart: + SetLongFilter(HBStart, value, negate); + break; + + case DatItemField.VTotal: + SetLongFilter(VTotal, value, negate); + break; + + case DatItemField.VBEnd: + SetLongFilter(VBEnd, value, negate); + break; + + case DatItemField.VBStart: + SetLongFilter(VBStart, value, negate); + break; + + // Driver + case DatItemField.SupportStatus: + if (negate) + SupportStatus.Negative |= value.AsSupportStatus(); + else + SupportStatus.Positive |= value.AsSupportStatus(); + break; + + case DatItemField.EmulationStatus: + if (negate) + EmulationStatus.Negative |= value.AsSupportStatus(); + else + EmulationStatus.Positive |= value.AsSupportStatus(); + break; + + case DatItemField.CocktailStatus: + if (negate) + CocktailStatus.Negative |= value.AsSupportStatus(); + else + CocktailStatus.Positive |= value.AsSupportStatus(); + break; + + case DatItemField.SaveStateStatus: + if (negate) + SaveStateStatus.Negative |= value.AsSupported(); + else + SaveStateStatus.Positive |= value.AsSupported(); + break; + + // Extension + case DatItemField.Extension_Name: + SetStringFilter(Extension_Name, value, negate); + break; + + // Feature + case DatItemField.FeatureType: + if (negate) + FeatureType.Negative |= value.AsFeatureType(); + else + FeatureType.Positive |= value.AsFeatureType(); + break; + + case DatItemField.FeatureStatus: + if (negate) + FeatureStatus.Negative |= value.AsFeatureStatus(); + else + FeatureStatus.Positive |= value.AsFeatureStatus(); + break; + + case DatItemField.FeatureOverall: + if (negate) + FeatureOverall.Negative |= value.AsFeatureStatus(); + else + FeatureOverall.Positive |= value.AsFeatureStatus(); + break; + + // Input + case DatItemField.Service: + SetBooleanFilter(Service, value, negate); + break; + + case DatItemField.Tilt: + SetBooleanFilter(Tilt, value, negate); + break; + + case DatItemField.Players: + SetLongFilter(Players, value, negate); + break; + + case DatItemField.Coins: + SetLongFilter(Coins, value, negate); + break; + + // Instance + case DatItemField.Instance_Name: + SetStringFilter(Instance_Name, value, negate); + break; + + case DatItemField.Instance_BriefName: + SetStringFilter(Instance_BriefName, value, negate); + break; + + // Location + case DatItemField.Location_Name: + SetStringFilter(Location_Name, value, negate); + break; + + case DatItemField.Location_Number: + SetLongFilter(Location_Number, value, negate); + break; + + case DatItemField.Location_Inverted: + SetBooleanFilter(Location_Inverted, value, negate); + break; + + // Part + case DatItemField.Part_Name: + SetStringFilter(Part_Name, value, negate); + break; + + case DatItemField.Part_Interface: + SetStringFilter(Part_Interface, value, negate); + break; + + // PartFeature + case DatItemField.Part_Feature_Name: + SetStringFilter(Part_Feature_Name, value, negate); + break; + + case DatItemField.Part_Feature_Value: + SetStringFilter(Part_Feature_Value, value, negate); + break; + + // RamOption + case DatItemField.Content: + SetStringFilter(Content, value, negate); + break; + + // Release + case DatItemField.Language: + SetStringFilter(Language, value, negate); + break; + + // Setting + case DatItemField.Setting_Name: + SetStringFilter(Setting_Name, value, negate); + break; + + case DatItemField.Setting_Value: + SetStringFilter(Setting_Value, value, negate); + break; + + case DatItemField.Setting_Default: + SetBooleanFilter(Setting_Default, value, negate); + break; + + // SlotOption + case DatItemField.SlotOption_Name: + SetStringFilter(SlotOption_Name, value, negate); + break; + + case DatItemField.SlotOption_DeviceName: + SetStringFilter(SlotOption_DeviceName, value, negate); + break; + + case DatItemField.SlotOption_Default: + SetBooleanFilter(SlotOption_Default, value, negate); + break; + + // SoftwareList + case DatItemField.SoftwareListStatus: + if (negate) + SoftwareListStatus.Negative |= value.AsSoftwareListStatus(); + else + SoftwareListStatus.Positive |= value.AsSoftwareListStatus(); + break; + + case DatItemField.Filter: + SetStringFilter(Filter, value, negate); + break; + + // Sound + case DatItemField.Channels: + SetLongFilter(Channels, value, negate); + break; + + #endregion + + #endregion // Item-Specific + } + } + } +} diff --git a/SabreTools.Filtering/Filter.cs b/SabreTools.Filtering/Filter.cs index b93d366e..9b5cd627 100644 --- a/SabreTools.Filtering/Filter.cs +++ b/SabreTools.Filtering/Filter.cs @@ -339,6 +339,32 @@ namespace SabreTools.Filtering Field filterField = filterFieldString.AsField(); SetFilter(filterField, filterValue, negate); + + // Set DatHeader filters + DatHeaderField datHeaderField= filterFieldString.AsDatHeaderField(); + if (datHeaderField != DatHeaderField.NULL) + { + SetFilter(datHeaderField, filterValue, negate); + continue; + } + + // Set Machine filters + MachineField machineField= filterFieldString.AsMachineField(); + if (machineField != MachineField.NULL) + { + SetFilter(machineField, filterValue, negate); + continue; + } + + // Set DatItem filters + DatItemField datItemField= filterFieldString.AsDatItemField(); + if (datItemField != DatItemField.NULL) + { + SetFilter(datItemField, filterValue, negate); + continue; + } + + // TODO: Add log here if it all falls through } } @@ -356,6 +382,48 @@ namespace SabreTools.Filtering } } + /// + /// 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(DatHeaderField key, List values, bool negate) + { + foreach (string value in values) + { + SetFilter(key, value, 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(MachineField key, List values, bool negate) + { + foreach (string value in values) + { + SetFilter(key, value, 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(DatItemField key, List values, bool negate) + { + foreach (string value in values) + { + SetFilter(key, value, negate); + } + } + /// /// Set a single filter from key /// @@ -1085,6 +1153,753 @@ namespace SabreTools.Filtering } } + /// + /// 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(DatHeaderField key, string value, bool negate) + { + switch (key) + { + // TODO: Add DatHeader filters + } + } + + /// + /// 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(MachineField key, string value, bool negate) + { + switch (key) + { + #region Common + + case MachineField.Name: + SetStringFilter(Machine_Name, value, negate); + break; + + case MachineField.Comment: + SetStringFilter(Machine_Comment, value, negate); + break; + + case MachineField.Description: + SetStringFilter(Machine_Description, value, negate); + break; + + case MachineField.Year: + SetStringFilter(Machine_Year, value, negate); + break; + + case MachineField.Manufacturer: + SetStringFilter(Machine_Manufacturer, value, negate); + break; + + case MachineField.Publisher: + SetStringFilter(Machine_Publisher, value, negate); + break; + + case MachineField.Category: + SetStringFilter(Machine_Category, value, negate); + break; + + case MachineField.RomOf: + SetStringFilter(Machine_RomOf, value, negate); + break; + + case MachineField.CloneOf: + SetStringFilter(Machine_CloneOf, value, negate); + break; + + case MachineField.SampleOf: + SetStringFilter(Machine_SampleOf, value, negate); + break; + + case MachineField.Type: + if (negate) + Machine_Type.Negative |= value.AsMachineType(); + else + Machine_Type.Positive |= value.AsMachineType(); + break; + + #endregion + + #region AttractMode + + case MachineField.Players: + SetStringFilter(Machine_Players, value, negate); + break; + + case MachineField.Rotation: + SetStringFilter(Machine_Rotation, value, negate); + break; + + case MachineField.Control: + SetStringFilter(Machine_Control, value, negate); + break; + + case MachineField.Status: + SetStringFilter(Machine_Status, value, negate); + break; + + case MachineField.DisplayCount: + SetStringFilter(Machine_DisplayCount, value, negate); + break; + + case MachineField.DisplayType: + SetStringFilter(Machine_DisplayType, value, negate); + break; + + case MachineField.Buttons: + SetStringFilter(Machine_Buttons, value, negate); + break; + + #endregion + + #region ListXML + + case MachineField.SourceFile: + SetStringFilter(Machine_SourceFile, value, negate); + break; + + case MachineField.Runnable: + if (negate) + Machine_Runnable.Negative |= value.AsRunnable(); + else + Machine_Runnable.Positive |= value.AsRunnable(); + break; + + #endregion + + #region Logiqx + + case MachineField.Board: + SetStringFilter(Machine_Board, value, negate); + break; + + case MachineField.RebuildTo: + SetStringFilter(Machine_RebuildTo, value, negate); + break; + + #endregion + + #region Logiqx EmuArc + + case MachineField.TitleID: + SetStringFilter(Machine_TitleID, value, negate); + break; + + case MachineField.Developer: + SetStringFilter(Machine_Developer, value, negate); + break; + + case MachineField.Genre: + SetStringFilter(Machine_Genre, value, negate); + break; + + case MachineField.Subgenre: + SetStringFilter(Machine_Subgenre, value, negate); + break; + + case MachineField.Ratings: + SetStringFilter(Machine_Ratings, value, negate); + break; + + case MachineField.Score: + SetStringFilter(Machine_Score, value, negate); + break; + + case MachineField.Enabled: + SetStringFilter(Machine_Enabled, value, negate); + break; + + case MachineField.CRC: + SetBooleanFilter(Machine_CRC, value, negate); + break; + + case MachineField.RelatedTo: + SetStringFilter(Machine_RelatedTo, value, negate); + break; + + #endregion + + #region OpenMSX + + case MachineField.GenMSXID: + SetStringFilter(Machine_GenMSXID, value, negate); + break; + + case MachineField.System: + SetStringFilter(Machine_System, value, negate); + break; + + case MachineField.Country: + SetStringFilter(Machine_Country, value, negate); + break; + + #endregion + + #region SoftwareList + + case MachineField.Supported: + if (negate) + Machine_Supported.Negative |= value.AsSupported(); + else + Machine_Supported.Positive |= value.AsSupported(); + break; + + #endregion + } + } + + /// + /// 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(DatItemField key, string value, bool negate) + { + switch (key) + { + #region Common + + case DatItemField.Type: + if (value.AsItemType() == null) + return; + + SetStringFilter(DatItem_Type, value, negate); + break; + + #endregion + + #region Item-Specific + + #region Actionable + + // Rom + case DatItemField.Name: + SetStringFilter(DatItem_Name, value, negate); + break; + + case DatItemField.Bios: + SetStringFilter(DatItem_Bios, value, negate); + break; + + case DatItemField.Size: + SetLongFilter(DatItem_Size, value, negate); + break; + + case DatItemField.CRC: + SetStringFilter(DatItem_CRC, value, negate); + break; + + case DatItemField.MD5: + SetStringFilter(DatItem_MD5, value, negate); + break; + +#if NET_FRAMEWORK + case DatItemField.RIPEMD160: + SetStringFilter(DatItem_RIPEMD160, value, negate); + break; +#endif + + case DatItemField.SHA1: + SetStringFilter(DatItem_SHA1, value, negate); + break; + + case DatItemField.SHA256: + SetStringFilter(DatItem_SHA256, value, negate); + break; + + case DatItemField.SHA384: + SetStringFilter(DatItem_SHA384, value, negate); + break; + + case DatItemField.SHA512: + SetStringFilter(DatItem_SHA512, value, negate); + break; + + case DatItemField.SpamSum: + SetStringFilter(DatItem_SpamSum, value, negate); + break; + + case DatItemField.Merge: + SetStringFilter(DatItem_Merge, value, negate); + break; + + case DatItemField.Region: + SetStringFilter(DatItem_Region, value, negate); + break; + + case DatItemField.Offset: + SetStringFilter(DatItem_Offset, value, negate); + break; + + case DatItemField.Date: + SetStringFilter(DatItem_Date, value, negate); + break; + + case DatItemField.Status: + if (negate) + DatItem_Status.Negative |= value.AsItemStatus(); + else + DatItem_Status.Positive |= value.AsItemStatus(); + break; + + case DatItemField.Optional: + SetBooleanFilter(DatItem_Optional, value, negate); + break; + + case DatItemField.Inverted: + SetBooleanFilter(DatItem_Inverted, value, negate); + break; + + // Rom (AttractMode) + case DatItemField.AltName: + SetStringFilter(DatItem_AltName, value, negate); + break; + + case DatItemField.AltTitle: + SetStringFilter(DatItem_AltTitle, value, negate); + break; + + // Rom (OpenMSX) + case DatItemField.Original: + SetStringFilter(DatItem_Original, value, negate); + break; + + case DatItemField.OpenMSXSubType: + if (negate) + DatItem_OpenMSXSubType.Negative |= value.AsOpenMSXSubType(); + else + DatItem_OpenMSXSubType.Positive |= value.AsOpenMSXSubType(); + break; + + case DatItemField.OpenMSXType: + SetStringFilter(DatItem_OpenMSXType, value, negate); + break; + + case DatItemField.Remark: + SetStringFilter(DatItem_Remark, value, negate); + break; + + case DatItemField.Boot: + SetStringFilter(DatItem_Boot, value, negate); + break; + + // Rom (SoftwareList) + case DatItemField.LoadFlag: + if (negate) + DatItem_LoadFlag.Negative |= value.AsLoadFlag(); + else + DatItem_LoadFlag.Positive |= value.AsLoadFlag(); + break; + + case DatItemField.Value: + SetStringFilter(DatItem_Value, value, negate); + break; + + // Disk + case DatItemField.Index: + SetStringFilter(DatItem_Index, value, negate); + break; + + case DatItemField.Writable: + SetBooleanFilter(DatItem_Writable, value, negate); + break; + + #endregion + + #region Auxiliary + + // Adjuster + case DatItemField.Default: + SetBooleanFilter(DatItem_Default, value, negate); + break; + + // Analog + case DatItemField.Analog_Mask: + SetStringFilter(DatItem_Analog_Mask, value, negate); + break; + + // BiosSet + case DatItemField.Description: + SetStringFilter(DatItem_Description, value, negate); + break; + + // Chip + case DatItemField.Tag: + SetStringFilter(DatItem_Tag, value, negate); + break; + + case DatItemField.ChipType: + if (negate) + DatItem_ChipType.Negative |= value.AsChipType(); + else + DatItem_ChipType.Positive |= value.AsChipType(); + break; + + case DatItemField.Clock: + SetLongFilter(DatItem_Clock, value, negate); + break; + + // Condition + case DatItemField.Mask: + SetStringFilter(DatItem_Mask, value, negate); + break; + + case DatItemField.Relation: + if (negate) + DatItem_Relation.Negative |= value.AsRelation(); + else + DatItem_Relation.Positive |= value.AsRelation(); + break; + + case DatItemField.Condition_Tag: + SetStringFilter(DatItem_Condition_Tag, value, negate); + break; + + case DatItemField.Condition_Mask: + SetStringFilter(DatItem_Condition_Mask, value, negate); + break; + + case DatItemField.Condition_Relation: + if (negate) + DatItem_Condition_Relation.Negative |= value.AsRelation(); + else + DatItem_Condition_Relation.Positive |= value.AsRelation(); + break; + + case DatItemField.Condition_Value: + SetStringFilter(DatItem_Condition_Value, value, negate); + break; + + // Control + case DatItemField.Control_Type: + + if (negate) + DatItem_Control_Type.Negative |= value.AsControlType(); + else + DatItem_Control_Type.Positive |= value.AsControlType(); + break; + + case DatItemField.Control_Player: + SetLongFilter(DatItem_Control_Player, value, negate); + break; + + case DatItemField.Control_Buttons: + SetLongFilter(DatItem_Control_Buttons, value, negate); + break; + + case DatItemField.Control_RequiredButtons: + SetLongFilter(DatItem_Control_ReqButtons, value, negate); + break; + + case DatItemField.Control_Minimum: + SetLongFilter(DatItem_Control_Minimum, value, negate); + break; + + case DatItemField.Control_Maximum: + SetLongFilter(DatItem_Control_Maximum, value, negate); + break; + + case DatItemField.Control_Sensitivity: + SetLongFilter(DatItem_Control_Sensitivity, value, negate); + break; + + case DatItemField.Control_KeyDelta: + SetLongFilter(DatItem_Control_KeyDelta, value, negate); + break; + + case DatItemField.Control_Reverse: + SetBooleanFilter(DatItem_Control_Reverse, value, negate); + break; + + case DatItemField.Control_Ways: + SetStringFilter(DatItem_Control_Ways, value, negate); + break; + + case DatItemField.Control_Ways2: + SetStringFilter(DatItem_Control_Ways2, value, negate); + break; + + case DatItemField.Control_Ways3: + SetStringFilter(DatItem_Control_Ways3, value, negate); + break; + + // DataArea + case DatItemField.AreaName: + SetStringFilter(DatItem_AreaName, value, negate); + break; + + case DatItemField.AreaSize: + SetLongFilter(DatItem_AreaSize, value, negate); + break; + + case DatItemField.AreaWidth: + SetLongFilter(DatItem_AreaWidth, value, negate); + break; + + case DatItemField.AreaEndianness: + if (negate) + DatItem_AreaEndianness.Negative |= value.AsEndianness(); + else + DatItem_AreaEndianness.Positive |= value.AsEndianness(); + break; + + // Device + case DatItemField.DeviceType: + if (negate) + DatItem_DeviceType.Negative |= value.AsDeviceType(); + else + DatItem_DeviceType.Positive |= value.AsDeviceType(); + break; + + case DatItemField.FixedImage: + SetStringFilter(DatItem_FixedImage, value, negate); + break; + + case DatItemField.Mandatory: + SetLongFilter(DatItem_Mandatory, value, negate); + break; + + case DatItemField.Interface: + SetStringFilter(DatItem_Interface, value, negate); + break; + + // Display + case DatItemField.DisplayType: + if (negate) + DatItem_DisplayType.Negative |= value.AsDisplayType(); + else + DatItem_DisplayType.Positive |= value.AsDisplayType(); + break; + + case DatItemField.Rotate: + SetLongFilter(DatItem_Rotate, value, negate); + break; + + case DatItemField.FlipX: + SetBooleanFilter(DatItem_FlipX, value, negate); + break; + + case DatItemField.Width: + SetLongFilter(DatItem_Width, value, negate); + break; + + case DatItemField.Height: + SetLongFilter(DatItem_Height, value, negate); + break; + + case DatItemField.Refresh: + SetDoubleFilter(DatItem_Refresh, value, negate); + break; + + case DatItemField.PixClock: + SetLongFilter(DatItem_PixClock, value, negate); + break; + + case DatItemField.HTotal: + SetLongFilter(DatItem_HTotal, value, negate); + break; + + case DatItemField.HBEnd: + SetLongFilter(DatItem_HBEnd, value, negate); + break; + + case DatItemField.HBStart: + SetLongFilter(DatItem_HBStart, value, negate); + break; + + case DatItemField.VTotal: + SetLongFilter(DatItem_VTotal, value, negate); + break; + + case DatItemField.VBEnd: + SetLongFilter(DatItem_VBEnd, value, negate); + break; + + case DatItemField.VBStart: + SetLongFilter(DatItem_VBStart, value, negate); + break; + + // Driver + case DatItemField.SupportStatus: + if (negate) + DatItem_SupportStatus.Negative |= value.AsSupportStatus(); + else + DatItem_SupportStatus.Positive |= value.AsSupportStatus(); + break; + + case DatItemField.EmulationStatus: + if (negate) + DatItem_EmulationStatus.Negative |= value.AsSupportStatus(); + else + DatItem_EmulationStatus.Positive |= value.AsSupportStatus(); + break; + + case DatItemField.CocktailStatus: + if (negate) + DatItem_CocktailStatus.Negative |= value.AsSupportStatus(); + else + DatItem_CocktailStatus.Positive |= value.AsSupportStatus(); + break; + + case DatItemField.SaveStateStatus: + if (negate) + DatItem_SaveStateStatus.Negative |= value.AsSupported(); + else + DatItem_SaveStateStatus.Positive |= value.AsSupported(); + break; + + // Extension + case DatItemField.Extension_Name: + SetStringFilter(DatItem_Extension_Name, value, negate); + break; + + // Feature + case DatItemField.FeatureType: + if (negate) + DatItem_FeatureType.Negative |= value.AsFeatureType(); + else + DatItem_FeatureType.Positive |= value.AsFeatureType(); + break; + + case DatItemField.FeatureStatus: + if (negate) + DatItem_FeatureStatus.Negative |= value.AsFeatureStatus(); + else + DatItem_FeatureStatus.Positive |= value.AsFeatureStatus(); + break; + + case DatItemField.FeatureOverall: + if (negate) + DatItem_FeatureOverall.Negative |= value.AsFeatureStatus(); + else + DatItem_FeatureOverall.Positive |= value.AsFeatureStatus(); + break; + + // Input + case DatItemField.Service: + SetBooleanFilter(DatItem_Service, value, negate); + break; + + case DatItemField.Tilt: + SetBooleanFilter(DatItem_Tilt, value, negate); + break; + + case DatItemField.Players: + SetLongFilter(DatItem_Players, value, negate); + break; + + case DatItemField.Coins: + SetLongFilter(DatItem_Coins, value, negate); + break; + + // Instance + case DatItemField.Instance_Name: + SetStringFilter(DatItem_Instance_Name, value, negate); + break; + + case DatItemField.Instance_BriefName: + SetStringFilter(DatItem_Instance_BriefName, value, negate); + break; + + // Location + case DatItemField.Location_Name: + SetStringFilter(DatItem_Location_Name, value, negate); + break; + + case DatItemField.Location_Number: + SetLongFilter(DatItem_Location_Number, value, negate); + break; + + case DatItemField.Location_Inverted: + SetBooleanFilter(DatItem_Location_Inverted, value, negate); + break; + + // Part + case DatItemField.Part_Name: + SetStringFilter(DatItem_Part_Name, value, negate); + break; + + case DatItemField.Part_Interface: + SetStringFilter(DatItem_Part_Interface, value, negate); + break; + + // PartFeature + case DatItemField.Part_Feature_Name: + SetStringFilter(DatItem_Part_Feature_Name, value, negate); + break; + + case DatItemField.Part_Feature_Value: + SetStringFilter(DatItem_Part_Feature_Value, value, negate); + break; + + // RamOption + case DatItemField.Content: + SetStringFilter(DatItem_Content, value, negate); + break; + + // Release + case DatItemField.Language: + SetStringFilter(DatItem_Language, value, negate); + break; + + // Setting + case DatItemField.Setting_Name: + SetStringFilter(DatItem_Setting_Name, value, negate); + break; + + case DatItemField.Setting_Value: + SetStringFilter(DatItem_Setting_Value, value, negate); + break; + + case DatItemField.Setting_Default: + SetBooleanFilter(DatItem_Setting_Default, value, negate); + break; + + // SlotOption + case DatItemField.SlotOption_Name: + SetStringFilter(DatItem_SlotOption_Name, value, negate); + break; + + case DatItemField.SlotOption_DeviceName: + SetStringFilter(DatItem_SlotOption_DeviceName, value, negate); + break; + + case DatItemField.SlotOption_Default: + SetBooleanFilter(DatItem_SlotOption_Default, value, negate); + break; + + // SoftwareList + case DatItemField.SoftwareListStatus: + if (negate) + DatItem_SoftwareListStatus.Negative |= value.AsSoftwareListStatus(); + else + DatItem_SoftwareListStatus.Positive |= value.AsSoftwareListStatus(); + break; + + case DatItemField.Filter: + SetStringFilter(DatItem_Filter, value, negate); + break; + + // Sound + case DatItemField.Channels: + SetLongFilter(DatItem_Channels, value, negate); + break; + + #endregion + + #endregion // Item-Specific + } + } + /// /// Set a bool? filter /// diff --git a/SabreTools.Filtering/MachineFilter.cs b/SabreTools.Filtering/MachineFilter.cs new file mode 100644 index 00000000..51b566f8 --- /dev/null +++ b/SabreTools.Filtering/MachineFilter.cs @@ -0,0 +1,361 @@ +using System.Collections.Generic; + +using SabreTools.Core; +using SabreTools.Core.Tools; +using SabreTools.Logging; + +namespace SabreTools.Filtering +{ + /// + /// Represents the filtering operations that need to be performed on a set of items, usually a DAT + /// + /// TODO: Can clever use of Filtering allow for easier external splitting methods? + /// TODO: Investigate how to reduce the amount of hardcoded filter statements + public class MachineFilter + { + #region Fields + + #region Filters + + #region Common + + public FilterItem Name { get; private set; } = new FilterItem(); + public FilterItem Comment { get; private set; } = new FilterItem(); + public FilterItem Description { get; private set; } = new FilterItem(); + public FilterItem Year { get; private set; } = new FilterItem(); + public FilterItem Manufacturer { get; private set; } = new FilterItem(); + public FilterItem Publisher { get; private set; } = new FilterItem(); + public FilterItem Category { get; private set; } = new FilterItem(); + public FilterItem RomOf { get; private set; } = new FilterItem(); + public FilterItem CloneOf { get; private set; } = new FilterItem(); + public FilterItem SampleOf { get; private set; } = new FilterItem(); + public FilterItem Type { get; private set; } = new FilterItem() { Positive = 0x0, Negative = 0x0 }; + + #endregion + + #region AttractMode + + public FilterItem Players { get; private set; } = new FilterItem(); + public FilterItem Rotation { get; private set; } = new FilterItem(); + public FilterItem Control { get; private set; } = new FilterItem(); + public FilterItem Status { get; private set; } = new FilterItem(); + public FilterItem DisplayCount { get; private set; } = new FilterItem(); + public FilterItem DisplayType { get; private set; } = new FilterItem(); + public FilterItem Buttons { get; private set; } = new FilterItem(); + + #endregion + + #region ListXML + + public FilterItem SourceFile { get; private set; } = new FilterItem(); + public FilterItem Runnable { get; private set; } = new FilterItem() { Positive = Core.Runnable.NULL, Negative = Core.Runnable.NULL }; + + #endregion + + #region Logiqx + + public FilterItem Board { get; private set; } = new FilterItem(); + public FilterItem RebuildTo { get; private set; } = new FilterItem(); + + #endregion + + #region Logiqx EmuArc + + public FilterItem TitleID { get; private set; } = new FilterItem(); + public FilterItem Developer { get; private set; } = new FilterItem(); + public FilterItem Genre { get; private set; } = new FilterItem(); + public FilterItem Subgenre { get; private set; } = new FilterItem(); + public FilterItem Ratings { get; private set; } = new FilterItem(); + public FilterItem Score { get; private set; } = new FilterItem(); + public FilterItem Enabled { get; private set; } = new FilterItem(); + public FilterItem CRC { get; private set; } = new FilterItem() { Neutral = null }; + public FilterItem RelatedTo { get; private set; } = new FilterItem(); + + #endregion + + #region OpenMSX + + public FilterItem GenMSXID { get; private set; } = new FilterItem(); + public FilterItem System { get; private set; } = new FilterItem(); + public FilterItem Country { get; private set; } = new FilterItem(); + + #endregion + + #region SoftwareList + + public FilterItem Supported { get; private set; } = new FilterItem() { Positive = Core.Supported.NULL, Negative = Core.Supported.NULL }; + + #endregion + + #endregion // Machine Filters + + #region Additional Flags + + /// + /// Include romof and cloneof when filtering machine names + /// + public bool IncludeOfInGame { get; set; } + + #endregion + + #endregion // Fields + + #region Logging + + /// + /// Logging object + /// + private readonly Logger logger; + + #endregion + + #region Constructors + + /// + /// Constructor + /// + public MachineFilter() + { + logger = new Logger(this); + } + + #endregion + + #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) + { + // If we don't even have a possible filter pair + if (!filterPair.Contains(":")) + { + logger.Warning($"'{filterPair}` is not a valid filter string. Valid filter strings are of the form 'key:value'. Please refer to README.1ST or the help feature for more details."); + continue; + } + + 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'); + + MachineField filterField = filterFieldString.AsMachineField(); + 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(MachineField 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(MachineField key, string value, bool negate) + { + switch (key) + { + #region Common + + case MachineField.Name: + SetStringFilter(Name, value, negate); + break; + + case MachineField.Comment: + SetStringFilter(Comment, value, negate); + break; + + case MachineField.Description: + SetStringFilter(Description, value, negate); + break; + + case MachineField.Year: + SetStringFilter(Year, value, negate); + break; + + case MachineField.Manufacturer: + SetStringFilter(Manufacturer, value, negate); + break; + + case MachineField.Publisher: + SetStringFilter(Publisher, value, negate); + break; + + case MachineField.Category: + SetStringFilter(Category, value, negate); + break; + + case MachineField.RomOf: + SetStringFilter(RomOf, value, negate); + break; + + case MachineField.CloneOf: + SetStringFilter(CloneOf, value, negate); + break; + + case MachineField.SampleOf: + SetStringFilter(SampleOf, value, negate); + break; + + case MachineField.Type: + if (negate) + Type.Negative |= value.AsMachineType(); + else + Type.Positive |= value.AsMachineType(); + break; + + #endregion + + #region AttractMode + + case MachineField.Players: + SetStringFilter(Players, value, negate); + break; + + case MachineField.Rotation: + SetStringFilter(Rotation, value, negate); + break; + + case MachineField.Control: + SetStringFilter(Control, value, negate); + break; + + case MachineField.Status: + SetStringFilter(Status, value, negate); + break; + + case MachineField.DisplayCount: + SetStringFilter(DisplayCount, value, negate); + break; + + case MachineField.DisplayType: + SetStringFilter(DisplayType, value, negate); + break; + + case MachineField.Buttons: + SetStringFilter(Buttons, value, negate); + break; + + #endregion + + #region ListXML + + case MachineField.SourceFile: + SetStringFilter(SourceFile, value, negate); + break; + + case MachineField.Runnable: + if (negate) + Runnable.Negative |= value.AsRunnable(); + else + Runnable.Positive |= value.AsRunnable(); + break; + + #endregion + + #region Logiqx + + case MachineField.Board: + SetStringFilter(Board, value, negate); + break; + + case MachineField.RebuildTo: + SetStringFilter(RebuildTo, value, negate); + break; + + #endregion + + #region Logiqx EmuArc + + case MachineField.TitleID: + SetStringFilter(TitleID, value, negate); + break; + + case MachineField.Developer: + SetStringFilter(Developer, value, negate); + break; + + case MachineField.Genre: + SetStringFilter(Genre, value, negate); + break; + + case MachineField.Subgenre: + SetStringFilter(Subgenre, value, negate); + break; + + case MachineField.Ratings: + SetStringFilter(Ratings, value, negate); + break; + + case MachineField.Score: + SetStringFilter(Score, value, negate); + break; + + case MachineField.Enabled: + SetStringFilter(Enabled, value, negate); + break; + + case MachineField.CRC: + SetBooleanFilter(CRC, value, negate); + break; + + case MachineField.RelatedTo: + SetStringFilter(RelatedTo, value, negate); + break; + + #endregion + + #region OpenMSX + + case MachineField.GenMSXID: + SetStringFilter(GenMSXID, value, negate); + break; + + case MachineField.System: + SetStringFilter(System, value, negate); + break; + + case MachineField.Country: + SetStringFilter(Country, value, negate); + break; + + #endregion + + #region SoftwareList + + case MachineField.Supported: + if (negate) + Supported.Negative |= value.AsSupported(); + else + Supported.Positive |= value.AsSupported(); + break; + + #endregion + } + } + + #endregion + } +}