From 6a26a0d2fa67cf9f9b8d79f4730eccdf75f0602f Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Sat, 19 Oct 2024 22:39:23 -0400 Subject: [PATCH] Make item dictionary implementations consistent --- SabreTools.Core/Tools/TextHelper.cs | 10 +- SabreTools.DatFiles/ItemDictionary.cs | 219 ++++++++++++------------ SabreTools.DatFiles/ItemDictionaryDB.cs | 174 ++++++++----------- 3 files changed, 182 insertions(+), 221 deletions(-) diff --git a/SabreTools.Core/Tools/TextHelper.cs b/SabreTools.Core/Tools/TextHelper.cs index 1cbedb72..4c190bdf 100644 --- a/SabreTools.Core/Tools/TextHelper.cs +++ b/SabreTools.Core/Tools/TextHelper.cs @@ -117,26 +117,26 @@ namespace SabreTools.Core.Tools /// /// Remove all chars that are considered path unsafe /// - public static string? RemovePathUnsafeCharacters(string? input) + public static string RemovePathUnsafeCharacters(string? input) { if (string.IsNullOrEmpty(input)) - return input; + return string.Empty; foreach (char invalid in Path.GetInvalidPathChars()) { input = input!.Replace(invalid.ToString(), string.Empty); } - return input; + return input!; } /// /// Remove all unicode-specific chars from a string /// - public static string? RemoveUnicodeCharacters(string? input) + public static string RemoveUnicodeCharacters(string? input) { if (string.IsNullOrEmpty(input)) - return input; + return string.Empty; return new string(input.Where(c => c <= 255).ToArray()); } diff --git a/SabreTools.DatFiles/ItemDictionary.cs b/SabreTools.DatFiles/ItemDictionary.cs index 285354c7..d3c26828 100644 --- a/SabreTools.DatFiles/ItemDictionary.cs +++ b/SabreTools.DatFiles/ItemDictionary.cs @@ -45,9 +45,9 @@ namespace SabreTools.DatFiles /// Internal dictionary for the class /// #if NET40_OR_GREATER || NETCOREAPP - private readonly ConcurrentDictionary?> items; + private readonly ConcurrentDictionary?> items = []; #else - private readonly Dictionary?> items; + private readonly Dictionary?> items = []; #endif /// @@ -109,11 +109,6 @@ namespace SabreTools.DatFiles { bucketedBy = ItemKey.NULL; mergedBy = DedupeType.None; -#if NET40_OR_GREATER || NETCOREAPP - items = new ConcurrentDictionary?>(); -#else - items = new Dictionary?>(); -#endif logger = new Logger(this); } @@ -318,23 +313,29 @@ namespace SabreTools.DatFiles List keys = [.. items.Keys]; foreach (string key in keys) { +#if NET40_OR_GREATER || NETCOREAPP + // If the key doesn't exist, skip + if (!items.TryGetValue(key, out var value)) + continue; + + // If the value is null, remove + else if (value == null) + items.TryRemove(key, out _); + + // If there are no non-blank items, remove + else if (!value!.Any(i => i != null && i is not Blank)) + items.TryRemove(key, out _); +#else // If the key doesn't exist, skip if (!items.ContainsKey(key)) continue; // If the value is null, remove else if (items[key] == null) -#if NET40_OR_GREATER || NETCOREAPP - items.TryRemove(key, out _); -#else items.Remove(key); -#endif // If there are no non-blank items, remove else if (!items[key]!.Any(i => i != null && i is not Blank)) -#if NET40_OR_GREATER || NETCOREAPP - items.TryRemove(key, out _); -#else items.Remove(key); #endif } @@ -389,8 +390,13 @@ namespace SabreTools.DatFiles // Explicit lock for some weird corner cases lock (key) { +#if NET40_OR_GREATER || NETCOREAPP + if (items.TryGetValue(key, out var list) && list != null) + return list.Contains(value); +#else if (items.ContainsKey(key) && items[key] != null) return items[key]!.Contains(value); +#endif } return false; @@ -864,11 +870,7 @@ namespace SabreTools.DatFiles try { // First we want to get a mapping for all games to description -#if NET40_OR_GREATER || NETCOREAPP - ConcurrentDictionary mapping = CreateMachineToDescriptionMapping(); -#else - Dictionary mapping = CreateMachineToDescriptionMapping(); -#endif + var mapping = CreateMachineToDescriptionMapping(); // Now we loop through every item and update accordingly UpdateMachineNamesFromDescriptions(mapping); @@ -1054,11 +1056,7 @@ namespace SabreTools.DatFiles /// /// Create machine to description mapping dictionary /// -#if NET40_OR_GREATER || NETCOREAPP - private ConcurrentDictionary CreateMachineToDescriptionMapping() -#else - private Dictionary CreateMachineToDescriptionMapping() -#endif + private IDictionary CreateMachineToDescriptionMapping() { #if NET40_OR_GREATER || NETCOREAPP ConcurrentDictionary mapping = new(); @@ -1105,7 +1103,7 @@ namespace SabreTools.DatFiles /// Set internal names to match One Rom Per Game (ORPG) logic /// /// DatItem to run logic on - private void SetOneRomPerGame(DatItem datItem) + private static void SetOneRomPerGame(DatItem datItem) { if (datItem.GetName() == null) return; @@ -1133,11 +1131,7 @@ namespace SabreTools.DatFiles /// /// Update machine names from descriptions according to mappings /// -#if NET40_OR_GREATER || NETCOREAPP - private void UpdateMachineNamesFromDescriptions(ConcurrentDictionary mapping) -#else - private void UpdateMachineNamesFromDescriptions(Dictionary mapping) -#endif + private void UpdateMachineNamesFromDescriptions(IDictionary mapping) { #if NET452_OR_GREATER || NETCOREAPP Parallel.ForEach(Keys, Globals.ParallelOptions, key => @@ -1200,33 +1194,28 @@ namespace SabreTools.DatFiles List games = [.. Keys.OrderBy(g => g)]; foreach (string game in games) { - var items = this[game]; - if (items == null) - continue; - // If the game has no items in it, we want to continue - if (items.Count == 0) + var items = this[game]; + if (items == null || items.Count == 0) continue; - // Determine if the game has a parent or not - string? parent = null; - if (!string.IsNullOrEmpty(items[0].GetFieldValue(DatItem.MachineKey)!.GetStringFieldValue(Models.Metadata.Machine.RomOfKey))) - parent = items[0].GetFieldValue(DatItem.MachineKey)!.GetStringFieldValue(Models.Metadata.Machine.RomOfKey); + // Get the machine + var machine = items[0].GetFieldValue(DatItem.MachineKey); + if (machine == null) + continue; - // If the parent doesnt exist, we want to continue - if (string.IsNullOrEmpty(parent)) + // Get the bios parent + string? romOf = machine.GetStringFieldValue(Models.Metadata.Machine.RomOfKey); + if (string.IsNullOrEmpty(romOf)) continue; // If the parent doesn't have any items, we want to continue - if (this[parent!]!.Count == 0) + var parentItems = this[romOf]; + if (parentItems == null || parentItems.Count == 0) continue; // If the parent exists and has items, we copy the items from the parent to the current game DatItem copyFrom = items[0]; - var parentItems = this[parent!]; - if (parentItems == null) - continue; - foreach (DatItem item in parentItems) { DatItem datItem = (DatItem)item.Clone(); @@ -1397,27 +1386,28 @@ namespace SabreTools.DatFiles if (items == null || items.Count == 0) continue; - // Determine if the game has a parent or not - string? parent = null; - if (!string.IsNullOrEmpty(items[0].GetFieldValue(DatItem.MachineKey)!.GetStringFieldValue(Models.Metadata.Machine.CloneOfKey))) - parent = items[0].GetFieldValue(DatItem.MachineKey)!.GetStringFieldValue(Models.Metadata.Machine.CloneOfKey); + // Get the machine + var machine = items[0].GetFieldValue(DatItem.MachineKey); + if (machine == null) + continue; - // If the parent doesnt exist, we want to continue - if (string.IsNullOrEmpty(parent)) + // Get the clone parent + string? cloneOf = machine.GetStringFieldValue(Models.Metadata.Machine.CloneOfKey); + if (string.IsNullOrEmpty(cloneOf)) continue; // If the parent doesn't have any items, we want to continue - if (this[parent!]!.Count == 0) + var parentItems = this[cloneOf]; + if (parentItems == null || parentItems.Count == 0) continue; // If the parent exists and has items, we copy the items from the parent to the current game DatItem copyFrom = items[0]; - var parentItems = this[parent!]; - foreach (DatItem item in parentItems!) + foreach (DatItem item in parentItems) { DatItem datItem = (DatItem)item.Clone(); datItem.CopyMachineInformation(copyFrom); - if (!items.Any(i => i.GetName()?.ToLowerInvariant() == datItem.GetName()?.ToLowerInvariant()) + if (!items.Any(i => string.Equals(i.GetName(), datItem.GetName(), StringComparison.OrdinalIgnoreCase)) && !items.Contains(datItem)) { Add(game, datItem); @@ -1426,7 +1416,7 @@ namespace SabreTools.DatFiles // Now we want to get the parent romof tag and put it in each of the items items = this[game]; - string? romof = this[parent!]![0].GetFieldValue(DatItem.MachineKey)!.GetStringFieldValue(Models.Metadata.Machine.RomOfKey); + string? romof = this[cloneOf]![0].GetFieldValue(DatItem.MachineKey)!.GetStringFieldValue(Models.Metadata.Machine.RomOfKey); foreach (DatItem item in items!) { item.GetFieldValue(DatItem.MachineKey)!.SetFieldValue(Models.Metadata.Machine.RomOfKey, romof); @@ -1449,26 +1439,30 @@ namespace SabreTools.DatFiles if (items == null || items.Count == 0) continue; - // Determine if the game has a parent or not - string? parent = null; - if (!string.IsNullOrEmpty(items[0].GetFieldValue(DatItem.MachineKey)!.GetStringFieldValue(Models.Metadata.Machine.CloneOfKey))) - parent = items[0].GetFieldValue(DatItem.MachineKey)!.GetStringFieldValue(Models.Metadata.Machine.CloneOfKey); - - // If there is no parent, then we continue - if (string.IsNullOrEmpty(parent)) + // Get the machine + var machine = items[0].GetFieldValue(DatItem.MachineKey); + if (machine == null) continue; + // Get the clone parent + string? cloneOf = machine.GetStringFieldValue(Models.Metadata.Machine.CloneOfKey); + if (string.IsNullOrEmpty(cloneOf)) + continue; + + // Get the parent items + var parentItems = this[cloneOf]; + // Otherwise, move the items from the current game to a subfolder of the parent game DatItem copyFrom; - if (this[parent!]!.Count == 0) + if (parentItems == null || parentItems.Count == 0) { copyFrom = new Rom(); - copyFrom.GetFieldValue(DatItem.MachineKey)!.SetFieldValue(Models.Metadata.Machine.NameKey, parent); - copyFrom.GetFieldValue(DatItem.MachineKey)!.SetFieldValue(Models.Metadata.Machine.DescriptionKey, parent); + copyFrom.GetFieldValue(DatItem.MachineKey)!.SetFieldValue(Models.Metadata.Machine.NameKey, cloneOf); + copyFrom.GetFieldValue(DatItem.MachineKey)!.SetFieldValue(Models.Metadata.Machine.DescriptionKey, cloneOf); } else { - copyFrom = this[parent!]![0]; + copyFrom = parentItems[0]; } items = this[game]; @@ -1480,7 +1474,7 @@ namespace SabreTools.DatFiles string? mergeTag = disk.GetStringFieldValue(Models.Metadata.Disk.MergeKey); // If the merge tag exists and the parent already contains it, skip - if (mergeTag != null && this[parent!]! + if (mergeTag != null && this[cloneOf]! .Where(i => i is Disk) .Select(i => (i as Disk)!.GetName()).Contains(mergeTag)) { @@ -1488,19 +1482,19 @@ namespace SabreTools.DatFiles } // If the merge tag exists but the parent doesn't contain it, add to parent - else if (mergeTag != null && !this[parent!]! + else if (mergeTag != null && !this[cloneOf]! .Where(i => i is Disk) .Select(i => (i as Disk)!.GetName()).Contains(mergeTag)) { disk.CopyMachineInformation(copyFrom); - Add(parent!, disk); + Add(cloneOf, disk); } // If there is no merge tag, add to parent else if (mergeTag == null) { disk.CopyMachineInformation(copyFrom); - Add(parent!, disk); + Add(cloneOf, disk); } } @@ -1508,7 +1502,7 @@ namespace SabreTools.DatFiles else if (item is Rom rom) { // If the merge tag exists and the parent already contains it, skip - if (rom.GetStringFieldValue(Models.Metadata.Rom.MergeKey) != null && this[parent!]! + if (rom.GetStringFieldValue(Models.Metadata.Rom.MergeKey) != null && this[cloneOf]! .Where(i => i is Rom).Select(i => (i as Rom)!.GetName()) .Contains(rom.GetStringFieldValue(Models.Metadata.Rom.MergeKey))) { @@ -1516,7 +1510,7 @@ namespace SabreTools.DatFiles } // If the merge tag exists but the parent doesn't contain it, add to subfolder of parent - else if (rom.GetStringFieldValue(Models.Metadata.Rom.MergeKey) != null && !this[parent!]! + else if (rom.GetStringFieldValue(Models.Metadata.Rom.MergeKey) != null && !this[cloneOf]! .Where(i => i is Rom).Select(i => (i as Rom)!.GetName()) .Contains(rom.GetStringFieldValue(Models.Metadata.Rom.MergeKey))) { @@ -1524,28 +1518,28 @@ namespace SabreTools.DatFiles rom.SetName($"{rom.GetFieldValue(DatItem.MachineKey)!.GetStringFieldValue(Models.Metadata.Machine.NameKey)}\\{rom.GetName()}"); rom.CopyMachineInformation(copyFrom); - Add(parent!, rom); + Add(cloneOf, rom); } // If the parent doesn't already contain this item, add to subfolder of parent - else if (!this[parent!]!.Contains(item) || skipDedup) + else if (!this[cloneOf]!.Contains(item) || skipDedup) { if (subfolder) rom.SetName($"{item.GetFieldValue(DatItem.MachineKey)!.GetStringFieldValue(Models.Metadata.Machine.NameKey)}\\{rom.GetName()}"); rom.CopyMachineInformation(copyFrom); - Add(parent!, rom); + Add(cloneOf, rom); } } // All other that would be missing to subfolder of parent - else if (!this[parent!]!.Contains(item)) + else if (!this[cloneOf]!.Contains(item)) { if (subfolder) item.SetName($"{item.GetFieldValue(DatItem.MachineKey)!.GetStringFieldValue(Models.Metadata.Machine.NameKey)}\\{item.GetName()}"); item.CopyMachineInformation(copyFrom); - Add(parent!, item); + Add(cloneOf, item); } } @@ -1562,13 +1556,19 @@ namespace SabreTools.DatFiles List games = [.. Keys.OrderBy(g => g)]; foreach (string game in games) { + // If the game has no items in it, we want to continue var items = this[game]; - if (items == null) + if (items == null || items.Count == 0) continue; - if (items.Count > 0 - && ((items[0].GetFieldValue(DatItem.MachineKey)!.GetBoolFieldValue(Models.Metadata.Machine.IsBiosKey) == true) - || (items[0].GetFieldValue(DatItem.MachineKey)!.GetBoolFieldValue(Models.Metadata.Machine.IsDeviceKey) == true))) + // Get the machine + var machine = items[0].GetFieldValue(DatItem.MachineKey); + if (machine == null) + continue; + + // Remove flagged items + if ((machine.GetBoolFieldValue(Models.Metadata.Machine.IsBiosKey) == true) + || (machine.GetBoolFieldValue(Models.Metadata.Machine.IsDeviceKey) == true)) { Remove(game); } @@ -1590,28 +1590,26 @@ namespace SabreTools.DatFiles if (items == null || items.Count == 0) continue; - // If the game (is/is not) a bios, we want to continue - if (bios ^ (items[0].GetFieldValue(DatItem.MachineKey)!.GetBoolFieldValue(Models.Metadata.Machine.IsBiosKey) == true)) + // Get the machine + var machine = items[0].GetFieldValue(DatItem.MachineKey); + if (machine == null) continue; - // Determine if the game has a parent or not - string? parent = null; - if (!string.IsNullOrEmpty(items[0].GetFieldValue(DatItem.MachineKey)!.GetStringFieldValue(Models.Metadata.Machine.RomOfKey))) - parent = items[0].GetFieldValue(DatItem.MachineKey)!.GetStringFieldValue(Models.Metadata.Machine.RomOfKey); + // If the game (is/is not) a bios, we want to continue + if (bios ^ (machine.GetBoolFieldValue(Models.Metadata.Machine.IsBiosKey) == true)) + continue; - // If the parent doesnt exist, we want to continue - if (string.IsNullOrEmpty(parent)) + // Get the bios parent + string? romOf = machine.GetStringFieldValue(Models.Metadata.Machine.RomOfKey); + if (string.IsNullOrEmpty(romOf)) continue; // If the parent doesn't have any items, we want to continue - if (this[parent!]!.Count == 0) + var parentItems = this[romOf]; + if (parentItems == null || parentItems.Count == 0) continue; // If the parent exists and has items, we remove the items that are in the parent from the current game - var parentItems = this[parent!]; - if (parentItems == null) - continue; - foreach (DatItem item in parentItems) { DatItem datItem = (DatItem)item.Clone(); @@ -1631,29 +1629,27 @@ namespace SabreTools.DatFiles List games = [.. Keys.OrderBy(g => g)]; foreach (string game in games) { - var items = this[game]; - if (items == null) - continue; - // If the game has no items in it, we want to continue - if (items.Count == 0) + var items = this[game]; + if (items == null || items.Count == 0) continue; - // Determine if the game has a parent or not - string? parent = null; - if (!string.IsNullOrEmpty(items[0].GetFieldValue(DatItem.MachineKey)!.GetStringFieldValue(Models.Metadata.Machine.CloneOfKey))) - parent = items[0].GetFieldValue(DatItem.MachineKey)!.GetStringFieldValue(Models.Metadata.Machine.CloneOfKey); + // Get the machine + var machine = items[0].GetFieldValue(DatItem.MachineKey); + if (machine == null) + continue; - // If the parent doesnt exist, we want to continue - if (string.IsNullOrEmpty(parent)) + // Get the clone parent + string? cloneOf = machine.GetStringFieldValue(Models.Metadata.Machine.CloneOfKey); + if (string.IsNullOrEmpty(cloneOf)) continue; // If the parent doesn't have any items, we want to continue - if (this[parent!] == null || this[parent!]!.Count == 0) + var parentItems = this[cloneOf]; + if (parentItems == null || parentItems.Count == 0) continue; // If the parent exists and has items, we remove the parent items from the current game - var parentItems = this[parent!]; foreach (DatItem item in parentItems!) { DatItem datItem = (DatItem)item.Clone(); @@ -1665,7 +1661,7 @@ namespace SabreTools.DatFiles // Now we want to get the parent romof tag and put it in each of the remaining items items = this[game]; - string? romof = this[parent!]![0].GetFieldValue(DatItem.MachineKey)!.GetStringFieldValue(Models.Metadata.Machine.RomOfKey); + string? romof = this[cloneOf!]![0].GetFieldValue(DatItem.MachineKey)!.GetStringFieldValue(Models.Metadata.Machine.RomOfKey); foreach (DatItem item in items!) { item.GetFieldValue(DatItem.MachineKey)!.SetFieldValue(Models.Metadata.Machine.RomOfKey, romof); @@ -1681,8 +1677,9 @@ namespace SabreTools.DatFiles List games = [.. Keys.OrderBy(g => g)]; foreach (string game in games) { + // If the game has no items in it, we want to continue var items = this[game]; - if (items == null) + if (items == null || items.Count == 0) continue; foreach (DatItem item in items) diff --git a/SabreTools.DatFiles/ItemDictionaryDB.cs b/SabreTools.DatFiles/ItemDictionaryDB.cs index 9403c222..03930f79 100644 --- a/SabreTools.DatFiles/ItemDictionaryDB.cs +++ b/SabreTools.DatFiles/ItemDictionaryDB.cs @@ -51,7 +51,7 @@ namespace SabreTools.DatFiles /// [JsonIgnore, XmlIgnore] #if NET40_OR_GREATER || NETCOREAPP - private readonly ConcurrentDictionary _items = new ConcurrentDictionary(); + private readonly ConcurrentDictionary _items = []; #else private readonly Dictionary _items = []; #endif @@ -67,7 +67,7 @@ namespace SabreTools.DatFiles /// [JsonIgnore, XmlIgnore] #if NET40_OR_GREATER || NETCOREAPP - private readonly ConcurrentDictionary _machines = new ConcurrentDictionary(); + private readonly ConcurrentDictionary _machines = []; #else private readonly Dictionary _machines = []; #endif @@ -83,7 +83,7 @@ namespace SabreTools.DatFiles /// [JsonIgnore, XmlIgnore] #if NET40_OR_GREATER || NETCOREAPP - private readonly ConcurrentDictionary _sources = new ConcurrentDictionary(); + private readonly ConcurrentDictionary _sources = []; #else private readonly Dictionary _sources = []; #endif @@ -99,7 +99,7 @@ namespace SabreTools.DatFiles /// [JsonIgnore, XmlIgnore] #if NET40_OR_GREATER || NETCOREAPP - private readonly ConcurrentDictionary _itemToMachineMapping = new ConcurrentDictionary(); + private readonly ConcurrentDictionary _itemToMachineMapping = []; #else private readonly Dictionary _itemToMachineMapping = []; #endif @@ -109,7 +109,7 @@ namespace SabreTools.DatFiles /// [JsonIgnore, XmlIgnore] #if NET40_OR_GREATER || NETCOREAPP - private readonly ConcurrentDictionary _itemToSourceMapping = new ConcurrentDictionary(); + private readonly ConcurrentDictionary _itemToSourceMapping = []; #else private readonly Dictionary _itemToSourceMapping = []; #endif @@ -119,7 +119,7 @@ namespace SabreTools.DatFiles /// [JsonIgnore, XmlIgnore] #if NET40_OR_GREATER || NETCOREAPP - private readonly ConcurrentDictionary> _buckets = new ConcurrentDictionary>(); + private readonly ConcurrentDictionary> _buckets = []; #else private readonly Dictionary> _buckets = []; #endif @@ -342,17 +342,20 @@ namespace SabreTools.DatFiles /// /// Get all item to machine mappings /// - public (long, long)[] GetItemMachineMappings() => [.. _itemToMachineMapping.Select(kvp => (kvp.Key, kvp.Value))]; + public (long, long)[] GetItemMachineMappings() + => [.. _itemToMachineMapping.Select(kvp => (kvp.Key, kvp.Value))]; /// /// Get all item to source mappings /// - public (long, long)[] GetItemSourceMappings() => [.. _itemToSourceMapping.Select(kvp => (kvp.Key, kvp.Value))]; + public (long, long)[] GetItemSourceMappings() + => [.. _itemToSourceMapping.Select(kvp => (kvp.Key, kvp.Value))]; /// /// Get all items and their indicies /// - public (long, DatItem)[] GetItems() => [.. _items.Select(kvp => (kvp.Key, kvp.Value))]; + public (long, DatItem)[] GetItems() + => [.. _items.Select(kvp => (kvp.Key, kvp.Value))]; /// /// Get the indices and items associated with a bucket name @@ -454,7 +457,8 @@ namespace SabreTools.DatFiles /// /// Get all machines and their indicies /// - public (long, Machine)[] GetMachines() => [.. _machines.Select(kvp => (kvp.Key, kvp.Value))]; + public (long, Machine)[] GetMachines() + => [.. _machines.Select(kvp => (kvp.Key, kvp.Value))]; /// /// Get a source based on the index @@ -485,7 +489,8 @@ namespace SabreTools.DatFiles /// /// Get all sources and their indicies /// - public (long, Source)[] GetSources() => [.. _sources.Select(kvp => (kvp.Key, kvp.Value))]; + public (long, Source)[] GetSources() + => [.. _sources.Select(kvp => (kvp.Key, kvp.Value))]; /// /// Remove an item, returning if it could be removed @@ -720,7 +725,7 @@ namespace SabreTools.DatFiles return false; // Try to find duplicates - return roms.Any(r => datItem.Equals(r.Item2)) == true; + return roms.Any(r => datItem.Equals(r.Item2)); } /// @@ -1148,14 +1153,14 @@ namespace SabreTools.DatFiles return xType.AsEnumValue() - yType.AsEnumValue(); // If directory names don't match - string? xDirectoryName = Path.GetDirectoryName(TextHelper.RemovePathUnsafeCharacters(x.Item2.GetName() ?? string.Empty)); - string? yDirectoryName = Path.GetDirectoryName(TextHelper.RemovePathUnsafeCharacters(y.Item2.GetName() ?? string.Empty)); + string? xDirectoryName = Path.GetDirectoryName(TextHelper.RemovePathUnsafeCharacters(x.Item2.GetName())); + string? yDirectoryName = Path.GetDirectoryName(TextHelper.RemovePathUnsafeCharacters(y.Item2.GetName())); if (xDirectoryName != yDirectoryName) return nc.Compare(xDirectoryName, yDirectoryName); // If item names don't match - string? xName = Path.GetFileName(TextHelper.RemovePathUnsafeCharacters(x.Item2.GetName() ?? string.Empty)); - string? yName = Path.GetFileName(TextHelper.RemovePathUnsafeCharacters(y.Item2.GetName() ?? string.Empty)); + string? xName = Path.GetFileName(TextHelper.RemovePathUnsafeCharacters(x.Item2.GetName())); + string? yName = Path.GetFileName(TextHelper.RemovePathUnsafeCharacters(y.Item2.GetName())); if (xName != yName) return nc.Compare(xName, yName); @@ -1243,11 +1248,7 @@ namespace SabreTools.DatFiles try { // First we want to get a mapping for all games to description -#if NET40_OR_GREATER || NETCOREAPP - ConcurrentDictionary mapping = CreateMachineToDescriptionMapping(); -#else - Dictionary mapping = CreateMachineToDescriptionMapping(); -#endif + var mapping = CreateMachineToDescriptionMapping(); // Now we loop through every item and update accordingly UpdateMachineNamesFromDescriptions(mapping); @@ -1443,11 +1444,7 @@ namespace SabreTools.DatFiles /// /// Create machine to description mapping dictionary /// -#if NET40_OR_GREATER || NETCOREAPP - private ConcurrentDictionary CreateMachineToDescriptionMapping() -#else - private Dictionary CreateMachineToDescriptionMapping() -#endif + private IDictionary CreateMachineToDescriptionMapping() { #if NET40_OR_GREATER || NETCOREAPP ConcurrentDictionary mapping = new(); @@ -1555,11 +1552,7 @@ namespace SabreTools.DatFiles /// /// Update machine names from descriptions according to mappings /// -#if NET40_OR_GREATER || NETCOREAPP - private void UpdateMachineNamesFromDescriptions(ConcurrentDictionary mapping) -#else - private void UpdateMachineNamesFromDescriptions(Dictionary mapping) -#endif + private void UpdateMachineNamesFromDescriptions(IDictionary mapping) { #if NET452_OR_GREATER || NETCOREAPP Parallel.ForEach(SortedKeys, Globals.ParallelOptions, key => @@ -1626,9 +1619,8 @@ namespace SabreTools.DatFiles List games = [.. SortedKeys]; foreach (string game in games) { + // Get the items for this game var items = GetItemsForBucket(game); - - // If the game has no items in it, we want to continue if (items == null || items.Length == 0) continue; @@ -1640,21 +1632,13 @@ namespace SabreTools.DatFiles if (machine.Item2 == null) continue; - // Determine if the game has a parent or not - (long, string?) parent = (-1, null); - if (!string.IsNullOrEmpty(machine.Item2.GetStringFieldValue(Models.Metadata.Machine.RomOfKey))) - { - string? romOf = machine.Item2.GetStringFieldValue(Models.Metadata.Machine.RomOfKey); - var romOfMachine = GetMachine(romOf); - parent = (romOfMachine.Item1, romOf); - } - - // If the parent doesnt exist, we want to continue - if (string.IsNullOrEmpty(parent.Item2)) + // Get the bios parent + string? romOf = machine.Item2.GetStringFieldValue(Models.Metadata.Machine.RomOfKey); + if (string.IsNullOrEmpty(romOf)) continue; // If the parent doesn't have any items, we want to continue - var parentItems = GetItemsForBucket(parent.Item2!); + var parentItems = GetItemsForBucket(romOf); if (parentItems == null || parentItems.Length == 0) continue; @@ -1679,10 +1663,8 @@ namespace SabreTools.DatFiles List games = [.. SortedKeys]; foreach (string game in games) { - // Get the items for this game + // If the game has no items in it, we want to continue var items = GetItemsForBucket(game); - - // If the machine doesn't have items, we continue if (items == null || items.Length == 0) continue; @@ -1857,21 +1839,13 @@ namespace SabreTools.DatFiles if (machine.Item2 == null) continue; - // Determine if the game has a parent or not - (long, string?) parent = (-1, null); - if (!string.IsNullOrEmpty(machine.Item2.GetStringFieldValue(Models.Metadata.Machine.CloneOfKey))) - { - string? cloneOf = machine.Item2.GetStringFieldValue(Models.Metadata.Machine.CloneOfKey); - var cloneOfMachine = GetMachine(cloneOf); - parent = (cloneOfMachine.Item1, cloneOf); - } - - // If there is no parent, then we continue - if (string.IsNullOrEmpty(parent.Item2)) + // Get the clone parent + string? cloneOf = machine.Item2.GetStringFieldValue(Models.Metadata.Machine.CloneOfKey); + if (string.IsNullOrEmpty(cloneOf)) continue; // If the parent doesn't have any items, we want to continue - var parentItems = GetItemsForBucket(parent.Item2!); + var parentItems = GetItemsForBucket(cloneOf); if (parentItems == null || parentItems.Length == 0) continue; @@ -1887,7 +1861,7 @@ namespace SabreTools.DatFiles } // Get the parent machine - var parentMachine = GetMachineForItem(GetItemsForBucket(parent.Item2!)![0].Item1); + var parentMachine = GetMachineForItem(GetItemsForBucket(cloneOf)![0].Item1); if (parentMachine.Item2 == null) continue; @@ -1925,24 +1899,21 @@ namespace SabreTools.DatFiles if (machine.Item2 == null) continue; - // Determine if the game has a parent or not - (long, string?) parent = (-1, null); - if (!string.IsNullOrEmpty(machine.Item2.GetStringFieldValue(Models.Metadata.Machine.CloneOfKey))) - { - string? cloneOf = machine.Item2.GetStringFieldValue(Models.Metadata.Machine.CloneOfKey); - var cloneOfMachine = GetMachine(cloneOf); - parent = (cloneOfMachine.Item1, cloneOf); - } + // Get the clone parent + string? cloneOf = machine.Item2.GetStringFieldValue(Models.Metadata.Machine.CloneOfKey); + if (string.IsNullOrEmpty(cloneOf)) + continue; - // If there is no parent, then we continue - if (string.IsNullOrEmpty(parent.Item2)) + // Get the clone parent machine + var cloneOfMachine = GetMachine(cloneOf); + if (cloneOfMachine.Item2 == null) continue; items = GetItemsForBucket(game); foreach ((long, DatItem) item in items!) { // Get the parent items and current machine name - var parentItems = GetItemsForBucket(parent.Item2!); + var parentItems = GetItemsForBucket(cloneOf); string? machineName = GetMachineForItem(item.Item1).Item2?.GetStringFieldValue(Models.Metadata.Machine.NameKey); // Special disk handling @@ -1965,15 +1936,15 @@ namespace SabreTools.DatFiles .Select(i => (i.Item2 as Disk)!.GetName()) .Contains(mergeTag)) { - _itemToMachineMapping[item.Item1] = parent.Item1; - _buckets[parent.Item2!].Add(disk); + _itemToMachineMapping[item.Item1] = cloneOfMachine.Item1; + _buckets[cloneOf].Add(disk); } // If there is no merge tag, add to parent else if (mergeTag == null) { - _itemToMachineMapping[item.Item1] = parent.Item1; - _buckets[parent.Item2!].Add(disk); + _itemToMachineMapping[item.Item1] = cloneOfMachine.Item1; + _buckets[cloneOf].Add(disk); } } @@ -1998,8 +1969,8 @@ namespace SabreTools.DatFiles if (subfolder) rom.SetName($"{machineName}\\{rom.GetName()}"); - _itemToMachineMapping[item.Item1] = parent.Item1; - _buckets[parent.Item2!].Add(rom); + _itemToMachineMapping[item.Item1] = cloneOfMachine.Item1; + _buckets[cloneOf].Add(rom); } // If the parent doesn't already contain this item, add to subfolder of parent @@ -2008,8 +1979,8 @@ namespace SabreTools.DatFiles if (subfolder) rom.SetName($"{machineName}\\{rom.GetName()}"); - _itemToMachineMapping[item.Item1] = parent.Item1; - _buckets[parent.Item2!].Add(rom); + _itemToMachineMapping[item.Item1] = cloneOfMachine.Item1; + _buckets[cloneOf].Add(rom); } } @@ -2019,8 +1990,8 @@ namespace SabreTools.DatFiles if (subfolder) item.Item2.SetName($"{machineName}\\{item.Item2.GetName()}"); - _itemToMachineMapping[item.Item1] = parent.Item1; - _buckets[parent.Item2!].Add(item); + _itemToMachineMapping[item.Item1] = cloneOfMachine.Item1; + _buckets[cloneOf].Add(item); } } @@ -2041,14 +2012,17 @@ namespace SabreTools.DatFiles List games = [.. SortedKeys]; foreach (string game in games) { + // If the game has no items in it, we want to continue var items = GetItemsForBucket(game); if (items == null || items.Length == 0) continue; + // Get the machine var machine = GetMachineForItem(items[0].Item1); if (machine.Item2 == null) continue; + // Remove flagged items if ((machine.Item2.GetBoolFieldValue(Models.Metadata.Machine.IsBiosKey) == true) || (machine.Item2.GetBoolFieldValue(Models.Metadata.Machine.IsDeviceKey) == true)) { @@ -2084,17 +2058,13 @@ namespace SabreTools.DatFiles if (bios ^ (machine.Item2.GetBoolFieldValue(Models.Metadata.Machine.IsBiosKey) == true)) continue; - // Determine if the game has a parent or not - string? parent = null; - if (!string.IsNullOrEmpty(machine.Item2.GetStringFieldValue(Models.Metadata.Machine.RomOfKey))) - parent = machine.Item2.GetStringFieldValue(Models.Metadata.Machine.RomOfKey); - - // If the parent doesnt exist, we want to continue - if (string.IsNullOrEmpty(parent)) + // Get the bios parent + string? romOf = machine.Item2.GetStringFieldValue(Models.Metadata.Machine.RomOfKey); + if (string.IsNullOrEmpty(romOf)) continue; // If the parent doesn't have any items, we want to continue - var parentItems = GetItemsForBucket(parent!); + var parentItems = GetItemsForBucket(romOf); if (parentItems == null || parentItems.Length == 0) continue; @@ -2118,12 +2088,9 @@ namespace SabreTools.DatFiles List games = [.. SortedKeys]; foreach (string game in games) { - var items = GetItemsForBucket(game); - if (items == null) - continue; - // If the game has no items in it, we want to continue - if (items.Length == 0) + var items = GetItemsForBucket(game); + if (items == null || items.Length == 0) continue; // Get the machine for the first item @@ -2131,17 +2098,13 @@ namespace SabreTools.DatFiles if (machine.Item2 == null) continue; - // Determine if the game has a parent or not - string? parent = null; - if (!string.IsNullOrEmpty(machine.Item2.GetStringFieldValue(Models.Metadata.Machine.CloneOfKey))) - parent = machine.Item2.GetStringFieldValue(Models.Metadata.Machine.CloneOfKey); - - // If the parent doesnt exist, we want to continue - if (string.IsNullOrEmpty(parent)) + // Get the clone parent + string? cloneOf = machine.Item2.GetStringFieldValue(Models.Metadata.Machine.CloneOfKey); + if (string.IsNullOrEmpty(cloneOf)) continue; // If the parent doesn't have any items, we want to continue - var parentItems = GetItemsForBucket(parent!); + var parentItems = GetItemsForBucket(cloneOf); if (parentItems == null || parentItems.Length == 0) continue; @@ -2157,7 +2120,7 @@ namespace SabreTools.DatFiles // Now we want to get the parent romof tag and put it in each of the remaining items items = GetItemsForBucket(game); - machine = GetMachineForItem(GetItemsForBucket(parent!)![0].Item1); + machine = GetMachineForItem(GetItemsForBucket(cloneOf)![0].Item1); if (machine.Item2 == null) continue; @@ -2181,8 +2144,9 @@ namespace SabreTools.DatFiles List games = [.. SortedKeys]; foreach (string game in games) { + // If the game has no items in it, we want to continue var items = GetItemsForBucket(game); - if (items == null) + if (items == null || items.Length == 0) continue; foreach ((long, DatItem) item in items)