using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using SabreTools.Library.Data;
using SabreTools.Library.DatItems;
namespace SabreTools.Library.DatFiles
{
///
/// Represents the filtering operations that need to be performed on a set of items, usually a DAT
///
public class Filter
{
#region Private instance variables
#region Positive
private List _gameNames;
private List _romNames;
private List _romTypes;
private List _crcs;
private List _md5s;
private List _sha1s;
private List _sha256s;
private List _sha384s;
private List _sha512s;
private ItemStatus _itemStatuses;
private MachineType _machineTypes;
#endregion
#region Negative
private List _notGameNames;
private List _notRomNames;
private List _notRomTypes;
private List _notCrcs;
private List _notMd5s;
private List _notSha1s;
private List _notSha256s;
private List _notSha384s;
private List _notSha512s;
private ItemStatus _itemNotStatuses;
private MachineType _machineNotTypes;
#endregion
#region Neutral
private long _sizeGreaterThanOrEqual;
private long _sizeLessThanOrEqual;
private long _sizeEqualTo;
private bool _includeOfInGame;
private bool? _runnable;
#endregion
#endregion // Private instance variables
#region Pubically facing variables
#region Positive
public List GameNames
{
get { return _gameNames; }
set { _gameNames = value; }
}
public List RomNames
{
get { return _romNames; }
set { _romNames = value; }
}
public List RomTypes
{
get { return _romTypes; }
set { _romTypes = value; }
}
public List CRCs
{
get { return _crcs; }
set { _crcs = value; }
}
public List MD5s
{
get { return _md5s; }
set { _md5s = value; }
}
public List SHA1s
{
get { return _sha1s; }
set { _sha1s = value; }
}
public List SHA256s
{
get { return _sha256s; }
set { _sha256s = value; }
}
public List SHA384s
{
get { return _sha384s; }
set { _sha384s = value; }
}
public List SHA512s
{
get { return _sha512s; }
set { _sha512s = value; }
}
public ItemStatus ItemStatuses
{
get { return _itemStatuses; }
set { _itemStatuses = value; }
}
public MachineType MachineTypes
{
get { return _machineTypes; }
set { _machineTypes = value; }
}
#endregion
#region Negative
public List NotGameNames
{
get { return _notGameNames; }
set { _notGameNames = value; }
}
public List NotRomNames
{
get { return _notRomNames; }
set { _notRomNames = value; }
}
public List NotRomTypes
{
get { return _notRomTypes; }
set { _notRomTypes = value; }
}
public List NotCRCs
{
get { return _notCrcs; }
set { _notCrcs = value; }
}
public List NotMD5s
{
get { return _notMd5s; }
set { _notMd5s = value; }
}
public List NotSHA1s
{
get { return _notSha1s; }
set { _notSha1s = value; }
}
public List NotSHA256s
{
get { return _notSha256s; }
set { _notSha256s = value; }
}
public List NotSHA384s
{
get { return _notSha384s; }
set { _notSha384s = value; }
}
public List NotSHA512s
{
get { return _notSha512s; }
set { _notSha512s = value; }
}
public ItemStatus NotItemStatuses
{
get { return _itemNotStatuses; }
set { _itemNotStatuses = value; }
}
public MachineType NotMachineTypes
{
get { return _machineNotTypes; }
set { _machineNotTypes = value; }
}
#endregion
#region Neutral
public long SizeGreaterThanOrEqual
{
get { return _sizeGreaterThanOrEqual; }
set { _sizeGreaterThanOrEqual = value; }
}
public long SizeLessThanOrEqual
{
get { return _sizeLessThanOrEqual; }
set { _sizeLessThanOrEqual = value; }
}
public long SizeEqualTo
{
get { return _sizeEqualTo; }
set { _sizeEqualTo = value; }
}
public bool IncludeOfInGame
{
get { return _includeOfInGame; }
set { _includeOfInGame = value; }
}
public bool? Runnable
{
get { return _runnable; }
set { _runnable = value; }
}
#endregion
#endregion // Pubically facing variables
#region Constructors
///
/// Create an empty Filter object
///
public Filter()
{
// Positive
_gameNames = new List();
_romNames = new List();
_romTypes = new List();
_crcs = new List();
_md5s = new List();
_sha1s = new List();
_sha256s = new List();
_sha384s = new List();
_sha512s = new List();
_itemStatuses = ItemStatus.NULL;
_machineTypes = MachineType.NULL;
// Negative
_notGameNames = new List();
_notRomNames = new List();
_notRomTypes = new List();
_notCrcs = new List();
_notMd5s = new List();
_notSha1s = new List();
_notSha256s = new List();
_notSha384s = new List();
_notSha512s = new List();
_itemNotStatuses = ItemStatus.NULL;
_machineNotTypes = MachineType.NULL;
// Neutral
_sizeGreaterThanOrEqual = -1;
_sizeLessThanOrEqual = -1;
_sizeEqualTo = -1;
_includeOfInGame = false;
_runnable = null;
}
#endregion
#region Instance methods
///
/// Check to see if a DatItem passes the filter
///
/// DatItem to check
/// True if the file passed the filter, false otherwise
public bool ItemPasses(DatItem item)
{
// If the item is null, we automatically fail it
if (item == null)
{
return false;
}
// Filter on machine type
if (_machineTypes != MachineType.NULL && (item.MachineType & _machineTypes) == 0)
{
return false;
}
if (_machineNotTypes != MachineType.NULL && (item.MachineType & _machineNotTypes) != 0)
{
return false;
}
// Filter on machine runability
if (_runnable != null && item.Runnable != _runnable)
{
return false;
}
// Take care of Rom and Disk specific differences
if (item.Type == ItemType.Rom)
{
Rom rom = (Rom)item;
// Filter on status
if (_itemStatuses != ItemStatus.NULL && (rom.ItemStatus & _itemStatuses) == 0)
{
return false;
}
if (_itemNotStatuses != ItemStatus.NULL && (rom.ItemStatus & _itemNotStatuses) != 0)
{
return false;
}
// Filter on rom size
if (_sizeEqualTo != -1 && rom.Size != _sizeEqualTo)
{
return false;
}
else
{
if (_sizeGreaterThanOrEqual != -1 && rom.Size < _sizeGreaterThanOrEqual)
{
return false;
}
if (_sizeLessThanOrEqual != -1 && rom.Size > _sizeLessThanOrEqual)
{
return false;
}
}
// Filter on CRC
if (_crcs.Count > 0)
{
// If the CRC isn't in the list, return false
if (!FindValueInList(_crcs, rom.CRC))
{
return false;
}
}
if (_notCrcs.Count > 0)
{
// If the CRC is in the list, return false
if (FindValueInList(_notCrcs, rom.CRC))
{
return false;
}
}
// Filter on MD5
if (_md5s.Count > 0)
{
// If the MD5 isn't in the list, return false
if (!FindValueInList(_md5s, rom.MD5))
{
return false;
}
}
if (_notMd5s.Count > 0)
{
// If the MD5 is in the list, return false
if (FindValueInList(_notMd5s, rom.MD5))
{
return false;
}
}
// Filter on SHA1
if (_sha1s.Count > 0)
{
// If the SHA-1 isn't in the list, return false
if (!FindValueInList(_sha1s, rom.SHA1))
{
return false;
}
}
if (_notSha1s.Count > 0)
{
// If the SHA-1 is in the list, return false
if (FindValueInList(_notSha1s, rom.SHA1))
{
return false;
}
}
// Filter on SHA256
if (_sha256s.Count > 0)
{
// If the SHA-1 isn't in the list, return false
if (!FindValueInList(_sha256s, rom.SHA256))
{
return false;
}
}
if (_notSha256s.Count > 0)
{
// If the SHA-1 is in the list, return false
if (FindValueInList(_notSha256s, rom.SHA256))
{
return false;
}
}
// Filter on SHA384
if (_sha384s.Count > 0)
{
// If the SHA-1 isn't in the list, return false
if (!FindValueInList(_sha384s, rom.SHA384))
{
return false;
}
}
if (_notSha384s.Count > 0)
{
// If the SHA-1 is in the list, return false
if (FindValueInList(_notSha384s, rom.SHA384))
{
return false;
}
}
// Filter on SHA512
if (_sha512s.Count > 0)
{
// If the SHA-1 isn't in the list, return false
if (!FindValueInList(_sha512s, rom.SHA512))
{
return false;
}
}
if (_notSha512s.Count > 0)
{
// If the SHA-1 is in the list, return false
if (FindValueInList(_notSha512s, rom.SHA512))
{
return false;
}
}
}
else if (item.Type == ItemType.Disk)
{
Disk rom = (Disk)item;
// Filter on status
if (_itemStatuses != ItemStatus.NULL && (rom.ItemStatus & _itemStatuses) == 0)
{
return false;
}
if (_itemNotStatuses != ItemStatus.NULL && (rom.ItemStatus & _itemNotStatuses) != 0)
{
return false;
}
// Filter on MD5
if (_md5s.Count > 0)
{
// If the MD5 isn't in the list, return false
if (!FindValueInList(_md5s, rom.MD5))
{
return false;
}
}
if (_notMd5s.Count > 0)
{
// If the MD5 is in the list, return false
if (FindValueInList(_notMd5s, rom.MD5))
{
return false;
}
}
// Filter on SHA1
if (_sha1s.Count > 0)
{
// If the SHA-1 isn't in the list, return false
if (!FindValueInList(_sha1s, rom.SHA1))
{
return false;
}
}
if (_notSha1s.Count > 0)
{
// If the SHA-1 is in the list, return false
if (FindValueInList(_notSha1s, rom.SHA1))
{
return false;
}
}
// Filter on SHA256
if (_sha256s.Count > 0)
{
// If the SHA-1 isn't in the list, return false
if (!FindValueInList(_sha256s, rom.SHA256))
{
return false;
}
}
if (_notSha256s.Count > 0)
{
// If the SHA-1 is in the list, return false
if (FindValueInList(_notSha256s, rom.SHA256))
{
return false;
}
}
// Filter on SHA384
if (_sha384s.Count > 0)
{
// If the SHA-1 isn't in the list, return false
if (!FindValueInList(_sha384s, rom.SHA384))
{
return false;
}
}
if (_notSha384s.Count > 0)
{
// If the SHA-1 is in the list, return false
if (FindValueInList(_notSha384s, rom.SHA384))
{
return false;
}
}
// Filter on SHA512
if (_sha512s.Count > 0)
{
// If the SHA-1 isn't in the list, return false
if (!FindValueInList(_sha512s, rom.SHA512))
{
return false;
}
}
if (_notSha512s.Count > 0)
{
// If the SHA-1 is in the list, return false
if (FindValueInList(_notSha512s, rom.SHA512))
{
return false;
}
}
}
// Filter on game name
if (_gameNames.Count > 0)
{
bool found = FindValueInList(_gameNames, item.MachineName);
// If we are checking CloneOf and RomOf, add them in as well
if (_includeOfInGame)
{
found |= FindValueInList(_gameNames, item.CloneOf);
found |= FindValueInList(_gameNames, item.RomOf);
}
// If the game name was not found in the list, return false
if (!found)
{
return false;
}
}
if (_notGameNames.Count > 0)
{
bool found = FindValueInList(_gameNames, item.MachineName);
// If we are checking CloneOf and RomOf, add them in as well
if (_includeOfInGame)
{
found |= FindValueInList(_gameNames, item.CloneOf);
found |= FindValueInList(_gameNames, item.RomOf);
}
// If the game name was found in the list, return false
if (found)
{
return false;
}
}
// Filter on rom name
if (_romNames.Count > 0)
{
// If the rom name was not found in the list, return false
if (!FindValueInList(_romNames, item.Name))
{
return false;
}
}
if (_notRomNames.Count > 0)
{
// If the rom name was found in the list, return false
if (FindValueInList(_notRomNames, item.Name))
{
return false;
}
}
// Filter on rom type
if (_romTypes.Count == 0 && _notRomTypes.Count == 0 && item.Type != ItemType.Rom && item.Type != ItemType.Disk)
{
return false;
}
if (_romTypes.Count > 0)
{
// If the rom type was not found in the list, return false
if (!FindValueInList(_romTypes, item.Type.ToString()))
{
return false;
}
}
if (_notRomTypes.Count > 0)
{
// If the rom type was found in the list, return false
if (FindValueInList(_notRomTypes, item.Type.ToString()))
{
return false;
}
}
return true;
}
///
/// Generic code to check if a specific value is in the list given
///
/// List to search for the value in
/// Value to search the list for
/// True if the value could be found, false otherwise
private bool FindValueInList(List haystack, string needle)
{
bool found = false;
foreach (string straw in haystack)
{
if (!String.IsNullOrEmpty(straw))
{
string regexStraw = straw;
// If the straw has no special characters at all, treat it as an exact match
if (regexStraw == Regex.Escape(regexStraw))
{
regexStraw = "^" + regexStraw + "$";
}
// Check if a match is found with the regex
found |= Regex.IsMatch(needle, regexStraw, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
}
}
return found;
}
#endregion
#region Static methods
///
/// Get the machine type from a string
///
/// Machine type as a string
/// A machine type based on the input
public static MachineType GetMachineTypeFromString(string gametype)
{
MachineType machineType = MachineType.NULL;
switch (gametype.ToLowerInvariant())
{
case "none":
machineType |= MachineType.None;
break;
case "bios":
machineType |= MachineType.Bios;
break;
case "dev":
case "device":
machineType |= MachineType.Device;
break;
case "mech":
case "mechanical":
machineType |= MachineType.Mechanical;
break;
default:
Globals.Logger.Warning("{0} is not a valid type", gametype);
break;
}
return machineType;
}
///
/// Get the item status from a string
///
/// Item status as a string
/// An item status based on the input
public static ItemStatus GetStatusFromString(string status)
{
ItemStatus itemStatus = ItemStatus.NULL;
switch (status.ToLowerInvariant())
{
case "none":
itemStatus |= ItemStatus.None;
break;
case "good":
itemStatus |= ItemStatus.Good;
break;
case "baddump":
itemStatus |= ItemStatus.BadDump;
break;
case "nodump":
itemStatus |= ItemStatus.Nodump;
break;
case "verified":
itemStatus |= ItemStatus.Verified;
break;
default:
Globals.Logger.Warning("{0} is not a valid status", status);
break;
}
return itemStatus;
}
#endregion
}
}