mirror of
https://github.com/claunia/SabreTools.git
synced 2025-12-16 19:14:27 +00:00
Create and use Cleaner
This commit is contained in:
@@ -695,15 +695,49 @@ namespace SabreTools.Library.DatFiles
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
// TODO: Is it possible for all non-cleaning operations to be non-destructive?
|
// TODO: Should the ApplyFilter method contain the splitting logic?
|
||||||
// If items are not flat out removed and just marked for removal instead, this
|
|
||||||
// could allow for rolling back removals and effectively "unfiltering" a DatFile
|
|
||||||
// without too much hassle. On write it would have to take into account these
|
|
||||||
// removed items, however. Similarly, this could lead to interesting issues
|
|
||||||
// with merging and splitting since removed items might end up causing empty
|
|
||||||
// machines on the other side
|
|
||||||
#region Filtering
|
#region Filtering
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Apply cleaning methods to the DatFile
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cleaner">Cleaner to use</param>
|
||||||
|
/// <returns>True if cleaning was successful, false on error</returns>
|
||||||
|
public bool ApplyCleaning(Cleaner cleaner)
|
||||||
|
{
|
||||||
|
// Perform item-level cleaning
|
||||||
|
CleanDatItems(cleaner);
|
||||||
|
|
||||||
|
// Process description to machine name
|
||||||
|
if (cleaner?.DescriptionAsName == true)
|
||||||
|
MachineDescriptionToName();
|
||||||
|
|
||||||
|
// If we are removing scene dates, do that now
|
||||||
|
if (cleaner?.SceneDateStrip == true)
|
||||||
|
StripSceneDatesFromItems();
|
||||||
|
|
||||||
|
// Run the one rom per game logic, if required
|
||||||
|
if (cleaner?.OneGamePerRegion == true)
|
||||||
|
OneGamePerRegion(cleaner.RegionList);
|
||||||
|
|
||||||
|
// Run the one rom per game logic, if required
|
||||||
|
if (cleaner?.OneRomPerGame == true)
|
||||||
|
OneRomPerGame();
|
||||||
|
|
||||||
|
// If we are removing fields, do that now
|
||||||
|
if (cleaner.ExcludeFields != null && cleaner.ExcludeFields.Any())
|
||||||
|
RemoveFieldsFromItems(cleaner.ExcludeFields);
|
||||||
|
|
||||||
|
// Remove all marked items
|
||||||
|
Items.ClearMarked();
|
||||||
|
|
||||||
|
// We remove any blanks, if we aren't supposed to have any
|
||||||
|
if (cleaner?.KeepEmptyGames == false)
|
||||||
|
Items.ClearEmpty();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Apply a set of Extra INIs on the DatFile
|
/// Apply a set of Extra INIs on the DatFile
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -773,15 +807,14 @@ namespace SabreTools.Library.DatFiles
|
|||||||
/// <param name="filter">Filter to use</param>
|
/// <param name="filter">Filter to use</param>
|
||||||
/// <param name="useTags">True if DatFile tags override splitting, false otherwise</param>
|
/// <param name="useTags">True if DatFile tags override splitting, false otherwise</param>
|
||||||
/// <returns>True if the DatFile was filtered, false on error</returns>
|
/// <returns>True if the DatFile was filtered, false on error</returns>
|
||||||
/// TODO: Re-evaluate what should be in here and see if we need to have a "Cleaner" class
|
|
||||||
public bool ApplyFilter(Filter filter, bool useTags)
|
public bool ApplyFilter(Filter filter, bool useTags)
|
||||||
{
|
{
|
||||||
|
// If we have a null filter, return false
|
||||||
|
if (filter == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Process description to machine name
|
|
||||||
if (filter.DescriptionAsName)
|
|
||||||
MachineDescriptionToName();
|
|
||||||
|
|
||||||
// If we are using tags from the DAT, set the proper input for split type unless overridden
|
// If we are using tags from the DAT, set the proper input for split type unless overridden
|
||||||
if (useTags && filter.InternalSplit == MergingFlag.None)
|
if (useTags && filter.InternalSplit == MergingFlag.None)
|
||||||
filter.InternalSplit = Header.ForceMerging;
|
filter.InternalSplit = Header.ForceMerging;
|
||||||
@@ -801,91 +834,14 @@ namespace SabreTools.Library.DatFiles
|
|||||||
if (item == null)
|
if (item == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// If the rom passes the filter, include it
|
// If the rom doesn't pass the filter, mark for removal
|
||||||
if (item.PassesFilter(filter))
|
if (!item.PassesFilter(filter))
|
||||||
{
|
|
||||||
// If we're stripping unicode characters, do so from all relevant things
|
|
||||||
if (filter.RemoveUnicode)
|
|
||||||
{
|
|
||||||
item.Name = Sanitizer.RemoveUnicodeCharacters(item.Name);
|
|
||||||
item.Machine.Name = Sanitizer.RemoveUnicodeCharacters(item.Machine.Name);
|
|
||||||
item.Machine.Description = Sanitizer.RemoveUnicodeCharacters(item.Machine.Description);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're in cleaning mode, do so from all relevant things
|
|
||||||
if (filter.Clean)
|
|
||||||
{
|
|
||||||
item.Machine.Name = Sanitizer.CleanGameName(item.Machine.Name);
|
|
||||||
item.Machine.Description = Sanitizer.CleanGameName(item.Machine.Description);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we are in single game mode, rename all games
|
|
||||||
if (filter.Single)
|
|
||||||
item.Machine.Name = "!";
|
|
||||||
|
|
||||||
// If we are in NTFS trim mode, trim the game name
|
|
||||||
if (filter.Trim)
|
|
||||||
{
|
|
||||||
// Windows max name length is 260
|
|
||||||
int usableLength = 260 - item.Machine.Name.Length - filter.Root.Length;
|
|
||||||
if (item.Name.Length > usableLength)
|
|
||||||
{
|
|
||||||
string ext = Path.GetExtension(item.Name);
|
|
||||||
item.Name = item.Name.Substring(0, usableLength - ext.Length);
|
|
||||||
item.Name += ext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise mark for removal
|
|
||||||
else
|
|
||||||
{
|
|
||||||
item.Remove = true;
|
item.Remove = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign back for caution
|
// Assign back for caution
|
||||||
Items[key] = items;
|
Items[key] = items;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are removing scene dates, do that now
|
|
||||||
if (Header.SceneDateStrip)
|
|
||||||
StripSceneDatesFromItems();
|
|
||||||
|
|
||||||
// Run the one rom per game logic, if required
|
|
||||||
if (Header.OneGamePerRegion)
|
|
||||||
OneGamePerRegion();
|
|
||||||
|
|
||||||
// Run the one rom per game logic, if required
|
|
||||||
if (Header.OneRomPerGame)
|
|
||||||
OneRomPerGame();
|
|
||||||
|
|
||||||
// If we are removing fields, do that now
|
|
||||||
if (Header.ExcludeFields != null && Header.ExcludeFields.Any())
|
|
||||||
RemoveFieldsFromItems();
|
|
||||||
|
|
||||||
// Remove all marked items
|
|
||||||
Items.ClearMarked();
|
|
||||||
|
|
||||||
// We remove any blanks, if we aren't supposed to have any
|
|
||||||
if (!Header.KeepEmptyGames)
|
|
||||||
{
|
|
||||||
List<string> possiblyEmptyKeys = Items.Keys.ToList();
|
|
||||||
foreach (string key in possiblyEmptyKeys)
|
|
||||||
{
|
|
||||||
List<DatItem> items = Items[key];
|
|
||||||
if (items == null || items.Count == 0)
|
|
||||||
{
|
|
||||||
Items.Remove(key);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<DatItem> newitems = items.Where(i => i.ItemType != ItemType.Blank).ToList();
|
|
||||||
|
|
||||||
Items.Remove(key);
|
|
||||||
Items.AddRange(key, newitems);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -929,6 +885,61 @@ namespace SabreTools.Library.DatFiles
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean individual items based on the current filter
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cleaner">Cleaner to use</param>
|
||||||
|
public void CleanDatItems(Cleaner cleaner)
|
||||||
|
{
|
||||||
|
List<string> keys = Items.Keys.ToList();
|
||||||
|
foreach (string key in keys)
|
||||||
|
{
|
||||||
|
// For every item in the current key
|
||||||
|
List<DatItem> items = Items[key];
|
||||||
|
foreach (DatItem item in items)
|
||||||
|
{
|
||||||
|
// If we have a null item, we can't clean it it
|
||||||
|
if (item == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// If we're stripping unicode characters, do so from all relevant things
|
||||||
|
if (cleaner?.RemoveUnicode == true)
|
||||||
|
{
|
||||||
|
item.Name = Sanitizer.RemoveUnicodeCharacters(item.Name);
|
||||||
|
item.Machine.Name = Sanitizer.RemoveUnicodeCharacters(item.Machine.Name);
|
||||||
|
item.Machine.Description = Sanitizer.RemoveUnicodeCharacters(item.Machine.Description);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're in cleaning mode, do so from all relevant things
|
||||||
|
if (cleaner?.Clean == true)
|
||||||
|
{
|
||||||
|
item.Machine.Name = Sanitizer.CleanGameName(item.Machine.Name);
|
||||||
|
item.Machine.Description = Sanitizer.CleanGameName(item.Machine.Description);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are in single game mode, rename all games
|
||||||
|
if (cleaner?.Single == true)
|
||||||
|
item.Machine.Name = "!";
|
||||||
|
|
||||||
|
// If we are in NTFS trim mode, trim the game name
|
||||||
|
if (cleaner?.Trim == true)
|
||||||
|
{
|
||||||
|
// Windows max name length is 260
|
||||||
|
int usableLength = 260 - item.Machine.Name.Length - (cleaner.Root?.Length ?? 0);
|
||||||
|
if (item.Name.Length > usableLength)
|
||||||
|
{
|
||||||
|
string ext = Path.GetExtension(item.Name);
|
||||||
|
item.Name = item.Name.Substring(0, usableLength - ext.Length);
|
||||||
|
item.Name += ext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign back for caution
|
||||||
|
Items[key] = items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Use game descriptions as names in the DAT, updating cloneof/romof/sampleof
|
/// Use game descriptions as names in the DAT, updating cloneof/romof/sampleof
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -989,6 +1000,7 @@ namespace SabreTools.Library.DatFiles
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filter a DAT using 1G1R logic given an ordered set of regions
|
/// Filter a DAT using 1G1R logic given an ordered set of regions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="regions">Ordered list of regions to use</param>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// In the most technical sense, the way that the region list is being used does not
|
/// In the most technical sense, the way that the region list is being used does not
|
||||||
/// confine its values to be just regions. Since it's essentially acting like a
|
/// confine its values to be just regions. Since it's essentially acting like a
|
||||||
@@ -999,8 +1011,12 @@ namespace SabreTools.Library.DatFiles
|
|||||||
/// to clone sets based on name, nor does it have the ability to match on the
|
/// to clone sets based on name, nor does it have the ability to match on the
|
||||||
/// Release DatItem type.
|
/// Release DatItem type.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public void OneGamePerRegion()
|
public void OneGamePerRegion(List<string> regions)
|
||||||
{
|
{
|
||||||
|
// If we have null region list, make it empty
|
||||||
|
if (regions == null)
|
||||||
|
regions = new List<string>();
|
||||||
|
|
||||||
// For sake of ease, the first thing we want to do is bucket by game
|
// For sake of ease, the first thing we want to do is bucket by game
|
||||||
Items.BucketBy(Field.Machine_Name, DedupeType.None, norename: true);
|
Items.BucketBy(Field.Machine_Name, DedupeType.None, norename: true);
|
||||||
|
|
||||||
@@ -1038,11 +1054,6 @@ namespace SabreTools.Library.DatFiles
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have null region list, make it empty
|
|
||||||
List<string> regions = Header.RegionList;
|
|
||||||
if (regions == null)
|
|
||||||
regions = new List<string>();
|
|
||||||
|
|
||||||
// Once we have the full list of mappings, filter out games to keep
|
// Once we have the full list of mappings, filter out games to keep
|
||||||
foreach (string key in parents.Keys)
|
foreach (string key in parents.Keys)
|
||||||
{
|
{
|
||||||
@@ -1094,14 +1105,16 @@ namespace SabreTools.Library.DatFiles
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Remove fields as per the header
|
/// Remove fields as per the header
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void RemoveFieldsFromItems()
|
/// <param name="fields">List of fields to use</param>
|
||||||
|
public void RemoveFieldsFromItems(List<Field> fields)
|
||||||
{
|
{
|
||||||
|
// If we have null field list, make it empty
|
||||||
|
if (fields == null)
|
||||||
|
fields = new List<Field>();
|
||||||
|
|
||||||
// Output the logging statement
|
// Output the logging statement
|
||||||
Globals.Logger.User("Removing filtered fields");
|
Globals.Logger.User("Removing filtered fields");
|
||||||
|
|
||||||
// Get the array of fields from the header
|
|
||||||
List<Field> fields = Header.ExcludeFields;
|
|
||||||
|
|
||||||
// Now process all of the roms
|
// Now process all of the roms
|
||||||
Parallel.ForEach(Items.Keys, Globals.ParallelOptions, key =>
|
Parallel.ForEach(Items.Keys, Globals.ParallelOptions, key =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -267,42 +267,6 @@ namespace SabreTools.Library.DatFiles
|
|||||||
|
|
||||||
#region Filtering Fields
|
#region Filtering Fields
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Dictionary of fields in machine and items to exclude from writing
|
|
||||||
/// </summary>
|
|
||||||
[JsonIgnore]
|
|
||||||
public List<Field> ExcludeFields { get; set; } = new List<Field>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Enable "One Rom, One Region (1G1R)" mode
|
|
||||||
/// </summary>
|
|
||||||
[JsonIgnore]
|
|
||||||
public bool OneGamePerRegion { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Ordered list of regions for "One Rom, One Region (1G1R)" mode
|
|
||||||
/// </summary>
|
|
||||||
[JsonIgnore]
|
|
||||||
public List<string> RegionList { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Ensure each rom is in their own game
|
|
||||||
/// </summary>
|
|
||||||
[JsonIgnore]
|
|
||||||
public bool OneRomPerGame { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Keep machines that don't contain any items
|
|
||||||
/// </summary>
|
|
||||||
[JsonIgnore]
|
|
||||||
public bool KeepEmptyGames { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove scene dates from the beginning of machine names
|
|
||||||
/// </summary>
|
|
||||||
[JsonIgnore]
|
|
||||||
public bool SceneDateStrip { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Deduplicate items using the given method
|
/// Deduplicate items using the given method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -315,7 +279,6 @@ namespace SabreTools.Library.DatFiles
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public Hash StripHash { get; private set; }
|
public Hash StripHash { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Write pre-processing
|
#region Write pre-processing
|
||||||
@@ -538,12 +501,6 @@ namespace SabreTools.Library.DatFiles
|
|||||||
ForceNodump = this.ForceNodump,
|
ForceNodump = this.ForceNodump,
|
||||||
ForcePacking = this.ForcePacking,
|
ForcePacking = this.ForcePacking,
|
||||||
DatFormat = this.DatFormat,
|
DatFormat = this.DatFormat,
|
||||||
ExcludeFields = this.ExcludeFields,
|
|
||||||
OneGamePerRegion = this.OneGamePerRegion,
|
|
||||||
RegionList = this.RegionList,
|
|
||||||
OneRomPerGame = this.OneRomPerGame,
|
|
||||||
KeepEmptyGames = this.KeepEmptyGames,
|
|
||||||
SceneDateStrip = this.SceneDateStrip,
|
|
||||||
DedupeRoms = this.DedupeRoms,
|
DedupeRoms = this.DedupeRoms,
|
||||||
StripHash = this.StripHash,
|
StripHash = this.StripHash,
|
||||||
|
|
||||||
@@ -585,12 +542,6 @@ namespace SabreTools.Library.DatFiles
|
|||||||
ForceNodump = this.ForceNodump,
|
ForceNodump = this.ForceNodump,
|
||||||
ForcePacking = this.ForcePacking,
|
ForcePacking = this.ForcePacking,
|
||||||
DatFormat = this.DatFormat,
|
DatFormat = this.DatFormat,
|
||||||
ExcludeFields = this.ExcludeFields,
|
|
||||||
OneGamePerRegion = this.OneGamePerRegion,
|
|
||||||
RegionList = this.RegionList,
|
|
||||||
OneRomPerGame = this.OneRomPerGame,
|
|
||||||
KeepEmptyGames = this.KeepEmptyGames,
|
|
||||||
SceneDateStrip = this.SceneDateStrip,
|
|
||||||
DedupeRoms = this.DedupeRoms,
|
DedupeRoms = this.DedupeRoms,
|
||||||
StripHash = this.StripHash,
|
StripHash = this.StripHash,
|
||||||
};
|
};
|
||||||
@@ -604,10 +555,6 @@ namespace SabreTools.Library.DatFiles
|
|||||||
return new DatHeader()
|
return new DatHeader()
|
||||||
{
|
{
|
||||||
DatFormat = this.DatFormat,
|
DatFormat = this.DatFormat,
|
||||||
ExcludeFields = this.ExcludeFields,
|
|
||||||
OneRomPerGame = this.OneRomPerGame,
|
|
||||||
KeepEmptyGames = this.KeepEmptyGames,
|
|
||||||
SceneDateStrip = this.SceneDateStrip,
|
|
||||||
DedupeRoms = this.DedupeRoms,
|
DedupeRoms = this.DedupeRoms,
|
||||||
StripHash = this.StripHash,
|
StripHash = this.StripHash,
|
||||||
|
|
||||||
@@ -684,12 +631,6 @@ namespace SabreTools.Library.DatFiles
|
|||||||
if (datHeader.DatFormat != 0x00)
|
if (datHeader.DatFormat != 0x00)
|
||||||
DatFormat = datHeader.DatFormat;
|
DatFormat = datHeader.DatFormat;
|
||||||
|
|
||||||
if (datHeader.ExcludeFields != null)
|
|
||||||
ExcludeFields = datHeader.ExcludeFields;
|
|
||||||
|
|
||||||
OneRomPerGame = datHeader.OneRomPerGame;
|
|
||||||
KeepEmptyGames = datHeader.KeepEmptyGames;
|
|
||||||
SceneDateStrip = datHeader.SceneDateStrip;
|
|
||||||
DedupeRoms = datHeader.DedupeRoms;
|
DedupeRoms = datHeader.DedupeRoms;
|
||||||
//StripHash = datHeader.StripHash;
|
//StripHash = datHeader.StripHash;
|
||||||
|
|
||||||
|
|||||||
@@ -715,6 +715,28 @@ namespace SabreTools.Library.DatFiles
|
|||||||
ClearEmpty();
|
ClearEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove any keys that have null or empty values
|
||||||
|
/// </summary>
|
||||||
|
public void ClearEmpty()
|
||||||
|
{
|
||||||
|
var keys = items.Keys.Where(k => k != null).ToList();
|
||||||
|
foreach (string key in keys)
|
||||||
|
{
|
||||||
|
// If the key doesn't exist, skip
|
||||||
|
if (!items.ContainsKey(key))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// If the value is null, remove
|
||||||
|
else if (items[key] == null)
|
||||||
|
items.Remove(key);
|
||||||
|
|
||||||
|
// If there are no non-blank items, remove
|
||||||
|
else if (items[key].Count(i => i != null && i.ItemType != ItemType.Blank) == 0)
|
||||||
|
items.Remove(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Remove all items marked for removal
|
/// Remove all items marked for removal
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -829,22 +851,6 @@ namespace SabreTools.Library.DatFiles
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove any keys that have null or empty values
|
|
||||||
/// </summary>
|
|
||||||
private void ClearEmpty()
|
|
||||||
{
|
|
||||||
var keys = items.Keys.Where(k => k != null).ToList();
|
|
||||||
foreach (string key in keys)
|
|
||||||
{
|
|
||||||
if (!items.ContainsKey(key))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (items[key] == null || items[key].Count == 0)
|
|
||||||
items.Remove(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the highest-order Field value that represents the statistics
|
/// Get the highest-order Field value that represents the statistics
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
72
SabreTools.Library/Filtering/Cleaner.cs
Normal file
72
SabreTools.Library/Filtering/Cleaner.cs
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using SabreTools.Library.DatItems;
|
||||||
|
|
||||||
|
namespace SabreTools.Library.Filtering
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the cleaning operations that need to be performed on a set of items, usually a DAT
|
||||||
|
/// </summary>
|
||||||
|
public class Cleaner
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Clean all names to WoD standards
|
||||||
|
/// </summary>
|
||||||
|
public bool Clean { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set Machine Description from Machine Name
|
||||||
|
/// </summary>
|
||||||
|
public bool DescriptionAsName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dictionary of fields in machine and items to exclude from writing
|
||||||
|
/// </summary>
|
||||||
|
public List<Field> ExcludeFields { get; set; } = new List<Field>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Keep machines that don't contain any items
|
||||||
|
/// </summary>
|
||||||
|
public bool KeepEmptyGames { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enable "One Rom, One Region (1G1R)" mode
|
||||||
|
/// </summary>
|
||||||
|
public bool OneGamePerRegion { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ordered list of regions for "One Rom, One Region (1G1R)" mode
|
||||||
|
/// </summary>
|
||||||
|
public List<string> RegionList { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ensure each rom is in their own game
|
||||||
|
/// </summary>
|
||||||
|
public bool OneRomPerGame { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove all unicode characters
|
||||||
|
/// </summary>
|
||||||
|
public bool RemoveUnicode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Include root directory when determing trim sizes
|
||||||
|
/// </summary>
|
||||||
|
public string Root { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove scene dates from the beginning of machine names
|
||||||
|
/// </summary>
|
||||||
|
public bool SceneDateStrip { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Change all machine names to "!"
|
||||||
|
/// </summary>
|
||||||
|
public bool Single { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Trim total machine and item name to not exceed NTFS limits
|
||||||
|
/// </summary>
|
||||||
|
public bool Trim { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -352,17 +352,7 @@ namespace SabreTools.Library.Filtering
|
|||||||
|
|
||||||
#endregion // DatItem Filters
|
#endregion // DatItem Filters
|
||||||
|
|
||||||
#region Manipulation Flags
|
#region Additional Flags
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Clean all names to WoD standards
|
|
||||||
/// </summary>
|
|
||||||
public bool Clean { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set Machine Description from Machine Name
|
|
||||||
/// </summary>
|
|
||||||
public bool DescriptionAsName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Include romof and cloneof when filtering machine names
|
/// Include romof and cloneof when filtering machine names
|
||||||
@@ -374,26 +364,6 @@ namespace SabreTools.Library.Filtering
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public MergingFlag InternalSplit { get; set; }
|
public MergingFlag InternalSplit { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove all unicode characters
|
|
||||||
/// </summary>
|
|
||||||
public bool RemoveUnicode { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Include root directory when determing trim sizes
|
|
||||||
/// </summary>
|
|
||||||
public string Root { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Change all machine names to "!"
|
|
||||||
/// </summary>
|
|
||||||
public bool Single { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Trim total machine and item name to not exceed NTFS limits
|
|
||||||
/// </summary>
|
|
||||||
public bool Trim { get; set; }
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#endregion // Fields
|
#endregion // Fields
|
||||||
|
|||||||
@@ -2302,6 +2302,11 @@ Some special strings that can be used:
|
|||||||
|
|
||||||
#region Fields
|
#region Fields
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Preconfigured Cleaner
|
||||||
|
/// </summary>
|
||||||
|
protected Cleaner Cleaner { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Preconfigured ExtraIni set
|
/// Preconfigured ExtraIni set
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2419,6 +2424,7 @@ Some special strings that can be used:
|
|||||||
public override void ProcessFeatures(Dictionary<string, Feature> features)
|
public override void ProcessFeatures(Dictionary<string, Feature> features)
|
||||||
{
|
{
|
||||||
// Generic feature flags
|
// Generic feature flags
|
||||||
|
Cleaner = GetCleaner(features);
|
||||||
Extras = GetExtras(features);
|
Extras = GetExtras(features);
|
||||||
Filter = GetFilter(features);
|
Filter = GetFilter(features);
|
||||||
Header = GetDatHeader(features);
|
Header = GetDatHeader(features);
|
||||||
@@ -2665,6 +2671,34 @@ Some special strings that can be used:
|
|||||||
|
|
||||||
#region Private Specific Extraction
|
#region Private Specific Extraction
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get Cleaner from feature list
|
||||||
|
/// </summary>
|
||||||
|
private Cleaner GetCleaner(Dictionary<string, Feature> features)
|
||||||
|
{
|
||||||
|
Cleaner cleaner = new Cleaner()
|
||||||
|
{
|
||||||
|
Clean = GetBoolean(features, CleanValue),
|
||||||
|
DescriptionAsName = GetBoolean(features, DescriptionAsNameValue),
|
||||||
|
KeepEmptyGames = GetBoolean(features, KeepEmptyGamesValue),
|
||||||
|
OneGamePerRegion = GetBoolean(features, OneGamePerRegionValue),
|
||||||
|
RegionList = GetList(features, RegionListValue),
|
||||||
|
OneRomPerGame = GetBoolean(features, OneRomPerGameValue),
|
||||||
|
RemoveUnicode = GetBoolean(features, RemoveUnicodeValue),
|
||||||
|
Root = GetString(features, RootDirStringValue),
|
||||||
|
SceneDateStrip = GetBoolean(features, SceneDateStripValue),
|
||||||
|
Single = GetBoolean(features, SingleSetValue),
|
||||||
|
Trim = GetBoolean(features, TrimValue),
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (string fieldName in GetList(features, ExcludeFieldListValue))
|
||||||
|
{
|
||||||
|
cleaner.ExcludeFields.Add(fieldName.AsField());
|
||||||
|
}
|
||||||
|
|
||||||
|
return cleaner;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get DatHeader from feature list
|
/// Get DatHeader from feature list
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2688,18 +2722,13 @@ Some special strings that can be used:
|
|||||||
GameName = GetBoolean(features, GamePrefixValue),
|
GameName = GetBoolean(features, GamePrefixValue),
|
||||||
HeaderSkipper = GetString(features, HeaderStringValue),
|
HeaderSkipper = GetString(features, HeaderStringValue),
|
||||||
Homepage = GetString(features, HomepageStringValue),
|
Homepage = GetString(features, HomepageStringValue),
|
||||||
KeepEmptyGames = GetBoolean(features, KeepEmptyGamesValue),
|
|
||||||
Name = GetString(features, NameStringValue),
|
Name = GetString(features, NameStringValue),
|
||||||
OneGamePerRegion = GetBoolean(features, OneGamePerRegionValue),
|
|
||||||
OneRomPerGame = GetBoolean(features, OneRomPerGameValue),
|
|
||||||
Postfix = GetString(features, PostfixStringValue),
|
Postfix = GetString(features, PostfixStringValue),
|
||||||
Prefix = GetString(features, PrefixStringValue),
|
Prefix = GetString(features, PrefixStringValue),
|
||||||
Quotes = GetBoolean(features, QuotesValue),
|
Quotes = GetBoolean(features, QuotesValue),
|
||||||
RegionList = GetList(features, RegionListValue),
|
|
||||||
RemoveExtension = GetBoolean(features, RemoveExtensionsValue),
|
RemoveExtension = GetBoolean(features, RemoveExtensionsValue),
|
||||||
ReplaceExtension = GetString(features, ReplaceExtensionStringValue),
|
ReplaceExtension = GetString(features, ReplaceExtensionStringValue),
|
||||||
RootDir = GetString(features, RootStringValue),
|
RootDir = GetString(features, RootStringValue),
|
||||||
SceneDateStrip = GetBoolean(features, SceneDateStripValue),
|
|
||||||
Type = GetBoolean(features, SuperdatValue) ? "SuperDAT" : null,
|
Type = GetBoolean(features, SuperdatValue) ? "SuperDAT" : null,
|
||||||
Url = GetString(features, UrlStringValue),
|
Url = GetString(features, UrlStringValue),
|
||||||
UseRomName = GetBoolean(features, RomsValue),
|
UseRomName = GetBoolean(features, RomsValue),
|
||||||
@@ -2724,11 +2753,6 @@ Some special strings that can be used:
|
|||||||
datHeader.DatFormat |= dftemp;
|
datHeader.DatFormat |= dftemp;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (string fieldName in GetList(features, ExcludeFieldListValue))
|
|
||||||
{
|
|
||||||
datHeader.ExcludeFields.Add(fieldName.AsField());
|
|
||||||
}
|
|
||||||
|
|
||||||
return datHeader;
|
return datHeader;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2972,13 +2996,7 @@ Some special strings that can be used:
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Filter manipulation flags
|
#region Additional Filter flags
|
||||||
|
|
||||||
// Clean names
|
|
||||||
filter.Clean = GetBoolean(features, CleanValue);
|
|
||||||
|
|
||||||
// Machine description as machine name
|
|
||||||
filter.DescriptionAsName = GetBoolean(features, DescriptionAsNameValue);
|
|
||||||
|
|
||||||
// Include 'of" in game filters
|
// Include 'of" in game filters
|
||||||
filter.IncludeOfInGame = GetBoolean(features, MatchOfTagsValue);
|
filter.IncludeOfInGame = GetBoolean(features, MatchOfTagsValue);
|
||||||
@@ -2986,18 +3004,6 @@ Some special strings that can be used:
|
|||||||
// Internal splitting
|
// Internal splitting
|
||||||
filter.InternalSplit = GetSplitType(features);
|
filter.InternalSplit = GetSplitType(features);
|
||||||
|
|
||||||
// Remove unicode characters
|
|
||||||
filter.RemoveUnicode = GetBoolean(features, RemoveUnicodeValue);
|
|
||||||
|
|
||||||
// Root directory
|
|
||||||
filter.Root = GetString(features, RootDirStringValue);
|
|
||||||
|
|
||||||
// Single game in output
|
|
||||||
filter.Single = GetBoolean(features, SingleSetValue);
|
|
||||||
|
|
||||||
// Trim to NTFS length
|
|
||||||
filter.Trim = GetBoolean(features, TrimValue);
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
return filter;
|
return filter;
|
||||||
|
|||||||
@@ -172,6 +172,7 @@ Reset the internal state: reset();";
|
|||||||
|
|
||||||
// Apply the filter blindly
|
// Apply the filter blindly
|
||||||
datFile.ApplyFilter(filter, false);
|
datFile.ApplyFilter(filter, false);
|
||||||
|
datFile.Items.ClearMarked(); // TODO: We might not want to remove immediately
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -240,15 +241,8 @@ Reset the internal state: reset();";
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the region list
|
|
||||||
var tempRegionList = datFile.Header.RegionList;
|
|
||||||
datFile.Header.RegionList = command.Arguments;
|
|
||||||
|
|
||||||
// Run the 1G1R functionality
|
// Run the 1G1R functionality
|
||||||
datFile.OneGamePerRegion();
|
datFile.OneGamePerRegion(command.Arguments);
|
||||||
|
|
||||||
// Reset the header value
|
|
||||||
datFile.Header.RegionList = tempRegionList;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -275,15 +269,8 @@ Reset the internal state: reset();";
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the field list
|
|
||||||
var tempRemoveFields = datFile.Header.ExcludeFields;
|
|
||||||
datFile.Header.ExcludeFields = command.Arguments.Select(s => s.AsField()).ToList();
|
|
||||||
|
|
||||||
// Run the removal functionality
|
// Run the removal functionality
|
||||||
datFile.RemoveFieldsFromItems();
|
datFile.RemoveFieldsFromItems(command.Arguments.Select(s => s.AsField()).ToList());
|
||||||
|
|
||||||
// Reset the header value
|
|
||||||
datFile.Header.ExcludeFields = tempRemoveFields;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ namespace SabreTools.Features
|
|||||||
{
|
{
|
||||||
datdata.ApplyExtras(Extras);
|
datdata.ApplyExtras(Extras);
|
||||||
datdata.ApplyFilter(Filter, false);
|
datdata.ApplyFilter(Filter, false);
|
||||||
|
datdata.ApplyCleaning(Cleaner);
|
||||||
datdata.Write(OutputDir);
|
datdata.Write(OutputDir);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -167,7 +167,8 @@ namespace SabreTools.Features
|
|||||||
|| datFile.Header.DatFormat.HasFlag(DatFormat.CSV)
|
|| datFile.Header.DatFormat.HasFlag(DatFormat.CSV)
|
||||||
|| datFile.Header.DatFormat.HasFlag(DatFormat.SSV));
|
|| datFile.Header.DatFormat.HasFlag(DatFormat.SSV));
|
||||||
datFile.ApplyExtras(Extras);
|
datFile.ApplyExtras(Extras);
|
||||||
datFile.ApplyFilter(Filter, false /* useTags */);
|
datFile.ApplyFilter(Filter, false);
|
||||||
|
datFile.ApplyCleaning(Cleaner);
|
||||||
|
|
||||||
// Get the correct output path
|
// Get the correct output path
|
||||||
string realOutDir = inputPath.GetOutputPath(OutputDir, GetBoolean(features, InplaceValue));
|
string realOutDir = inputPath.GetOutputPath(OutputDir, GetBoolean(features, InplaceValue));
|
||||||
@@ -201,9 +202,10 @@ namespace SabreTools.Features
|
|||||||
else
|
else
|
||||||
datHeaders = userInputDat.PopulateUserData(inputPaths);
|
datHeaders = userInputDat.PopulateUserData(inputPaths);
|
||||||
|
|
||||||
// Apply the extras and filter
|
// Apply the extras, filter, and cleaning
|
||||||
userInputDat.ApplyExtras(Extras);
|
userInputDat.ApplyExtras(Extras);
|
||||||
userInputDat.ApplyFilter(Filter, false);
|
userInputDat.ApplyFilter(Filter, false);
|
||||||
|
userInputDat.ApplyCleaning(Cleaner);
|
||||||
|
|
||||||
// Output only DatItems that are duplicated across inputs
|
// Output only DatItems that are duplicated across inputs
|
||||||
if (updateMode.HasFlag(UpdateMode.DiffDupesOnly))
|
if (updateMode.HasFlag(UpdateMode.DiffDupesOnly))
|
||||||
@@ -287,11 +289,12 @@ namespace SabreTools.Features
|
|||||||
// Loop through each input and diff against the base
|
// Loop through each input and diff against the base
|
||||||
Parallel.ForEach(inputPaths, Globals.ParallelOptions, inputPath =>
|
Parallel.ForEach(inputPaths, Globals.ParallelOptions, inputPath =>
|
||||||
{
|
{
|
||||||
// Parse, extras, and filter the path to a new DatFile
|
// Parse and process the path to a new DatFile
|
||||||
DatFile repDat = DatFile.Create(userInputDat.Header.CloneFiltering());
|
DatFile repDat = DatFile.Create(userInputDat.Header.CloneFiltering());
|
||||||
repDat.Parse(inputPath, indexId: 1, keep: true);
|
repDat.Parse(inputPath, indexId: 1, keep: true);
|
||||||
repDat.ApplyExtras(Extras);
|
repDat.ApplyExtras(Extras);
|
||||||
repDat.ApplyFilter(Filter, false);
|
repDat.ApplyFilter(Filter, false);
|
||||||
|
repDat.ApplyCleaning(Cleaner);
|
||||||
|
|
||||||
// Now replace the fields from the base DatFile
|
// Now replace the fields from the base DatFile
|
||||||
userInputDat.DiffAgainst(repDat, GetBoolean(Features, ByGameValue));
|
userInputDat.DiffAgainst(repDat, GetBoolean(Features, ByGameValue));
|
||||||
@@ -308,11 +311,12 @@ namespace SabreTools.Features
|
|||||||
// Loop through each input and apply the base DatFile
|
// Loop through each input and apply the base DatFile
|
||||||
Parallel.ForEach(inputPaths, Globals.ParallelOptions, inputPath =>
|
Parallel.ForEach(inputPaths, Globals.ParallelOptions, inputPath =>
|
||||||
{
|
{
|
||||||
// Parse, extras, and filter the path to a new DatFile
|
// Parse and process the path to a new DatFile
|
||||||
DatFile repDat = DatFile.Create(userInputDat.Header.CloneFiltering());
|
DatFile repDat = DatFile.Create(userInputDat.Header.CloneFiltering());
|
||||||
repDat.Parse(inputPath, indexId: 1, keep: true);
|
repDat.Parse(inputPath, indexId: 1, keep: true);
|
||||||
repDat.ApplyExtras(Extras);
|
repDat.ApplyExtras(Extras);
|
||||||
repDat.ApplyFilter(Filter, false);
|
repDat.ApplyFilter(Filter, false);
|
||||||
|
repDat.ApplyCleaning(Cleaner);
|
||||||
|
|
||||||
// Now replace the fields from the base DatFile
|
// Now replace the fields from the base DatFile
|
||||||
userInputDat.BaseReplace(repDat, updateFields, GetBoolean(features, OnlySameValue));
|
userInputDat.BaseReplace(repDat, updateFields, GetBoolean(features, OnlySameValue));
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ namespace SabreTools.Features
|
|||||||
datdata.Parse(datfile, 99, keep: true);
|
datdata.Parse(datfile, 99, keep: true);
|
||||||
datdata.ApplyExtras(Extras);
|
datdata.ApplyExtras(Extras);
|
||||||
datdata.ApplyFilter(Filter, true);
|
datdata.ApplyFilter(Filter, true);
|
||||||
|
datdata.ApplyCleaning(Cleaner);
|
||||||
|
|
||||||
// Set depot information
|
// Set depot information
|
||||||
datdata.Header.InputDepot = Header.InputDepot.Clone() as DepotInformation;
|
datdata.Header.InputDepot = Header.InputDepot.Clone() as DepotInformation;
|
||||||
@@ -88,6 +89,7 @@ namespace SabreTools.Features
|
|||||||
datdata.Parse(datfile, 99, keep: true);
|
datdata.Parse(datfile, 99, keep: true);
|
||||||
datdata.ApplyExtras(Extras);
|
datdata.ApplyExtras(Extras);
|
||||||
datdata.ApplyFilter(Filter, true);
|
datdata.ApplyFilter(Filter, true);
|
||||||
|
datdata.ApplyCleaning(Cleaner);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set depot information
|
// Set depot information
|
||||||
|
|||||||
Reference in New Issue
Block a user