From bd92f8993a6f48a0179063dba07a65643b05ee6f Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Wed, 2 Sep 2020 12:19:12 -0700 Subject: [PATCH] Name is not guaranteed --- SabreTools.Library/DatFiles/DatFile.cs | 155 +++++++----------- SabreTools.Library/DatFiles/ItemDictionary.cs | 1 - SabreTools.Library/DatItems/Adjuster.cs | 68 ++++++++ SabreTools.Library/DatItems/Archive.cs | 146 ++++++++++++++++- SabreTools.Library/DatItems/Auxiliary.cs | 2 +- SabreTools.Library/DatItems/BiosSet.cs | 68 ++++++++ SabreTools.Library/DatItems/Blank.cs | 2 - SabreTools.Library/DatItems/Chip.cs | 68 ++++++++ SabreTools.Library/DatItems/Configuration.cs | 69 ++++++++ SabreTools.Library/DatItems/DatItem.cs | 130 +++++++++------ .../DatItems/DeviceReference.cs | 146 ++++++++++++++++- SabreTools.Library/DatItems/DipSwitch.cs | 69 ++++++++ SabreTools.Library/DatItems/Disk.cs | 68 ++++++++ SabreTools.Library/DatItems/Media.cs | 72 +++++++- SabreTools.Library/DatItems/RamOption.cs | 70 +++++++- SabreTools.Library/DatItems/Release.cs | 70 +++++++- SabreTools.Library/DatItems/Rom.cs | 68 ++++++++ SabreTools.Library/DatItems/Sample.cs | 146 ++++++++++++++++- SabreTools.Library/DatItems/Slot.cs | 69 ++++++++ SabreTools.Library/DatItems/SoftwareList.cs | 74 +++++++++ 20 files changed, 1397 insertions(+), 164 deletions(-) diff --git a/SabreTools.Library/DatFiles/DatFile.cs b/SabreTools.Library/DatFiles/DatFile.cs index 2bd31568..10e100f2 100644 --- a/SabreTools.Library/DatFiles/DatFile.cs +++ b/SabreTools.Library/DatFiles/DatFile.cs @@ -953,37 +953,8 @@ namespace SabreTools.Library.DatFiles 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; - } - } + // Run cleaning per item + item.Clean(cleaner); } // Assign back for caution @@ -1146,9 +1117,7 @@ namespace SabreTools.Library.DatFiles List items = Items[key]; for (int i = 0; i < items.Count; i++) { - string[] splitname = items[i].Name.Split('.'); - items[i].Machine.Name += $"/{string.Join(".", splitname.Take(splitname.Length > 1 ? splitname.Length - 1 : 1))}"; - items[i].Name = Path.GetFileName(items[i].Name); + items[i].SetOneRomPerGame(); } }); } @@ -1362,7 +1331,7 @@ namespace SabreTools.Library.DatFiles { DatItem datItem = (DatItem)item.Clone(); datItem.CopyMachineInformation(copyFrom); - if (Items[game].Where(i => i.Name == datItem.Name).Count() == 0 && !Items[game].Contains(datItem)) + if (Items[game].Where(i => i.GetName() == datItem.GetName()).Count() == 0 && !Items[game].Contains(datItem)) Items.Add(game, datItem); } } @@ -1400,7 +1369,7 @@ namespace SabreTools.Library.DatFiles // Determine if the game has any devices or not List deviceReferences = Items[game] .Where(i => i.ItemType == ItemType.DeviceReference) - .Select(i => i.Name) + .Select(i => (i as DeviceReference).Name) .ToList(); List newdevs = new List(); foreach (string deviceReference in deviceReferences) @@ -1414,13 +1383,13 @@ namespace SabreTools.Library.DatFiles List devItems = Items[deviceReference]; newdevs.AddRange((Items[deviceReference] ?? new List()) .Where(i => i.ItemType == ItemType.DeviceReference) - .Select(i => i.Name)); + .Select(i => (i as DeviceReference).Name)); foreach (DatItem item in devItems) { DatItem datItem = (DatItem)item.Clone(); datItem.CopyMachineInformation(copyFrom); - if (Items[game].Where(i => i.ItemType == datItem.ItemType && i.Name == datItem.Name).Count() == 0) + if (Items[game].Where(i => i.ItemType == ItemType.DeviceReference && (i as DeviceReference).Name == (datItem as DeviceReference).Name).Count() == 0) { foundnew = true; Items.Add(game, datItem); @@ -1476,7 +1445,7 @@ namespace SabreTools.Library.DatFiles { DatItem datItem = (DatItem)item.Clone(); datItem.CopyMachineInformation(copyFrom); - if (Items[game].Where(i => i.ItemType == datItem.ItemType && i.Name == datItem.Name).Count() == 0) + if (Items[game].Where(i => i.ItemType == ItemType.Slot && (i as Slot).Name == (datItem as Slot).Name).Count() == 0) { foundnew = true; Items.Add(game, datItem); @@ -1531,7 +1500,7 @@ namespace SabreTools.Library.DatFiles { DatItem datItem = (DatItem)item.Clone(); datItem.CopyMachineInformation(copyFrom); - if (Items[game].Where(i => i.Name.ToLowerInvariant() == datItem.Name.ToLowerInvariant()).Count() == 0 + if (Items[game].Where(i => i.GetName()?.ToLowerInvariant() == datItem.GetName()?.ToLowerInvariant()).Count() == 0 && !Items[game].Contains(datItem)) { Items.Add(game, datItem); @@ -1592,23 +1561,23 @@ namespace SabreTools.Library.DatFiles Disk disk = item as Disk; // If the merge tag exists and the parent already contains it, skip - if (disk.MergeTag != null && Items[parent].Select(i => i.Name).Contains(disk.MergeTag)) + if (disk.MergeTag != null && Items[parent].Where(i => i.ItemType == ItemType.Disk).Select(i => (i as Disk).Name).Contains(disk.MergeTag)) { continue; } // If the merge tag exists but the parent doesn't contain it, add to parent - else if (disk.MergeTag != null && !Items[parent].Select(i => i.Name).Contains(disk.MergeTag)) + else if (disk.MergeTag != null && !Items[parent].Where(i => i.ItemType == ItemType.Disk).Select(i => (i as Disk).Name).Contains(disk.MergeTag)) { - item.CopyMachineInformation(copyFrom); - Items.Add(parent, item); + disk.CopyMachineInformation(copyFrom); + Items.Add(parent, disk); } // If there is no merge tag, add to parent else if (disk.MergeTag == null) { - item.CopyMachineInformation(copyFrom); - Items.Add(parent, item); + disk.CopyMachineInformation(copyFrom); + Items.Add(parent, disk); } } @@ -1618,29 +1587,29 @@ namespace SabreTools.Library.DatFiles Rom rom = item as Rom; // If the merge tag exists and the parent already contains it, skip - if (rom.MergeTag != null && Items[parent].Select(i => i.Name).Contains(rom.MergeTag)) + if (rom.MergeTag != null && Items[parent].Where(i => i.ItemType == ItemType.Rom).Select(i => (i as Rom).Name).Contains(rom.MergeTag)) { continue; } // If the merge tag exists but the parent doesn't contain it, add to subfolder of parent - else if (rom.MergeTag != null && !Items[parent].Select(i => i.Name).Contains(rom.MergeTag)) + else if (rom.MergeTag != null && !Items[parent].Where(i => i.ItemType == ItemType.Rom).Select(i => (i as Rom).Name).Contains(rom.MergeTag)) { if (subfolder) - item.Name = $"{item.Machine.Name}\\{item.Name}"; + rom.Name = $"{rom.Machine.Name}\\{rom.Name}"; - item.CopyMachineInformation(copyFrom); - Items.Add(parent, item); + rom.CopyMachineInformation(copyFrom); + Items.Add(parent, rom); } // If the parent doesn't already contain this item, add to subfolder of parent else if (!Items[parent].Contains(item)) { if (subfolder) - item.Name = $"{item.Machine.Name}\\{item.Name}"; + rom.Name = $"{item.Machine.Name}\\{rom.Name}"; - item.CopyMachineInformation(copyFrom); - Items.Add(parent, item); + rom.CopyMachineInformation(copyFrom); + Items.Add(parent, rom); } } @@ -1648,7 +1617,7 @@ namespace SabreTools.Library.DatFiles else if (!Items[parent].Contains(item)) { if (subfolder) - item.Name = $"{item.Machine.Name}\\{item.Name}"; + item.SetFields(new Dictionary { [Field.DatItem_Name] = $"{item.Machine.Name}\\{item.GetName()}" }); item.CopyMachineInformation(copyFrom); Items.Add(parent, item); @@ -1856,13 +1825,6 @@ namespace SabreTools.Library.DatFiles { string key = string.Empty; - // If there's no name in the rom, we log and skip it - if (item.Name == null) - { - Globals.Logger.Warning($"{Header.FileName}: Rom with no name found! Skipping..."); - return key; - } - // If we have a Disk, Media, or Rom, clean the hash data if (item.ItemType == ItemType.Disk) { @@ -2258,7 +2220,7 @@ namespace SabreTools.Library.DatFiles string key = datItem.GetKey(Field.DatItem_CRC); Items.Add(key, datItem); - Globals.Logger.User($"File added: {datItem.Name}{Environment.NewLine}"); + Globals.Logger.User($"File added: {datItem.GetName() ?? string.Empty}{Environment.NewLine}"); } catch (IOException ex) { @@ -2304,14 +2266,14 @@ namespace SabreTools.Library.DatFiles if (Header.Type == "SuperDAT") { machineName = parent; - itemName = datItem.Name; + itemName = datItem.GetName(); } // Otherwise, we want the archive name as the game, and the file as everything else else { machineName = parent; - itemName = datItem.Name; + itemName = datItem.GetName(); } } @@ -2330,31 +2292,28 @@ namespace SabreTools.Library.DatFiles datItem.Machine.Description = machineName; // If we have a Disk, then the ".chd" extension needs to be removed - if (datItem.ItemType == ItemType.Disk && datItem.Name.EndsWith(".chd")) + if (datItem.ItemType == ItemType.Disk && itemName.EndsWith(".chd")) { - datItem.Name = itemName.Substring(0, itemName.Length - 4); + itemName = itemName.Substring(0, itemName.Length - 4); } // If we have a Media, then the extension needs to be removed else if (datItem.ItemType == ItemType.Media) { - if (datItem.Name.EndsWith(".dicf")) - datItem.Name = itemName.Substring(0, itemName.Length - 5); - else if (datItem.Name.EndsWith(".aaru")) - datItem.Name = itemName.Substring(0, itemName.Length - 5); - else if (datItem.Name.EndsWith(".aaruformat")) - datItem.Name = itemName.Substring(0, itemName.Length - 11); - else if (datItem.Name.EndsWith(".aaruf")) - datItem.Name = itemName.Substring(0, itemName.Length - 6); - else if (datItem.Name.EndsWith(".aif")) - datItem.Name = itemName.Substring(0, itemName.Length - 3); + if (itemName.EndsWith(".dicf")) + itemName = itemName.Substring(0, itemName.Length - 5); + else if (itemName.EndsWith(".aaru")) + itemName = itemName.Substring(0, itemName.Length - 5); + else if (itemName.EndsWith(".aaruformat")) + itemName = itemName.Substring(0, itemName.Length - 11); + else if (itemName.EndsWith(".aaruf")) + itemName = itemName.Substring(0, itemName.Length - 6); + else if (itemName.EndsWith(".aif")) + itemName = itemName.Substring(0, itemName.Length - 3); } - // All others leave the extension alone - else - { - datItem.Name = itemName; - } + // Set the item name back + datItem.SetFields(new Dictionary { [Field.DatItem_Name] = itemName }); } #endregion @@ -2710,7 +2669,7 @@ namespace SabreTools.Library.DatFiles BaseFile tgzRom = tgz.GetTorrentGZFileInfo(); if (isZip == false && tgzRom != null && (outputFormat == OutputFormat.TorrentGzip || outputFormat == OutputFormat.TorrentGzipRomba)) { - Globals.Logger.User($"Matches found for '{Path.GetFileName(datItem.Name)}', rebuilding accordingly..."); + Globals.Logger.User($"Matches found for '{Path.GetFileName(datItem.GetName() ?? string.Empty)}', rebuilding accordingly..."); // Get the proper output path if (outputFormat == OutputFormat.TorrentGzipRomba) @@ -2738,7 +2697,7 @@ namespace SabreTools.Library.DatFiles BaseFile txzRom = txz.GetTorrentXZFileInfo(); if (isZip == false && txzRom != null && (outputFormat == OutputFormat.TorrentXZ || outputFormat == OutputFormat.TorrentXZRomba)) { - Globals.Logger.User($"Matches found for '{Path.GetFileName(datItem.Name)}', rebuilding accordingly..."); + Globals.Logger.User($"Matches found for '{Path.GetFileName(datItem.GetName() ?? datItem.ItemType.ToString())}', rebuilding accordingly..."); // Get the proper output path if (outputFormat == OutputFormat.TorrentXZRomba) @@ -2769,7 +2728,7 @@ namespace SabreTools.Library.DatFiles { BaseArchive archive = BaseArchive.Create(file); if (archive != null) - (fileStream, _) = archive.CopyToStream(datItem.Name); + (fileStream, _) = archive.CopyToStream(datItem.GetName() ?? datItem.ItemType.ToString()); } // Otherwise, just open the filestream else @@ -2805,7 +2764,7 @@ namespace SabreTools.Library.DatFiles dupes.Add(item); } - Globals.Logger.User($"{(inverse ? "No matches" : "Matches")} found for '{Path.GetFileName(datItem.Name)}', rebuilding accordingly..."); + Globals.Logger.User($"{(inverse ? "No matches" : "Matches")} found for '{Path.GetFileName(datItem.GetName() ?? datItem.ItemType.ToString())}', rebuilding accordingly..."); rebuilt = true; // Special case for partial packing mode @@ -2847,7 +2806,7 @@ namespace SabreTools.Library.DatFiles { BaseArchive archive = BaseArchive.Create(file); if (archive != null) - (fileStream, _) = archive.CopyToStream(datItem.Name); + (fileStream, _) = archive.CopyToStream(datItem.GetName() ?? datItem.ItemType.ToString()); } // Otherwise, just open the filestream else @@ -2879,7 +2838,7 @@ namespace SabreTools.Library.DatFiles // If it has duplicates and we're not filtering, rebuild it if (hasDuplicates && !inverse) { - Globals.Logger.User($"Headerless matches found for '{Path.GetFileName(datItem.Name)}', rebuilding accordingly..."); + Globals.Logger.User($"Headerless matches found for '{Path.GetFileName(datItem.GetName() ?? datItem.ItemType.ToString())}', rebuilding accordingly..."); rebuilt = true; // Now loop through the list and rebuild accordingly @@ -2887,7 +2846,7 @@ namespace SabreTools.Library.DatFiles { // Create a headered item to use as well datItem.CopyMachineInformation(item); - datItem.Name += $"_{crc}"; + datItem.SetFields(new Dictionary { [Field.DatItem_Name] = $"{datItem.GetName()}_{crc}" } ); // If either copy succeeds, then we want to set rebuilt to true bool eitherSuccess = false; @@ -3091,11 +3050,11 @@ namespace SabreTools.Library.DatFiles List items = Items[key]; foreach (DatItem item in items) { - if (newExtA.Contains(PathExtensions.GetNormalizedExtension(item.Name))) + if (newExtA.Contains(PathExtensions.GetNormalizedExtension(item.GetName() ?? string.Empty))) { extADat.Items.Add(key, item); } - else if (newExtB.Contains(PathExtensions.GetNormalizedExtension(item.Name))) + else if (newExtB.Contains(PathExtensions.GetNormalizedExtension(item.GetName() ?? string.Empty))) { extBDat.Items.Add(key, item); } @@ -3525,7 +3484,7 @@ namespace SabreTools.Library.DatFiles // Initialize strings string fix = string.Empty, game = item.Machine.Name, - name = item.Name, + name = item.GetName() ?? item.ItemType.ToString(), crc = string.Empty, md5 = string.Empty, ripemd160 = string.Empty, @@ -3599,7 +3558,7 @@ namespace SabreTools.Library.DatFiles /// True if the UseRomName should be always on (default), false otherwise protected void ProcessItemName(DatItem item, bool forceRemoveQuotes, bool forceRomName = true) { - string name = item.Name; + string name = item.GetName() ?? string.Empty; // Backup relevant values and set new ones accordingly bool quotesBackup = Header.Quotes; @@ -3625,7 +3584,7 @@ namespace SabreTools.Library.DatFiles if (!string.IsNullOrWhiteSpace(disk.SHA1)) { name = PathExtensions.GetDepotPath(disk.SHA1, Header.OutputDepot.Depth).Replace('\\', '/'); - item.Name = pre + name + post; + item.SetFields(new Dictionary { [Field.DatItem_Name] = $"{pre}{name}{post}" } ); } } else if (item.ItemType == ItemType.Media) @@ -3636,7 +3595,7 @@ namespace SabreTools.Library.DatFiles if (!string.IsNullOrWhiteSpace(media.SHA1)) { name = PathExtensions.GetDepotPath(media.SHA1, Header.OutputDepot.Depth).Replace('\\', '/'); - item.Name = pre + name + post; + item.SetFields(new Dictionary { [Field.DatItem_Name] = $"{pre}{name}{post}" }); } } else if (item.ItemType == ItemType.Rom) @@ -3647,7 +3606,7 @@ namespace SabreTools.Library.DatFiles if (!string.IsNullOrWhiteSpace(rom.SHA1)) { name = PathExtensions.GetDepotPath(rom.SHA1, Header.OutputDepot.Depth).Replace('\\', '/'); - item.Name = $"{pre}{name}{post}"; + item.SetFields(new Dictionary { [Field.DatItem_Name] = $"{pre}{name}{post}" }); } } @@ -3671,7 +3630,7 @@ namespace SabreTools.Library.DatFiles name = Path.Combine(item.Machine.Name, name); // Now assign back the item name - item.Name = pre + name + post; + item.SetFields(new Dictionary { [Field.DatItem_Name] = pre + name + post }); // Restore all relevant values if (forceRemoveQuotes) @@ -3700,7 +3659,7 @@ namespace SabreTools.Library.DatFiles { Globals.Logger.Verbose($"Empty folder found: {datItem.Machine.Name}"); - datItem.Name = (datItem.Name == "null" ? "-" : datItem.Name); + rom.Name = (rom.Name == "null" ? "-" : rom.Name); rom.Size = Constants.SizeZero; rom.CRC = rom.CRC == "null" ? Constants.CRCZero : null; rom.MD5 = rom.MD5 == "null" ? Constants.MD5Zero : null; diff --git a/SabreTools.Library/DatFiles/ItemDictionary.cs b/SabreTools.Library/DatFiles/ItemDictionary.cs index 3f41a1a7..f39e2599 100644 --- a/SabreTools.Library/DatFiles/ItemDictionary.cs +++ b/SabreTools.Library/DatFiles/ItemDictionary.cs @@ -402,7 +402,6 @@ namespace SabreTools.Library.DatFiles // Filter the list fi = fi.Where(i => i != null) .Where(i => !i.Remove) - .Where(i => i.Name != null) .Where(i => i.Machine?.Name != null) .ToList(); diff --git a/SabreTools.Library/DatItems/Adjuster.cs b/SabreTools.Library/DatItems/Adjuster.cs index 2534ba0b..0152db3a 100644 --- a/SabreTools.Library/DatItems/Adjuster.cs +++ b/SabreTools.Library/DatItems/Adjuster.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.IO; using System.Linq; using SabreTools.Library.Filtering; @@ -15,6 +16,12 @@ namespace SabreTools.Library.DatItems { #region Fields + /// + /// Name of the item + /// + [JsonProperty("name")] + public string Name { get; set; } + /// /// Determine whether the value is default /// @@ -31,6 +38,15 @@ namespace SabreTools.Library.DatItems #region Accessors + /// + /// Gets the name to use for a DatItem + /// + /// Name if available, null otherwise + public override string GetName() + { + return Name; + } + /// /// Set fields with given values /// @@ -41,6 +57,9 @@ namespace SabreTools.Library.DatItems base.SetFields(mappings); // Handle Adjuster-specific fields + if (mappings.Keys.Contains(Field.DatItem_Name)) + Name = mappings[Field.DatItem_Name]; + if (mappings.Keys.Contains(Field.DatItem_Default)) Default = mappings[Field.DatItem_Default].AsYesNo(); @@ -120,6 +139,33 @@ namespace SabreTools.Library.DatItems #region Filtering + /// + /// Clean a DatItem according to the cleaner + /// + /// Cleaner to implement + public override void Clean(Cleaner cleaner) + { + // Clean common items first + base.Clean(cleaner); + + // If we're stripping unicode characters, strip item name + if (cleaner?.RemoveUnicode == true) + Name = Sanitizer.RemoveUnicodeCharacters(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 - Machine.Name.Length - (cleaner.Root?.Length ?? 0); + if (Name.Length > usableLength) + { + string ext = Path.GetExtension(Name); + Name = Name.Substring(0, usableLength - ext.Length); + Name += ext; + } + } + } + /// /// Check to see if a DatItem passes the filter /// @@ -131,6 +177,12 @@ namespace SabreTools.Library.DatItems if (!base.PassesFilter(filter)) return false; + // Filter on item name + if (filter.DatItem_Name.MatchesPositiveSet(Name) == false) + return false; + if (filter.DatItem_Name.MatchesNegativeSet(Name) == true) + return false; + // Filter on default if (filter.DatItem_Default.MatchesNeutral(null, Default) == false) return false; @@ -150,6 +202,9 @@ namespace SabreTools.Library.DatItems base.RemoveFields(fields); // Remove the fields + if (fields.Contains(Field.DatItem_Name)) + Name = null; + if (fields.Contains(Field.DatItem_Default)) Default = null; @@ -159,6 +214,16 @@ namespace SabreTools.Library.DatItems // TODO: Handle DatItem_Condition* } + /// + /// Set internal names to match One Rom Per Game (ORPG) logic + /// + public override void SetOneRomPerGame() + { + string[] splitname = Name.Split('.'); + Machine.Name += $"/{string.Join(".", splitname.Take(splitname.Length > 1 ? splitname.Length - 1 : 1))}"; + Name = Path.GetFileName(Name); + } + #endregion #region Sorting and Merging @@ -181,6 +246,9 @@ namespace SabreTools.Library.DatItems Adjuster newItem = item as Adjuster; // Replace the fields + if (fields.Contains(Field.DatItem_Name)) + Name = newItem.Name; + if (fields.Contains(Field.DatItem_Default)) Default = newItem.Default; diff --git a/SabreTools.Library/DatItems/Archive.cs b/SabreTools.Library/DatItems/Archive.cs index ebdf56da..170abdcd 100644 --- a/SabreTools.Library/DatItems/Archive.cs +++ b/SabreTools.Library/DatItems/Archive.cs @@ -1,4 +1,10 @@ -using Newtonsoft.Json; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +using SabreTools.Library.Filtering; +using SabreTools.Library.Tools; +using Newtonsoft.Json; namespace SabreTools.Library.DatItems { @@ -8,6 +14,43 @@ namespace SabreTools.Library.DatItems [JsonObject("archive")] public class Archive : DatItem { + #region Fields + + /// + /// Name of the item + /// + [JsonProperty("name")] + public string Name { get; set; } + + #endregion + + #region Accessors + + /// + /// Gets the name to use for a DatItem + /// + /// Name if available, null otherwise + public override string GetName() + { + return Name; + } + + /// + /// Set fields with given values + /// + /// Mappings dictionary + public override void SetFields(Dictionary mappings) + { + // Set base fields + base.SetFields(mappings); + + // Handle Archive-specific fields + if (mappings.Keys.Contains(Field.DatItem_Name)) + Name = mappings[Field.DatItem_Name]; + } + + #endregion + #region Constructors /// @@ -73,5 +116,106 @@ namespace SabreTools.Library.DatItems } #endregion + + #region Filtering + + /// + /// Clean a DatItem according to the cleaner + /// + /// Cleaner to implement + public override void Clean(Cleaner cleaner) + { + // Clean common items first + base.Clean(cleaner); + + // If we're stripping unicode characters, strip item name + if (cleaner?.RemoveUnicode == true) + Name = Sanitizer.RemoveUnicodeCharacters(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 - Machine.Name.Length - (cleaner.Root?.Length ?? 0); + if (Name.Length > usableLength) + { + string ext = Path.GetExtension(Name); + Name = Name.Substring(0, usableLength - ext.Length); + Name += ext; + } + } + } + + /// + /// Check to see if a DatItem passes the filter + /// + /// Filter to check against + /// True if the item passed the filter, false otherwise + public override bool PassesFilter(Filter filter) + { + // Check common fields first + if (!base.PassesFilter(filter)) + return false; + + // Filter on item name + if (filter.DatItem_Name.MatchesPositiveSet(Name) == false) + return false; + if (filter.DatItem_Name.MatchesNegativeSet(Name) == true) + return false; + + return true; + } + + /// + /// Remove fields from the DatItem + /// + /// List of Fields to remove + public override void RemoveFields(List fields) + { + // Remove common fields first + base.RemoveFields(fields); + + // Remove the fields + if (fields.Contains(Field.DatItem_Name)) + Name = null; + } + + /// + /// Set internal names to match One Rom Per Game (ORPG) logic + /// + public override void SetOneRomPerGame() + { + string[] splitname = Name.Split('.'); + Machine.Name += $"/{string.Join(".", splitname.Take(splitname.Length > 1 ? splitname.Length - 1 : 1))}"; + Name = Path.GetFileName(Name); + } + + #endregion + + #region Sorting and Merging + + /// + /// Replace fields from another item + /// + /// DatItem to pull new information from + /// List of Fields representing what should be updated + public override void ReplaceFields(DatItem item, List fields) + { + // Replace common fields first + base.ReplaceFields(item, fields); + + // If we don't have a Archive to replace from, ignore specific fields + if (item.ItemType != ItemType.Archive) + return; + + // Cast for easier access + Archive newItem = item as Archive; + + // Replace the fields + if (fields.Contains(Field.DatItem_Name)) + Name = newItem.Name; + } + + #endregion } } diff --git a/SabreTools.Library/DatItems/Auxiliary.cs b/SabreTools.Library/DatItems/Auxiliary.cs index 57d2419e..47ee2a99 100644 --- a/SabreTools.Library/DatItems/Auxiliary.cs +++ b/SabreTools.Library/DatItems/Auxiliary.cs @@ -24,7 +24,7 @@ namespace SabreTools.Library.DatItems /// /// Represents one ListXML condition /// - /// TODO: Promote to DatItem level? (Both used at ListXML level AND under a lot of stuff) + /// TODO: Promote to DatItem level? (doesn't have "name" field?) (Both used at ListXML level AND under a lot of stuff) [JsonObject("condition")] public class Condition { diff --git a/SabreTools.Library/DatItems/BiosSet.cs b/SabreTools.Library/DatItems/BiosSet.cs index 31588f3d..56cb14e2 100644 --- a/SabreTools.Library/DatItems/BiosSet.cs +++ b/SabreTools.Library/DatItems/BiosSet.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.IO; using System.Linq; using SabreTools.Library.Filtering; @@ -15,6 +16,12 @@ namespace SabreTools.Library.DatItems { #region Fields + /// + /// Name of the item + /// + [JsonProperty("name")] + public string Name { get; set; } + /// /// Description of the BIOS /// @@ -31,6 +38,15 @@ namespace SabreTools.Library.DatItems #region Accessors + /// + /// Gets the name to use for a DatItem + /// + /// Name if available, null otherwise + public override string GetName() + { + return Name; + } + /// /// Set fields with given values /// @@ -41,6 +57,9 @@ namespace SabreTools.Library.DatItems base.SetFields(mappings); // Handle BiosSet-specific fields + if (mappings.Keys.Contains(Field.DatItem_Name)) + Name = mappings[Field.DatItem_Name]; + if (mappings.Keys.Contains(Field.DatItem_Default)) Default = mappings[Field.DatItem_Default].AsYesNo(); @@ -121,6 +140,33 @@ namespace SabreTools.Library.DatItems #region Filtering + /// + /// Clean a DatItem according to the cleaner + /// + /// Cleaner to implement + public override void Clean(Cleaner cleaner) + { + // Clean common items first + base.Clean(cleaner); + + // If we're stripping unicode characters, strip item name + if (cleaner?.RemoveUnicode == true) + Name = Sanitizer.RemoveUnicodeCharacters(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 - Machine.Name.Length - (cleaner.Root?.Length ?? 0); + if (Name.Length > usableLength) + { + string ext = Path.GetExtension(Name); + Name = Name.Substring(0, usableLength - ext.Length); + Name += ext; + } + } + } + /// /// Check to see if a DatItem passes the filter /// @@ -132,6 +178,12 @@ namespace SabreTools.Library.DatItems if (!base.PassesFilter(filter)) return false; + // Filter on item name + if (filter.DatItem_Name.MatchesPositiveSet(Name) == false) + return false; + if (filter.DatItem_Name.MatchesNegativeSet(Name) == true) + return false; + // Filter on description if (filter.DatItem_Description.MatchesPositiveSet(Description) == false) return false; @@ -155,6 +207,9 @@ namespace SabreTools.Library.DatItems base.RemoveFields(fields); // Remove the fields + if (fields.Contains(Field.DatItem_Name)) + Name = null; + if (fields.Contains(Field.DatItem_Description)) Description = null; @@ -162,6 +217,16 @@ namespace SabreTools.Library.DatItems Default = null; } + /// + /// Set internal names to match One Rom Per Game (ORPG) logic + /// + public override void SetOneRomPerGame() + { + string[] splitname = Name.Split('.'); + Machine.Name += $"/{string.Join(".", splitname.Take(splitname.Length > 1 ? splitname.Length - 1 : 1))}"; + Name = Path.GetFileName(Name); + } + #endregion #region Sorting and Merging @@ -184,6 +249,9 @@ namespace SabreTools.Library.DatItems BiosSet newItem = item as BiosSet; // Replace the fields + if (fields.Contains(Field.DatItem_Name)) + Name = newItem.Name; + if (fields.Contains(Field.DatItem_Description)) Description = newItem.Description; diff --git a/SabreTools.Library/DatItems/Blank.cs b/SabreTools.Library/DatItems/Blank.cs index 5615774f..69bab4a6 100644 --- a/SabreTools.Library/DatItems/Blank.cs +++ b/SabreTools.Library/DatItems/Blank.cs @@ -15,7 +15,6 @@ namespace SabreTools.Library.DatItems /// public Blank() { - Name = string.Empty; ItemType = ItemType.Blank; } @@ -27,7 +26,6 @@ namespace SabreTools.Library.DatItems { return new Blank() { - Name = this.Name, ItemType = this.ItemType, DupeType = this.DupeType, diff --git a/SabreTools.Library/DatItems/Chip.cs b/SabreTools.Library/DatItems/Chip.cs index c2cced83..5caae13c 100644 --- a/SabreTools.Library/DatItems/Chip.cs +++ b/SabreTools.Library/DatItems/Chip.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.IO; using System.Linq; using SabreTools.Library.Filtering; @@ -15,6 +16,12 @@ namespace SabreTools.Library.DatItems { #region Fields + /// + /// Name of the item + /// + [JsonProperty("name")] + public string Name { get; set; } + /// /// Internal tag /// @@ -37,6 +44,15 @@ namespace SabreTools.Library.DatItems #region Accessors + /// + /// Gets the name to use for a DatItem + /// + /// Name if available, null otherwise + public override string GetName() + { + return Name; + } + /// /// Set fields with given values /// @@ -47,6 +63,9 @@ namespace SabreTools.Library.DatItems base.SetFields(mappings); // Handle Chip-specific fields + if (mappings.Keys.Contains(Field.DatItem_Name)) + Name = mappings[Field.DatItem_Name]; + if (mappings.Keys.Contains(Field.DatItem_Tag)) Tag = mappings[Field.DatItem_Tag]; @@ -134,6 +153,33 @@ namespace SabreTools.Library.DatItems #region Filtering + /// + /// Clean a DatItem according to the cleaner + /// + /// Cleaner to implement + public override void Clean(Cleaner cleaner) + { + // Clean common items first + base.Clean(cleaner); + + // If we're stripping unicode characters, strip item name + if (cleaner?.RemoveUnicode == true) + Name = Sanitizer.RemoveUnicodeCharacters(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 - Machine.Name.Length - (cleaner.Root?.Length ?? 0); + if (Name.Length > usableLength) + { + string ext = Path.GetExtension(Name); + Name = Name.Substring(0, usableLength - ext.Length); + Name += ext; + } + } + } + /// /// Check to see if a DatItem passes the filter /// @@ -145,6 +191,12 @@ namespace SabreTools.Library.DatItems if (!base.PassesFilter(filter)) return false; + // Filter on item name + if (filter.DatItem_Name.MatchesPositiveSet(Name) == false) + return false; + if (filter.DatItem_Name.MatchesNegativeSet(Name) == true) + return false; + // DatItem_Tag if (filter.DatItem_Tag.MatchesPositiveSet(Tag) == false) return false; @@ -176,6 +228,9 @@ namespace SabreTools.Library.DatItems base.RemoveFields(fields); // Remove the fields + if (fields.Contains(Field.DatItem_Name)) + Name = null; + if (fields.Contains(Field.DatItem_Tag)) Tag = null; @@ -186,6 +241,16 @@ namespace SabreTools.Library.DatItems Clock = null; } + /// + /// Set internal names to match One Rom Per Game (ORPG) logic + /// + public override void SetOneRomPerGame() + { + string[] splitname = Name.Split('.'); + Machine.Name += $"/{string.Join(".", splitname.Take(splitname.Length > 1 ? splitname.Length - 1 : 1))}"; + Name = Path.GetFileName(Name); + } + #endregion #region Sorting and Merging @@ -208,6 +273,9 @@ namespace SabreTools.Library.DatItems Chip newItem = item as Chip; // Replace the fields + if (fields.Contains(Field.DatItem_Name)) + Name = newItem.Name; + if (fields.Contains(Field.DatItem_Tag)) Tag = newItem.Tag; diff --git a/SabreTools.Library/DatItems/Configuration.cs b/SabreTools.Library/DatItems/Configuration.cs index 620212cc..15074105 100644 --- a/SabreTools.Library/DatItems/Configuration.cs +++ b/SabreTools.Library/DatItems/Configuration.cs @@ -1,7 +1,9 @@ using System.Collections.Generic; +using System.IO; using System.Linq; using SabreTools.Library.Filtering; +using SabreTools.Library.Tools; using Newtonsoft.Json; namespace SabreTools.Library.DatItems @@ -14,6 +16,12 @@ namespace SabreTools.Library.DatItems { #region Fields + /// + /// Name of the item + /// + [JsonProperty("name")] + public string Name { get; set; } + /// /// Tag associated with the configuration /// @@ -48,6 +56,15 @@ namespace SabreTools.Library.DatItems #region Accessors + /// + /// Gets the name to use for a DatItem + /// + /// Name if available, null otherwise + public override string GetName() + { + return Name; + } + /// /// Set fields with given values /// @@ -58,6 +75,9 @@ namespace SabreTools.Library.DatItems base.SetFields(mappings); // Handle Configuration-specific fields + if (mappings.Keys.Contains(Field.DatItem_Name)) + Name = mappings[Field.DatItem_Name]; + if (mappings.Keys.Contains(Field.DatItem_Tag)) Tag = mappings[Field.DatItem_Tag]; @@ -149,6 +169,33 @@ namespace SabreTools.Library.DatItems #region Filtering + /// + /// Clean a DatItem according to the cleaner + /// + /// Cleaner to implement + public override void Clean(Cleaner cleaner) + { + // Clean common items first + base.Clean(cleaner); + + // If we're stripping unicode characters, strip item name + if (cleaner?.RemoveUnicode == true) + Name = Sanitizer.RemoveUnicodeCharacters(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 - Machine.Name.Length - (cleaner.Root?.Length ?? 0); + if (Name.Length > usableLength) + { + string ext = Path.GetExtension(Name); + Name = Name.Substring(0, usableLength - ext.Length); + Name += ext; + } + } + } + /// /// Check to see if a DatItem passes the filter /// @@ -160,6 +207,12 @@ namespace SabreTools.Library.DatItems if (!base.PassesFilter(filter)) return false; + // Filter on item name + if (filter.DatItem_Name.MatchesPositiveSet(Name) == false) + return false; + if (filter.DatItem_Name.MatchesNegativeSet(Name) == true) + return false; + // Filter on tag if (filter.DatItem_Tag.MatchesPositiveSet(Tag) == false) return false; @@ -189,6 +242,9 @@ namespace SabreTools.Library.DatItems base.RemoveFields(fields); // Remove the fields + if (fields.Contains(Field.DatItem_Name)) + Name = null; + if (fields.Contains(Field.DatItem_Tag)) Tag = null; @@ -209,6 +265,16 @@ namespace SabreTools.Library.DatItems // TODO: Handle DatItem_Setting* } + /// + /// Set internal names to match One Rom Per Game (ORPG) logic + /// + public override void SetOneRomPerGame() + { + string[] splitname = Name.Split('.'); + Machine.Name += $"/{string.Join(".", splitname.Take(splitname.Length > 1 ? splitname.Length - 1 : 1))}"; + Name = Path.GetFileName(Name); + } + #endregion #region Sorting and Merging @@ -231,6 +297,9 @@ namespace SabreTools.Library.DatItems Configuration newItem = item as Configuration; // Replace the fields + if (fields.Contains(Field.DatItem_Name)) + Name = newItem.Name; + if (fields.Contains(Field.DatItem_Tag)) Tag = newItem.Tag; diff --git a/SabreTools.Library/DatItems/DatItem.cs b/SabreTools.Library/DatItems/DatItem.cs index fb9b2837..dd9a6364 100644 --- a/SabreTools.Library/DatItems/DatItem.cs +++ b/SabreTools.Library/DatItems/DatItem.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Net; using SabreTools.Library.Data; using SabreTools.Library.FileTypes; @@ -26,12 +25,6 @@ namespace SabreTools.Library.DatItems #region Common Fields - /// - /// Name of the item - /// - [JsonProperty("name")] - public string Name { get; set; } - /// /// Item type for outputting /// @@ -368,6 +361,15 @@ namespace SabreTools.Library.DatItems #region Accessors + /// + /// Gets the name to use for a DatItem + /// + /// Name if available, null otherwise + public virtual string GetName() + { + return null; + } + /// /// Set fields with given values /// @@ -380,13 +382,6 @@ namespace SabreTools.Library.DatItems Machine.SetFields(mappings); - #region Common - - if (mappings.Keys.Contains(Field.DatItem_Name)) - Name = mappings[Field.DatItem_Name]; - - #endregion - #region AttractMode if (mappings.Keys.Contains(Field.DatItem_AltName)) @@ -514,13 +509,22 @@ namespace SabreTools.Library.DatItems #else return itemType switch { + ItemType.Adjuster => new Adjuster(), ItemType.Archive => new Archive(), ItemType.BiosSet => new BiosSet(), ItemType.Blank => new Blank(), + ItemType.Chip => new Chip(), + ItemType.Configuration => new Configuration(), + ItemType.DeviceReference => new DeviceReference(), + ItemType.DipSwitch => new DipSwitch(), ItemType.Disk => new Disk(), + ItemType.Media => new Media(), + ItemType.RamOption => new RamOption(), ItemType.Release => new Release(), ItemType.Rom => new Rom(), ItemType.Sample => new Sample(), + ItemType.Slot => new Slot(), + ItemType.SoftwareList => new SoftwareList(), _ => new Rom(), }; #endif @@ -596,10 +600,7 @@ namespace SabreTools.Library.DatItems { try { - if (Name == other.Name) - return Equals(other) ? 0 : 1; - - return string.Compare(Name, other.Name); + return ItemType - other.ItemType; } catch { @@ -630,7 +631,7 @@ namespace SabreTools.Library.DatItems // If the duplicate is external already or should be, set it if (lastItem.DupeType.HasFlag(DupeType.External) || lastItem.Source.Index != Source.Index) { - if (lastItem.Machine.Name == Machine.Name && lastItem.Name == Name) + if (lastItem.Machine.Name == Machine.Name) output = DupeType.External | DupeType.All; else output = DupeType.External | DupeType.Hash; @@ -639,7 +640,7 @@ namespace SabreTools.Library.DatItems // Otherwise, it's considered an internal dupe else { - if (lastItem.Machine.Name == Machine.Name && lastItem.Name == Name) + if (lastItem.Machine.Name == Machine.Name) output = DupeType.Internal | DupeType.All; else output = DupeType.Internal | DupeType.Hash; @@ -652,6 +653,31 @@ namespace SabreTools.Library.DatItems #region Filtering + /// + /// Clean a DatItem according to the cleaner + /// + /// Cleaner to implement + public virtual void Clean(Cleaner cleaner) + { + // If we're stripping unicode characters, strip machine name and description + if (cleaner?.RemoveUnicode == true) + { + Machine.Name = Sanitizer.RemoveUnicodeCharacters(Machine.Name); + Machine.Description = Sanitizer.RemoveUnicodeCharacters(Machine.Description); + } + + // If we're in cleaning mode, sanitize machine name and description + if (cleaner?.Clean == true) + { + Machine.Name = Sanitizer.CleanGameName(Machine.Name); + Machine.Description = Sanitizer.CleanGameName(Machine.Description); + } + + // If we are in single game mode, rename the machine + if (cleaner?.Single == true) + Machine.Name = "!"; + } + /// /// Check to see if a DatItem passes the filter /// @@ -665,12 +691,6 @@ namespace SabreTools.Library.DatItems #region Common - // Filter on item name - if (filter.DatItem_Name.MatchesPositiveSet(Name) == false) - return false; - if (filter.DatItem_Name.MatchesNegativeSet(Name) == true) - return false; - // Filter on item type if (filter.DatItem_Type.MatchesPositiveSet(ItemType.ToString()) == false) return false; @@ -795,13 +815,6 @@ namespace SabreTools.Library.DatItems // Remove machine fields Machine.RemoveFields(fields); - #region Common - - if (fields.Contains(Field.DatItem_Name)) - Name = null; - - #endregion - #region AttractMode if (fields.Contains(Field.DatItem_AltName)) @@ -863,6 +876,13 @@ namespace SabreTools.Library.DatItems #endregion } + /// + /// Set internal names to match One Rom Per Game (ORPG) logic + /// + public virtual void SetOneRomPerGame() + { + } + #endregion #region Sorting and Merging @@ -943,13 +963,6 @@ namespace SabreTools.Library.DatItems /// List of Fields representing what should be updated public virtual void ReplaceFields(DatItem item, List fields) { - #region Common - - if (fields.Contains(Field.DatItem_Name)) - Name = item.Name; - - #endregion - #region AttractMode if (fields.Contains(Field.DatItem_AltName)) @@ -1125,14 +1138,14 @@ namespace SabreTools.Library.DatItems { saveditem.Source = file.Source.Clone() as Source; saveditem.CopyMachineInformation(file); - saveditem.Name = file.Name; + saveditem.SetFields(new Dictionary { [Field.DatItem_Name] = file.GetName() }); } // If the current machine is a child of the new machine, use the new machine instead if (saveditem.Machine.CloneOf == file.Machine.Name || saveditem.Machine.RomOf == file.Machine.Name) { saveditem.CopyMachineInformation(file); - saveditem.Name = file.Name; + saveditem.SetFields(new Dictionary { [Field.DatItem_Name] = file.GetName() }); } break; @@ -1185,33 +1198,39 @@ namespace SabreTools.Library.DatItems continue; } + // Get the last item name, if applicable + string lastItemName = lastItem.GetName() ?? lastItem.ItemType.ToString(); + + // Get the current item name, if applicable + string datItemName = datItem.GetName() ?? datItem.ItemType.ToString(); + // If the current item exactly matches the last item, then we don't add it if (datItem.GetDuplicateStatus(lastItem).HasFlag(DupeType.All)) { - Globals.Logger.Verbose($"Exact duplicate found for '{datItem.Name}'"); + Globals.Logger.Verbose($"Exact duplicate found for '{datItemName}'"); continue; } // If the current name matches the previous name, rename the current item - else if (datItem.Name == lastItem.Name) + else if (datItemName == lastItemName) { - Globals.Logger.Verbose($"Name duplicate found for '{datItem.Name}'"); + Globals.Logger.Verbose($"Name duplicate found for '{datItemName}'"); if (datItem.ItemType == ItemType.Disk || datItem.ItemType == ItemType.Media || datItem.ItemType == ItemType.Rom) { - datItem.Name += GetDuplicateSuffix(datItem); + datItemName += GetDuplicateSuffix(datItem); #if NET_FRAMEWORK - lastrenamed = lastrenamed ?? datItem.Name; + lastrenamed = lastrenamed ?? datItemName; #else - lastrenamed ??= datItem.Name; + lastrenamed ??= datItemName; #endif } // If we have a conflict with the last renamed item, do the right thing - if (datItem.Name == lastrenamed) + if (datItemName == lastrenamed) { - lastrenamed = datItem.Name; - datItem.Name += (lastid == 0 ? string.Empty : "_" + lastid); + lastrenamed = datItemName; + datItemName += (lastid == 0 ? string.Empty : "_" + lastid); lastid++; } // If we have no conflict, then we want to reset the lastrenamed and id @@ -1221,6 +1240,9 @@ namespace SabreTools.Library.DatItems lastid = 0; } + // Set the item name back to the datItem + datItem.SetFields(new Dictionary { [Field.DatItem_Name] = datItemName }); + output.Add(datItem); } @@ -1274,10 +1296,10 @@ namespace SabreTools.Library.DatItems { if (x.ItemType == y.ItemType) { - if (Path.GetDirectoryName(Sanitizer.RemovePathUnsafeCharacters(x.Name)) == Path.GetDirectoryName(Sanitizer.RemovePathUnsafeCharacters(y.Name))) - return nc.Compare(Path.GetFileName(Sanitizer.RemovePathUnsafeCharacters(x.Name)), Path.GetFileName(Sanitizer.RemovePathUnsafeCharacters(y.Name))); + if (Path.GetDirectoryName(Sanitizer.RemovePathUnsafeCharacters(x.GetName() ?? string.Empty)) == Path.GetDirectoryName(Sanitizer.RemovePathUnsafeCharacters(y.GetName() ?? string.Empty))) + return nc.Compare(Path.GetFileName(Sanitizer.RemovePathUnsafeCharacters(x.GetName() ?? string.Empty)), Path.GetFileName(Sanitizer.RemovePathUnsafeCharacters(y.GetName() ?? string.Empty))); - return nc.Compare(Path.GetDirectoryName(Sanitizer.RemovePathUnsafeCharacters(x.Name)), Path.GetDirectoryName(Sanitizer.RemovePathUnsafeCharacters(y.Name))); + return nc.Compare(Path.GetDirectoryName(Sanitizer.RemovePathUnsafeCharacters(x.GetName() ?? string.Empty)), Path.GetDirectoryName(Sanitizer.RemovePathUnsafeCharacters(y.GetName() ?? string.Empty))); } return x.ItemType - y.ItemType; diff --git a/SabreTools.Library/DatItems/DeviceReference.cs b/SabreTools.Library/DatItems/DeviceReference.cs index a787d498..7170141d 100644 --- a/SabreTools.Library/DatItems/DeviceReference.cs +++ b/SabreTools.Library/DatItems/DeviceReference.cs @@ -1,4 +1,10 @@ -using Newtonsoft.Json; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +using SabreTools.Library.Filtering; +using SabreTools.Library.Tools; +using Newtonsoft.Json; namespace SabreTools.Library.DatItems { @@ -8,6 +14,43 @@ namespace SabreTools.Library.DatItems [JsonObject("device_ref")] public class DeviceReference : DatItem { + #region Fields + + /// + /// Name of the item + /// + [JsonProperty("name")] + public string Name { get; set; } + + #endregion + + #region Accessors + + /// + /// Gets the name to use for a DatItem + /// + /// Name if available, null otherwise + public override string GetName() + { + return Name; + } + + /// + /// Set fields with given values + /// + /// Mappings dictionary + public override void SetFields(Dictionary mappings) + { + // Set base fields + base.SetFields(mappings); + + // Handle DeviceReference-specific fields + if (mappings.Keys.Contains(Field.DatItem_Name)) + Name = mappings[Field.DatItem_Name]; + } + + #endregion + #region Constructors /// @@ -73,5 +116,106 @@ namespace SabreTools.Library.DatItems } #endregion + + #region Filtering + + /// + /// Clean a DatItem according to the cleaner + /// + /// Cleaner to implement + public override void Clean(Cleaner cleaner) + { + // Clean common items first + base.Clean(cleaner); + + // If we're stripping unicode characters, strip item name + if (cleaner?.RemoveUnicode == true) + Name = Sanitizer.RemoveUnicodeCharacters(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 - Machine.Name.Length - (cleaner.Root?.Length ?? 0); + if (Name.Length > usableLength) + { + string ext = Path.GetExtension(Name); + Name = Name.Substring(0, usableLength - ext.Length); + Name += ext; + } + } + } + + /// + /// Check to see if a DatItem passes the filter + /// + /// Filter to check against + /// True if the item passed the filter, false otherwise + public override bool PassesFilter(Filter filter) + { + // Check common fields first + if (!base.PassesFilter(filter)) + return false; + + // Filter on item name + if (filter.DatItem_Name.MatchesPositiveSet(Name) == false) + return false; + if (filter.DatItem_Name.MatchesNegativeSet(Name) == true) + return false; + + return true; + } + + /// + /// Remove fields from the DatItem + /// + /// List of Fields to remove + public override void RemoveFields(List fields) + { + // Remove common fields first + base.RemoveFields(fields); + + // Remove the fields + if (fields.Contains(Field.DatItem_Name)) + Name = null; + } + + /// + /// Set internal names to match One Rom Per Game (ORPG) logic + /// + public override void SetOneRomPerGame() + { + string[] splitname = Name.Split('.'); + Machine.Name += $"/{string.Join(".", splitname.Take(splitname.Length > 1 ? splitname.Length - 1 : 1))}"; + Name = Path.GetFileName(Name); + } + + #endregion + + #region Sorting and Merging + + /// + /// Replace fields from another item + /// + /// DatItem to pull new information from + /// List of Fields representing what should be updated + public override void ReplaceFields(DatItem item, List fields) + { + // Replace common fields first + base.ReplaceFields(item, fields); + + // If we don't have a DeviceReference to replace from, ignore specific fields + if (item.ItemType != ItemType.DeviceReference) + return; + + // Cast for easier access + DeviceReference newItem = item as DeviceReference; + + // Replace the fields + if (fields.Contains(Field.DatItem_Name)) + Name = newItem.Name; + } + + #endregion } } diff --git a/SabreTools.Library/DatItems/DipSwitch.cs b/SabreTools.Library/DatItems/DipSwitch.cs index f56dd88a..f990cd5d 100644 --- a/SabreTools.Library/DatItems/DipSwitch.cs +++ b/SabreTools.Library/DatItems/DipSwitch.cs @@ -1,7 +1,9 @@ using System.Collections.Generic; +using System.IO; using System.Linq; using SabreTools.Library.Filtering; +using SabreTools.Library.Tools; using Newtonsoft.Json; namespace SabreTools.Library.DatItems @@ -14,6 +16,12 @@ namespace SabreTools.Library.DatItems { #region Fields + /// + /// Name of the item + /// + [JsonProperty("name")] + public string Name { get; set; } + /// /// Tag associated with the dipswitch /// @@ -48,6 +56,15 @@ namespace SabreTools.Library.DatItems #region Accessors + /// + /// Gets the name to use for a DatItem + /// + /// Name if available, null otherwise + public override string GetName() + { + return Name; + } + /// /// Set fields with given values /// @@ -58,6 +75,9 @@ namespace SabreTools.Library.DatItems base.SetFields(mappings); // Handle DipSwitch-specific fields + if (mappings.Keys.Contains(Field.DatItem_Name)) + Name = mappings[Field.DatItem_Name]; + if (mappings.Keys.Contains(Field.DatItem_Tag)) Tag = mappings[Field.DatItem_Tag]; @@ -149,6 +169,33 @@ namespace SabreTools.Library.DatItems #region Filtering + /// + /// Clean a DatItem according to the cleaner + /// + /// Cleaner to implement + public override void Clean(Cleaner cleaner) + { + // Clean common items first + base.Clean(cleaner); + + // If we're stripping unicode characters, strip item name + if (cleaner?.RemoveUnicode == true) + Name = Sanitizer.RemoveUnicodeCharacters(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 - Machine.Name.Length - (cleaner.Root?.Length ?? 0); + if (Name.Length > usableLength) + { + string ext = Path.GetExtension(Name); + Name = Name.Substring(0, usableLength - ext.Length); + Name += ext; + } + } + } + /// /// Check to see if a DatItem passes the filter /// @@ -160,6 +207,12 @@ namespace SabreTools.Library.DatItems if (!base.PassesFilter(filter)) return false; + // Filter on item name + if (filter.DatItem_Name.MatchesPositiveSet(Name) == false) + return false; + if (filter.DatItem_Name.MatchesNegativeSet(Name) == true) + return false; + // Filter on tag if (filter.DatItem_Tag.MatchesPositiveSet(Tag) == false) return false; @@ -189,6 +242,9 @@ namespace SabreTools.Library.DatItems base.RemoveFields(fields); // Remove the fields + if (fields.Contains(Field.DatItem_Name)) + Name = null; + if (fields.Contains(Field.DatItem_Tag)) Tag = null; @@ -209,6 +265,16 @@ namespace SabreTools.Library.DatItems // TODO: Handle DatItem_Value* } + /// + /// Set internal names to match One Rom Per Game (ORPG) logic + /// + public override void SetOneRomPerGame() + { + string[] splitname = Name.Split('.'); + Machine.Name += $"/{string.Join(".", splitname.Take(splitname.Length > 1 ? splitname.Length - 1 : 1))}"; + Name = Path.GetFileName(Name); + } + #endregion #region Sorting and Merging @@ -231,6 +297,9 @@ namespace SabreTools.Library.DatItems DipSwitch newItem = item as DipSwitch; // Replace the fields + if (fields.Contains(Field.DatItem_Name)) + Name = newItem.Name; + if (fields.Contains(Field.DatItem_Tag)) Tag = newItem.Tag; diff --git a/SabreTools.Library/DatItems/Disk.cs b/SabreTools.Library/DatItems/Disk.cs index 8b8fa7bc..b173a025 100644 --- a/SabreTools.Library/DatItems/Disk.cs +++ b/SabreTools.Library/DatItems/Disk.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.IO; using System.Linq; using SabreTools.Library.FileTypes; @@ -24,6 +25,12 @@ namespace SabreTools.Library.DatItems #region Fields + /// + /// Name of the item + /// + [JsonProperty("name")] + public string Name { get; set; } + /// /// Data MD5 hash /// @@ -85,6 +92,15 @@ namespace SabreTools.Library.DatItems #region Accessors + /// + /// Gets the name to use for a DatItem + /// + /// Name if available, null otherwise + public override string GetName() + { + return Name; + } + /// /// Set fields with given values /// @@ -95,6 +111,9 @@ namespace SabreTools.Library.DatItems base.SetFields(mappings); // Handle Disk-specific fields + if (mappings.Keys.Contains(Field.DatItem_Name)) + Name = mappings[Field.DatItem_Name]; + if (mappings.Keys.Contains(Field.DatItem_MD5)) MD5 = mappings[Field.DatItem_MD5]; @@ -345,6 +364,33 @@ namespace SabreTools.Library.DatItems #region Filtering + /// + /// Clean a DatItem according to the cleaner + /// + /// Cleaner to implement + public override void Clean(Cleaner cleaner) + { + // Clean common items first + base.Clean(cleaner); + + // If we're stripping unicode characters, strip item name + if (cleaner?.RemoveUnicode == true) + Name = Sanitizer.RemoveUnicodeCharacters(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 - Machine.Name.Length - (cleaner.Root?.Length ?? 0); + if (Name.Length > usableLength) + { + string ext = Path.GetExtension(Name); + Name = Name.Substring(0, usableLength - ext.Length); + Name += ext; + } + } + } + /// /// Check to see if a DatItem passes the filter /// @@ -356,6 +402,12 @@ namespace SabreTools.Library.DatItems if (!base.PassesFilter(filter)) return false; + // Filter on item name + if (filter.DatItem_Name.MatchesPositiveSet(Name) == false) + return false; + if (filter.DatItem_Name.MatchesNegativeSet(Name) == true) + return false; + // Filter on MD5 if (filter.DatItem_MD5.MatchesPositiveSet(MD5) == false) return false; @@ -413,6 +465,9 @@ namespace SabreTools.Library.DatItems base.RemoveFields(fields); // Remove the fields + if (fields.Contains(Field.DatItem_Name)) + Name = null; + if (fields.Contains(Field.DatItem_MD5)) MD5 = null; @@ -438,6 +493,16 @@ namespace SabreTools.Library.DatItems Optional = null; } + /// + /// Set internal names to match One Rom Per Game (ORPG) logic + /// + public override void SetOneRomPerGame() + { + string[] splitname = Name.Split('.'); + Machine.Name += $"/{string.Join(".", splitname.Take(splitname.Length > 1 ? splitname.Length - 1 : 1))}"; + Name = Path.GetFileName(Name); + } + #endregion #region Sorting and Merging @@ -495,6 +560,9 @@ namespace SabreTools.Library.DatItems Disk newItem = item as Disk; // Replace the fields + if (fields.Contains(Field.DatItem_Name)) + Name = newItem.Name; + if (fields.Contains(Field.DatItem_MD5)) { if (string.IsNullOrEmpty(MD5) && !string.IsNullOrEmpty(newItem.MD5)) diff --git a/SabreTools.Library/DatItems/Media.cs b/SabreTools.Library/DatItems/Media.cs index a177cda9..1ad694f4 100644 --- a/SabreTools.Library/DatItems/Media.cs +++ b/SabreTools.Library/DatItems/Media.cs @@ -1,12 +1,11 @@ using System.Collections.Generic; +using System.IO; using System.Linq; -using SabreTools.Library.Data; using SabreTools.Library.FileTypes; using SabreTools.Library.Filtering; using SabreTools.Library.Tools; using Newtonsoft.Json; -using Newtonsoft.Json.Converters; namespace SabreTools.Library.DatItems { @@ -21,12 +20,18 @@ namespace SabreTools.Library.DatItems private byte[] _md5; // 16 bytes private byte[] _sha1; // 20 bytes private byte[] _sha256; // 32 bytes - // TODO: Implement SpamSum + // TODO: Implement SpamSum #endregion #region Fields + /// + /// Name of the item + /// + [JsonProperty("name")] + public string Name { get; set; } + /// /// Data MD5 hash /// @@ -61,6 +66,15 @@ namespace SabreTools.Library.DatItems #region Accessors + /// + /// Gets the name to use for a DatItem + /// + /// Name if available, null otherwise + public override string GetName() + { + return Name; + } + /// /// Set fields with given values /// @@ -71,6 +85,9 @@ namespace SabreTools.Library.DatItems base.SetFields(mappings); // Handle Media-specific fields + if (mappings.Keys.Contains(Field.DatItem_Name)) + Name = mappings[Field.DatItem_Name]; + if (mappings.Keys.Contains(Field.DatItem_MD5)) MD5 = mappings[Field.DatItem_MD5]; @@ -294,6 +311,33 @@ namespace SabreTools.Library.DatItems #region Filtering + /// + /// Clean a DatItem according to the cleaner + /// + /// Cleaner to implement + public override void Clean(Cleaner cleaner) + { + // Clean common items first + base.Clean(cleaner); + + // If we're stripping unicode characters, strip item name + if (cleaner?.RemoveUnicode == true) + Name = Sanitizer.RemoveUnicodeCharacters(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 - Machine.Name.Length - (cleaner.Root?.Length ?? 0); + if (Name.Length > usableLength) + { + string ext = Path.GetExtension(Name); + Name = Name.Substring(0, usableLength - ext.Length); + Name += ext; + } + } + } + /// /// Check to see if a DatItem passes the filter /// @@ -305,6 +349,12 @@ namespace SabreTools.Library.DatItems if (!base.PassesFilter(filter)) return false; + // Filter on item name + if (filter.DatItem_Name.MatchesPositiveSet(Name) == false) + return false; + if (filter.DatItem_Name.MatchesNegativeSet(Name) == true) + return false; + // Filter on MD5 if (filter.DatItem_MD5.MatchesPositiveSet(MD5) == false) return false; @@ -336,6 +386,9 @@ namespace SabreTools.Library.DatItems base.RemoveFields(fields); // Remove the fields + if (fields.Contains(Field.DatItem_Name)) + Name = null; + if (fields.Contains(Field.DatItem_MD5)) MD5 = null; @@ -346,6 +399,16 @@ namespace SabreTools.Library.DatItems SHA256 = null; } + /// + /// Set internal names to match One Rom Per Game (ORPG) logic + /// + public override void SetOneRomPerGame() + { + string[] splitname = Name.Split('.'); + Machine.Name += $"/{string.Join(".", splitname.Take(splitname.Length > 1 ? splitname.Length - 1 : 1))}"; + Name = Path.GetFileName(Name); + } + #endregion #region Sorting and Merging @@ -407,6 +470,9 @@ namespace SabreTools.Library.DatItems Media newItem = item as Media; // Replace the fields + if (fields.Contains(Field.DatItem_Name)) + Name = newItem.Name; + if (fields.Contains(Field.DatItem_MD5)) { if (string.IsNullOrEmpty(MD5) && !string.IsNullOrEmpty(newItem.MD5)) diff --git a/SabreTools.Library/DatItems/RamOption.cs b/SabreTools.Library/DatItems/RamOption.cs index 5f844518..f3d1ab82 100644 --- a/SabreTools.Library/DatItems/RamOption.cs +++ b/SabreTools.Library/DatItems/RamOption.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.IO; using System.Linq; using SabreTools.Library.Filtering; @@ -15,6 +16,12 @@ namespace SabreTools.Library.DatItems { #region Fields + /// + /// Name of the item + /// + [JsonProperty("name")] + public string Name { get; set; } + /// /// Determine whether the RamOption is default /// @@ -31,6 +38,15 @@ namespace SabreTools.Library.DatItems #region Accessors + /// + /// Gets the name to use for a DatItem + /// + /// Name if available, null otherwise + public override string GetName() + { + return Name; + } + /// /// Set fields with given values /// @@ -41,6 +57,9 @@ namespace SabreTools.Library.DatItems base.SetFields(mappings); // Handle BiosSet-specific fields + if (mappings.Keys.Contains(Field.DatItem_Name)) + Name = mappings[Field.DatItem_Name]; + if (mappings.Keys.Contains(Field.DatItem_Default)) Default = mappings[Field.DatItem_Default].AsYesNo(); @@ -121,6 +140,33 @@ namespace SabreTools.Library.DatItems #region Filtering + /// + /// Clean a DatItem according to the cleaner + /// + /// Cleaner to implement + public override void Clean(Cleaner cleaner) + { + // Clean common items first + base.Clean(cleaner); + + // If we're stripping unicode characters, strip item name + if (cleaner?.RemoveUnicode == true) + Name = Sanitizer.RemoveUnicodeCharacters(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 - Machine.Name.Length - (cleaner.Root?.Length ?? 0); + if (Name.Length > usableLength) + { + string ext = Path.GetExtension(Name); + Name = Name.Substring(0, usableLength - ext.Length); + Name += ext; + } + } + } + /// /// Check to see if a DatItem passes the filter /// @@ -132,6 +178,12 @@ namespace SabreTools.Library.DatItems if (!base.PassesFilter(filter)) return false; + // Filter on item name + if (filter.DatItem_Name.MatchesPositiveSet(Name) == false) + return false; + if (filter.DatItem_Name.MatchesNegativeSet(Name) == true) + return false; + // Filter on default if (filter.DatItem_Default.MatchesNeutral(null, Default) == false) return false; @@ -155,6 +207,9 @@ namespace SabreTools.Library.DatItems base.RemoveFields(fields); // Remove the fields + if (fields.Contains(Field.DatItem_Name)) + Name = null; + if (fields.Contains(Field.DatItem_Default)) Default = null; @@ -162,6 +217,16 @@ namespace SabreTools.Library.DatItems Content = null; } + /// + /// Set internal names to match One Rom Per Game (ORPG) logic + /// + public override void SetOneRomPerGame() + { + string[] splitname = Name.Split('.'); + Machine.Name += $"/{string.Join(".", splitname.Take(splitname.Length > 1 ? splitname.Length - 1 : 1))}"; + Name = Path.GetFileName(Name); + } + #endregion #region Sorting and Merging @@ -176,7 +241,7 @@ namespace SabreTools.Library.DatItems // Replace common fields first base.ReplaceFields(item, fields); - // If we don't have a BiosSet to replace from, ignore specific fields + // If we don't have a RamOption to replace from, ignore specific fields if (item.ItemType != ItemType.RamOption) return; @@ -184,6 +249,9 @@ namespace SabreTools.Library.DatItems RamOption newItem = item as RamOption; // Replace the fields + if (fields.Contains(Field.DatItem_Name)) + Name = newItem.Name; + if (fields.Contains(Field.DatItem_Default)) Default = newItem.Default; diff --git a/SabreTools.Library/DatItems/Release.cs b/SabreTools.Library/DatItems/Release.cs index 865cf676..83ac1cdc 100644 --- a/SabreTools.Library/DatItems/Release.cs +++ b/SabreTools.Library/DatItems/Release.cs @@ -1,9 +1,10 @@ using System.Collections.Generic; +using System.IO; using System.Linq; using SabreTools.Library.Filtering; -using Newtonsoft.Json; using SabreTools.Library.Tools; +using Newtonsoft.Json; namespace SabreTools.Library.DatItems { @@ -15,6 +16,12 @@ namespace SabreTools.Library.DatItems { #region Fields + /// + /// Name of the item + /// + [JsonProperty("name")] + public string Name { get; set; } + /// /// Release region(s) /// @@ -43,6 +50,15 @@ namespace SabreTools.Library.DatItems #region Accessors + /// + /// Gets the name to use for a DatItem + /// + /// Name if available, null otherwise + public override string GetName() + { + return Name; + } + /// /// Set fields with given values /// @@ -53,6 +69,9 @@ namespace SabreTools.Library.DatItems base.SetFields(mappings); // Handle Release-specific fields + if (mappings.Keys.Contains(Field.DatItem_Name)) + Name = mappings[Field.DatItem_Name]; + if (mappings.Keys.Contains(Field.DatItem_Region)) Region = mappings[Field.DatItem_Region]; @@ -149,6 +168,33 @@ namespace SabreTools.Library.DatItems #region Filtering + /// + /// Clean a DatItem according to the cleaner + /// + /// Cleaner to implement + public override void Clean(Cleaner cleaner) + { + // Clean common items first + base.Clean(cleaner); + + // If we're stripping unicode characters, strip item name + if (cleaner?.RemoveUnicode == true) + Name = Sanitizer.RemoveUnicodeCharacters(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 - Machine.Name.Length - (cleaner.Root?.Length ?? 0); + if (Name.Length > usableLength) + { + string ext = Path.GetExtension(Name); + Name = Name.Substring(0, usableLength - ext.Length); + Name += ext; + } + } + } + /// /// Check to see if a DatItem passes the filter /// @@ -160,6 +206,12 @@ namespace SabreTools.Library.DatItems if (!base.PassesFilter(filter)) return false; + // Filter on item name + if (filter.DatItem_Name.MatchesPositiveSet(Name) == false) + return false; + if (filter.DatItem_Name.MatchesNegativeSet(Name) == true) + return false; + // Filter on region if (filter.DatItem_Region.MatchesPositiveSet(Region) == false) return false; @@ -195,6 +247,9 @@ namespace SabreTools.Library.DatItems base.RemoveFields(fields); // Remove the fields + if (fields.Contains(Field.DatItem_Name)) + Name = null; + if (fields.Contains(Field.DatItem_Region)) Region = null; @@ -208,6 +263,16 @@ namespace SabreTools.Library.DatItems Default = null; } + /// + /// Set internal names to match One Rom Per Game (ORPG) logic + /// + public override void SetOneRomPerGame() + { + string[] splitname = Name.Split('.'); + Machine.Name += $"/{string.Join(".", splitname.Take(splitname.Length > 1 ? splitname.Length - 1 : 1))}"; + Name = Path.GetFileName(Name); + } + #endregion #region Sorting and Merging @@ -230,6 +295,9 @@ namespace SabreTools.Library.DatItems Release newItem = item as Release; // Replace the fields + if (fields.Contains(Field.DatItem_Name)) + Name = newItem.Name; + if (fields.Contains(Field.DatItem_Region)) Region = newItem.Region; diff --git a/SabreTools.Library/DatItems/Rom.cs b/SabreTools.Library/DatItems/Rom.cs index d4ce5d34..b0a83f8a 100644 --- a/SabreTools.Library/DatItems/Rom.cs +++ b/SabreTools.Library/DatItems/Rom.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using SabreTools.Library.Data; @@ -33,6 +34,12 @@ namespace SabreTools.Library.DatItems #region Fields + /// + /// Name of the item + /// + [JsonProperty("name")] + public string Name { get; set; } + /// /// What BIOS is required for this rom /// @@ -164,6 +171,15 @@ namespace SabreTools.Library.DatItems #region Accessors + /// + /// Gets the name to use for a DatItem + /// + /// Name if available, null otherwise + public override string GetName() + { + return Name; + } + /// /// Set fields with given values /// @@ -174,6 +190,9 @@ namespace SabreTools.Library.DatItems base.SetFields(mappings); // Handle Rom-specific fields + if (mappings.Keys.Contains(Field.DatItem_Name)) + Name = mappings[Field.DatItem_Name]; + if (mappings.Keys.Contains(Field.DatItem_Bios)) Bios = mappings[Field.DatItem_Bios]; @@ -501,6 +520,33 @@ namespace SabreTools.Library.DatItems #region Filtering + /// + /// Clean a DatItem according to the cleaner + /// + /// Cleaner to implement + public override void Clean(Cleaner cleaner) + { + // Clean common items first + base.Clean(cleaner); + + // If we're stripping unicode characters, strip item name + if (cleaner?.RemoveUnicode == true) + Name = Sanitizer.RemoveUnicodeCharacters(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 - Machine.Name.Length - (cleaner.Root?.Length ?? 0); + if (Name.Length > usableLength) + { + string ext = Path.GetExtension(Name); + Name = Name.Substring(0, usableLength - ext.Length); + Name += ext; + } + } + } + /// /// Check to see if a DatItem passes the filter /// @@ -512,6 +558,12 @@ namespace SabreTools.Library.DatItems if (!base.PassesFilter(filter)) return false; + // Filter on item name + if (filter.DatItem_Name.MatchesPositiveSet(Name) == false) + return false; + if (filter.DatItem_Name.MatchesNegativeSet(Name) == true) + return false; + // Filter on bios if (filter.DatItem_Bios.MatchesPositiveSet(Bios) == false) return false; @@ -621,6 +673,9 @@ namespace SabreTools.Library.DatItems base.RemoveFields(fields); // Remove the fields + if (fields.Contains(Field.DatItem_Name)) + Name = null; + if (fields.Contains(Field.DatItem_Bios)) Bios = null; @@ -672,6 +727,16 @@ namespace SabreTools.Library.DatItems Inverted = null; } + /// + /// Set internal names to match One Rom Per Game (ORPG) logic + /// + public override void SetOneRomPerGame() + { + string[] splitname = Name.Split('.'); + Machine.Name += $"/{string.Join(".", splitname.Take(splitname.Length > 1 ? splitname.Length - 1 : 1))}"; + Name = Path.GetFileName(Name); + } + #endregion #region Sorting and Merging @@ -751,6 +816,9 @@ namespace SabreTools.Library.DatItems Rom newItem = item as Rom; // Replace the fields + if (fields.Contains(Field.DatItem_Name)) + Name = newItem.Name; + if (fields.Contains(Field.DatItem_Bios)) Bios = newItem.Bios; diff --git a/SabreTools.Library/DatItems/Sample.cs b/SabreTools.Library/DatItems/Sample.cs index 24a1eded..9f8a0ccb 100644 --- a/SabreTools.Library/DatItems/Sample.cs +++ b/SabreTools.Library/DatItems/Sample.cs @@ -1,4 +1,10 @@ -using Newtonsoft.Json; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +using SabreTools.Library.Filtering; +using SabreTools.Library.Tools; +using Newtonsoft.Json; namespace SabreTools.Library.DatItems { @@ -8,6 +14,43 @@ namespace SabreTools.Library.DatItems [JsonObject("sample")] public class Sample : DatItem { + #region Fields + + /// + /// Name of the item + /// + [JsonProperty("name")] + public string Name { get; set; } + + #endregion + + #region Accessors + + /// + /// Gets the name to use for a DatItem + /// + /// Name if available, null otherwise + public override string GetName() + { + return Name; + } + + /// + /// Set fields with given values + /// + /// Mappings dictionary + public override void SetFields(Dictionary mappings) + { + // Set base fields + base.SetFields(mappings); + + // Handle Sample-specific fields + if (mappings.Keys.Contains(Field.DatItem_Name)) + Name = mappings[Field.DatItem_Name]; + } + + #endregion + #region Constructors /// @@ -73,5 +116,106 @@ namespace SabreTools.Library.DatItems } #endregion + + #region Filtering + + /// + /// Clean a DatItem according to the cleaner + /// + /// Cleaner to implement + public override void Clean(Cleaner cleaner) + { + // Clean common items first + base.Clean(cleaner); + + // If we're stripping unicode characters, strip item name + if (cleaner?.RemoveUnicode == true) + Name = Sanitizer.RemoveUnicodeCharacters(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 - Machine.Name.Length - (cleaner.Root?.Length ?? 0); + if (Name.Length > usableLength) + { + string ext = Path.GetExtension(Name); + Name = Name.Substring(0, usableLength - ext.Length); + Name += ext; + } + } + } + + /// + /// Check to see if a DatItem passes the filter + /// + /// Filter to check against + /// True if the item passed the filter, false otherwise + public override bool PassesFilter(Filter filter) + { + // Check common fields first + if (!base.PassesFilter(filter)) + return false; + + // Filter on item name + if (filter.DatItem_Name.MatchesPositiveSet(Name) == false) + return false; + if (filter.DatItem_Name.MatchesNegativeSet(Name) == true) + return false; + + return true; + } + + /// + /// Remove fields from the DatItem + /// + /// List of Fields to remove + public override void RemoveFields(List fields) + { + // Remove common fields first + base.RemoveFields(fields); + + // Remove the fields + if (fields.Contains(Field.DatItem_Name)) + Name = null; + } + + /// + /// Set internal names to match One Rom Per Game (ORPG) logic + /// + public override void SetOneRomPerGame() + { + string[] splitname = Name.Split('.'); + Machine.Name += $"/{string.Join(".", splitname.Take(splitname.Length > 1 ? splitname.Length - 1 : 1))}"; + Name = Path.GetFileName(Name); + } + + #endregion + + #region Sorting and Merging + + /// + /// Replace fields from another item + /// + /// DatItem to pull new information from + /// List of Fields representing what should be updated + public override void ReplaceFields(DatItem item, List fields) + { + // Replace common fields first + base.ReplaceFields(item, fields); + + // If we don't have a Sample to replace from, ignore specific fields + if (item.ItemType != ItemType.Sample) + return; + + // Cast for easier access + Sample newItem = item as Sample; + + // Replace the fields + if (fields.Contains(Field.DatItem_Name)) + Name = newItem.Name; + } + + #endregion } } diff --git a/SabreTools.Library/DatItems/Slot.cs b/SabreTools.Library/DatItems/Slot.cs index 8536a892..84d4685b 100644 --- a/SabreTools.Library/DatItems/Slot.cs +++ b/SabreTools.Library/DatItems/Slot.cs @@ -1,6 +1,9 @@ using System.Collections.Generic; +using System.IO; +using System.Linq; using SabreTools.Library.Filtering; +using SabreTools.Library.Tools; using Newtonsoft.Json; namespace SabreTools.Library.DatItems @@ -13,6 +16,12 @@ namespace SabreTools.Library.DatItems { #region Fields + /// + /// Name of the item + /// + [JsonProperty("name")] + public string Name { get; set; } + /// /// Slot options associated with the slot /// @@ -23,6 +32,15 @@ namespace SabreTools.Library.DatItems #region Accessors + /// + /// Gets the name to use for a DatItem + /// + /// Name if available, null otherwise + public override string GetName() + { + return Name; + } + /// /// Set fields with given values /// @@ -33,6 +51,8 @@ namespace SabreTools.Library.DatItems base.SetFields(mappings); // Handle Slot-specific fields + if (mappings.Keys.Contains(Field.DatItem_Name)) + Name = mappings[Field.DatItem_Name]; // TODO: Handle DatItem_SlotOption* } @@ -109,6 +129,33 @@ namespace SabreTools.Library.DatItems #region Filtering + /// + /// Clean a DatItem according to the cleaner + /// + /// Cleaner to implement + public override void Clean(Cleaner cleaner) + { + // Clean common items first + base.Clean(cleaner); + + // If we're stripping unicode characters, strip item name + if (cleaner?.RemoveUnicode == true) + Name = Sanitizer.RemoveUnicodeCharacters(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 - Machine.Name.Length - (cleaner.Root?.Length ?? 0); + if (Name.Length > usableLength) + { + string ext = Path.GetExtension(Name); + Name = Name.Substring(0, usableLength - ext.Length); + Name += ext; + } + } + } + /// /// Check to see if a DatItem passes the filter /// @@ -120,6 +167,12 @@ namespace SabreTools.Library.DatItems if (!base.PassesFilter(filter)) return false; + // Filter on item name + if (filter.DatItem_Name.MatchesPositiveSet(Name) == false) + return false; + if (filter.DatItem_Name.MatchesNegativeSet(Name) == true) + return false; + // TODO: Handle DatItem_SlotOption* return true; @@ -135,12 +188,25 @@ namespace SabreTools.Library.DatItems base.RemoveFields(fields); // Remove the fields + if (fields.Contains(Field.DatItem_Name)) + Name = null; + if (fields.Contains(Field.DatItem_SlotOptions)) SlotOptions = null; // TODO: Handle DatItem_SlotOption* } + /// + /// Set internal names to match One Rom Per Game (ORPG) logic + /// + public override void SetOneRomPerGame() + { + string[] splitname = Name.Split('.'); + Machine.Name += $"/{string.Join(".", splitname.Take(splitname.Length > 1 ? splitname.Length - 1 : 1))}"; + Name = Path.GetFileName(Name); + } + #endregion #region Sorting and Merging @@ -163,6 +229,9 @@ namespace SabreTools.Library.DatItems Slot newItem = item as Slot; // Replace the fields + if (fields.Contains(Field.DatItem_Name)) + Name = newItem.Name; + if (fields.Contains(Field.DatItem_SlotOptions)) SlotOptions = newItem.SlotOptions; diff --git a/SabreTools.Library/DatItems/SoftwareList.cs b/SabreTools.Library/DatItems/SoftwareList.cs index d3045c07..91242fc2 100644 --- a/SabreTools.Library/DatItems/SoftwareList.cs +++ b/SabreTools.Library/DatItems/SoftwareList.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.IO; using System.Linq; using SabreTools.Library.Filtering; @@ -15,9 +16,21 @@ namespace SabreTools.Library.DatItems { #region Fields + /// + /// Name of the item + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Status of the softare list according to the machine + /// [JsonProperty("status", DefaultValueHandling = DefaultValueHandling.Ignore)] public SoftwareListStatus Status { get; set; } + /// + /// Filter to apply to the software list + /// [JsonProperty("filter", DefaultValueHandling = DefaultValueHandling.Ignore)] public string Filter { get; set; } @@ -25,6 +38,15 @@ namespace SabreTools.Library.DatItems #region Accessors + /// + /// Gets the name to use for a DatItem + /// + /// Name if available, null otherwise + public override string GetName() + { + return Name; + } + /// /// Set fields with given values /// @@ -35,6 +57,9 @@ namespace SabreTools.Library.DatItems base.SetFields(mappings); // Handle SoftwareList-specific fields + if (mappings.Keys.Contains(Field.DatItem_Name)) + Name = mappings[Field.DatItem_Name]; + if (mappings.Keys.Contains(Field.DatItem_SoftwareListStatus)) Status = mappings[Field.DatItem_Default].AsSoftwareListStatus(); @@ -117,6 +142,33 @@ namespace SabreTools.Library.DatItems #region Filtering + /// + /// Clean a DatItem according to the cleaner + /// + /// Cleaner to implement + public override void Clean(Cleaner cleaner) + { + // Clean common items first + base.Clean(cleaner); + + // If we're stripping unicode characters, strip item name + if (cleaner?.RemoveUnicode == true) + Name = Sanitizer.RemoveUnicodeCharacters(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 - Machine.Name.Length - (cleaner.Root?.Length ?? 0); + if (Name.Length > usableLength) + { + string ext = Path.GetExtension(Name); + Name = Name.Substring(0, usableLength - ext.Length); + Name += ext; + } + } + } + /// /// Check to see if a DatItem passes the filter /// @@ -128,6 +180,12 @@ namespace SabreTools.Library.DatItems if (!base.PassesFilter(filter)) return false; + // Filter on item name + if (filter.DatItem_Name.MatchesPositiveSet(Name) == false) + return false; + if (filter.DatItem_Name.MatchesNegativeSet(Name) == true) + return false; + // Filter on status if (filter.DatItem_SoftwareListStatus.MatchesPositive(SoftwareListStatus.NULL, Status) == false) return false; @@ -153,6 +211,9 @@ namespace SabreTools.Library.DatItems base.RemoveFields(fields); // Remove the fields + if (fields.Contains(Field.DatItem_Name)) + Name = null; + if (fields.Contains(Field.DatItem_SoftwareListStatus)) Status = SoftwareListStatus.NULL; @@ -160,6 +221,16 @@ namespace SabreTools.Library.DatItems Filter = null; } + /// + /// Set internal names to match One Rom Per Game (ORPG) logic + /// + public override void SetOneRomPerGame() + { + string[] splitname = Name.Split('.'); + Machine.Name += $"/{string.Join(".", splitname.Take(splitname.Length > 1 ? splitname.Length - 1 : 1))}"; + Name = Path.GetFileName(Name); + } + #endregion #region Sorting and Merging @@ -182,6 +253,9 @@ namespace SabreTools.Library.DatItems SoftwareList newItem = item as SoftwareList; // Replace the fields + if (fields.Contains(Field.DatItem_Name)) + Name = newItem.Name; + if (fields.Contains(Field.DatItem_SoftwareListStatus)) Status = newItem.Status;