Support ancient .NET in Filtering

This commit is contained in:
Matt Nadareski
2024-02-28 23:09:31 -05:00
parent 2145245c31
commit c2973beb7f
8 changed files with 83 additions and 55 deletions

View File

@@ -1,5 +1,7 @@
using System; using System;
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent; using System.Collections.Concurrent;
#endif
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@@ -215,7 +217,7 @@ namespace SabreTools.Filtering
if (datItem.GetName()!.Length > usableLength) if (datItem.GetName()!.Length > usableLength)
{ {
string ext = Path.GetExtension(datItem.GetName()!); string ext = Path.GetExtension(datItem.GetName()!);
datItem.SetName(datItem.GetName()![..(usableLength - ext.Length)] + ext); datItem.SetName(datItem.GetName()!.Substring(0, usableLength - ext.Length) + ext);
} }
} }
} }
@@ -230,8 +232,13 @@ namespace SabreTools.Filtering
try try
{ {
// First we want to get a mapping for all games to description // First we want to get a mapping for all games to description
#if NET40_OR_GREATER || NETCOREAPP
ConcurrentDictionary<string, string> concurrentDictionary = new(); ConcurrentDictionary<string, string> concurrentDictionary = new();
ConcurrentDictionary<string, string> mapping = concurrentDictionary; ConcurrentDictionary<string, string> mapping = concurrentDictionary;
#else
Dictionary<string, string> concurrentDictionary = [];
Dictionary<string, string> mapping = concurrentDictionary;
#endif
#if NET452_OR_GREATER || NETCOREAPP #if NET452_OR_GREATER || NETCOREAPP
Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key => Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key =>
#elif NET40_OR_GREATER #elif NET40_OR_GREATER
@@ -247,7 +254,11 @@ namespace SabreTools.Filtering
foreach (DatItem item in items) foreach (DatItem item in items)
{ {
// If the key mapping doesn't exist, add it // If the key mapping doesn't exist, add it
#if NET40_OR_GREATER || NETCOREAPP
mapping.TryAdd(item.Machine.Name!, item.Machine.Description!.Replace('/', '_').Replace("\"", "''").Replace(":", " -")); mapping.TryAdd(item.Machine.Name!, item.Machine.Description!.Replace('/', '_').Replace("\"", "''").Replace(":", " -"));
#else
mapping[item.Machine.Name!] = item.Machine.Description!.Replace('/', '_').Replace("\"", "''").Replace(":", " -");
#endif
} }
#if NET40_OR_GREATER || NETCOREAPP #if NET40_OR_GREATER || NETCOREAPP
}); });
@@ -272,20 +283,20 @@ namespace SabreTools.Filtering
foreach (DatItem item in items) foreach (DatItem item in items)
{ {
// Update machine name // Update machine name
if (!string.IsNullOrWhiteSpace(item.Machine.Name) && mapping.ContainsKey(item.Machine.Name)) if (!string.IsNullOrEmpty(item.Machine.Name) && mapping.ContainsKey(item.Machine.Name!))
item.Machine.Name = mapping[item.Machine.Name]; item.Machine.Name = mapping[item.Machine.Name!];
// Update cloneof // Update cloneof
if (!string.IsNullOrWhiteSpace(item.Machine.CloneOf) && mapping.ContainsKey(item.Machine.CloneOf)) if (!string.IsNullOrEmpty(item.Machine.CloneOf) && mapping.ContainsKey(item.Machine.CloneOf!))
item.Machine.CloneOf = mapping[item.Machine.CloneOf]; item.Machine.CloneOf = mapping[item.Machine.CloneOf!];
// Update romof // Update romof
if (!string.IsNullOrWhiteSpace(item.Machine.RomOf) && mapping.ContainsKey(item.Machine.RomOf)) if (!string.IsNullOrEmpty(item.Machine.RomOf) && mapping.ContainsKey(item.Machine.RomOf!))
item.Machine.RomOf = mapping[item.Machine.RomOf]; item.Machine.RomOf = mapping[item.Machine.RomOf!];
// Update sampleof // Update sampleof
if (!string.IsNullOrWhiteSpace(item.Machine.SampleOf) && mapping.ContainsKey(item.Machine.SampleOf)) if (!string.IsNullOrEmpty(item.Machine.SampleOf) && mapping.ContainsKey(item.Machine.SampleOf!))
item.Machine.SampleOf = mapping[item.Machine.SampleOf]; item.Machine.SampleOf = mapping[item.Machine.SampleOf!];
// Add the new item to the output list // Add the new item to the output list
newItems.Add(item); newItems.Add(item);
@@ -337,7 +348,7 @@ namespace SabreTools.Filtering
// Match on CloneOf first // Match on CloneOf first
if (!string.IsNullOrEmpty(item.Machine.CloneOf)) if (!string.IsNullOrEmpty(item.Machine.CloneOf))
{ {
if (!parents.ContainsKey(item.Machine.CloneOf.ToLowerInvariant())) if (!parents.ContainsKey(item.Machine.CloneOf!.ToLowerInvariant()))
parents.Add(item.Machine.CloneOf.ToLowerInvariant(), new List<string>()); parents.Add(item.Machine.CloneOf.ToLowerInvariant(), new List<string>());
parents[item.Machine.CloneOf.ToLowerInvariant()].Add(item.Machine.Name!.ToLowerInvariant()); parents[item.Machine.CloneOf.ToLowerInvariant()].Add(item.Machine.Name!.ToLowerInvariant());
@@ -346,7 +357,7 @@ namespace SabreTools.Filtering
// Then by RomOf // Then by RomOf
else if (!string.IsNullOrEmpty(item.Machine.RomOf)) else if (!string.IsNullOrEmpty(item.Machine.RomOf))
{ {
if (!parents.ContainsKey(item.Machine.RomOf.ToLowerInvariant())) if (!parents.ContainsKey(item.Machine.RomOf!.ToLowerInvariant()))
parents.Add(item.Machine.RomOf.ToLowerInvariant(), new List<string>()); parents.Add(item.Machine.RomOf.ToLowerInvariant(), new List<string>());
parents[item.Machine.RomOf.ToLowerInvariant()].Add(item.Machine.Name!.ToLowerInvariant()); parents[item.Machine.RomOf.ToLowerInvariant()].Add(item.Machine.Name!.ToLowerInvariant());
@@ -356,7 +367,7 @@ namespace SabreTools.Filtering
else else
{ {
if (!parents.ContainsKey(item.Machine.Name!.ToLowerInvariant())) if (!parents.ContainsKey(item.Machine.Name!.ToLowerInvariant()))
parents.Add(item.Machine.Name.ToLowerInvariant(), new List<string>()); parents.Add(item.Machine.Name!.ToLowerInvariant(), new List<string>());
parents[item.Machine.Name.ToLowerInvariant()].Add(item.Machine.Name.ToLowerInvariant()); parents[item.Machine.Name.ToLowerInvariant()].Add(item.Machine.Name.ToLowerInvariant());
} }
@@ -432,7 +443,11 @@ namespace SabreTools.Filtering
return; return;
string[] splitname = datItem.GetName()!.Split('.'); string[] splitname = datItem.GetName()!.Split('.');
#if NET20 || NET35
datItem.Machine.Name += $"/{string.Join(".", splitname.Take(splitname.Length > 1 ? splitname.Length - 1 : 1).ToArray())}";
#else
datItem.Machine.Name += $"/{string.Join(".", splitname.Take(splitname.Length > 1 ? splitname.Length - 1 : 1))}"; datItem.Machine.Name += $"/{string.Join(".", splitname.Take(splitname.Length > 1 ? splitname.Length - 1 : 1))}";
#endif
datItem.SetName(Path.GetFileName(datItem.GetName())); datItem.SetName(Path.GetFileName(datItem.GetName()));
} }

View File

@@ -29,7 +29,7 @@ namespace SabreTools.Filtering
public bool SetRemover(string field) public bool SetRemover(string field)
{ {
// If the key is null or empty, return false // If the key is null or empty, return false
if (string.IsNullOrWhiteSpace(field)) if (string.IsNullOrEmpty(field))
return false; return false;
// If we have a DatHeader field // If we have a DatHeader field

View File

@@ -35,7 +35,7 @@ namespace SabreTools.Filtering
public bool SetRemover(string field) public bool SetRemover(string field)
{ {
// If the key is null or empty, return false // If the key is null or empty, return false
if (string.IsNullOrWhiteSpace(field)) if (string.IsNullOrEmpty(field))
return false; return false;
// If we have a Machine field // If we have a Machine field

View File

@@ -69,7 +69,7 @@ namespace SabreTools.Filtering
string inputTrimmed = input.Trim('"', ' ', '\t'); string inputTrimmed = input.Trim('"', ' ', '\t');
string fieldString = inputTrimmed.Split(':')[0].ToLowerInvariant().Trim('"', ' ', '\t'); string fieldString = inputTrimmed.Split(':')[0].ToLowerInvariant().Trim('"', ' ', '\t');
string fileString = inputTrimmed[(fieldString.Length + 1)..].Trim('"', ' ', '\t'); string fileString = inputTrimmed.Substring(fieldString.Length + 1).Trim('"', ' ', '\t');
item.DatItemField = fieldString.AsDatItemField(); item.DatItemField = fieldString.AsDatItemField();
item.MachineField = fieldString.AsMachineField(); item.MachineField = fieldString.AsMachineField();

View File

@@ -119,10 +119,10 @@ namespace SabreTools.Filtering
|| filterTrimmed.StartsWith("~") || filterTrimmed.StartsWith("~")
|| filterTrimmed.StartsWith("not-"); || filterTrimmed.StartsWith("not-");
filterTrimmed = filterTrimmed.TrimStart('!', '~'); filterTrimmed = filterTrimmed.TrimStart('!', '~');
filterTrimmed = filterTrimmed.StartsWith("not-") ? filterTrimmed[4..] : filterTrimmed; filterTrimmed = filterTrimmed.StartsWith("not-") ? filterTrimmed.Substring(4) : filterTrimmed;
string filterFieldString = filterTrimmed.Split(':')[0].ToLowerInvariant().Trim('"', ' ', '\t'); string filterFieldString = filterTrimmed.Split(':')[0].ToLowerInvariant().Trim('"', ' ', '\t');
string filterValue = filterTrimmed[(filterFieldString.Length + 1)..].Trim('"', ' ', '\t'); string filterValue = filterTrimmed.Substring(filterFieldString.Length + 1).Trim('"', ' ', '\t');
return (filterFieldString, filterValue, negate); return (filterFieldString, filterValue, negate);
} }

View File

@@ -116,13 +116,13 @@ namespace SabreTools.Filtering
if (single == null || single.Equals(def)) if (single == null || single.Equals(def))
return null; return null;
// If we have a flag
#if NETFRAMEWORK #if NETFRAMEWORK
if (typeof(T).IsEnum && ((single as Enum)! & (value as Enum)!) != 0) // TODO: Fix flag matching
#else #else
// If we have a flag
if (typeof(T).IsEnum && (single as Enum)!.HasFlag((value as Enum)!)) if (typeof(T).IsEnum && (single as Enum)!.HasFlag((value as Enum)!))
#endif
return true; return true;
#endif
return single.Equals(value); return single.Equals(value);
} }
@@ -157,7 +157,7 @@ namespace SabreTools.Filtering
{ {
if (straw is string strawString) if (straw is string strawString)
{ {
if (!string.IsNullOrWhiteSpace(strawString) && needle is string needleString) if (!string.IsNullOrEmpty(strawString) && needle is string needleString)
{ {
string regexStraw = strawString; string regexStraw = strawString;

View File

@@ -1,10 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net6.0;net8.0</TargetFrameworks> <!-- Assembly Properties -->
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>1.1.2</Version>
<!-- Package Properties -->
<Authors>Matt Nadareski</Authors>
<Copyright>Copyright (c)2016-2024 Matt Nadareski</Copyright>
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
<RepositoryUrl>https://github.com/SabreTools/SabreTools</RepositoryUrl>
<RepositoryType>git</RepositoryType>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@@ -246,20 +246,20 @@ namespace SabreTools.Filtering
// Determine if the game has a parent or not // Determine if the game has a parent or not
string? parent = null; string? parent = null;
if (!string.IsNullOrWhiteSpace(items[0].Machine.RomOf)) if (!string.IsNullOrEmpty(items[0].Machine.RomOf))
parent = items[0].Machine.RomOf; parent = items[0].Machine.RomOf;
// If the parent doesnt exist, we want to continue // If the parent doesnt exist, we want to continue
if (string.IsNullOrWhiteSpace(parent)) if (string.IsNullOrEmpty(parent))
continue; continue;
// If the parent doesn't have any items, we want to continue // If the parent doesn't have any items, we want to continue
if (datFile.Items[parent]!.Count == 0) if (datFile.Items[parent!]!.Count == 0)
continue; continue;
// If the parent exists and has items, we copy the items from the parent to the current game // If the parent exists and has items, we copy the items from the parent to the current game
DatItem copyFrom = items[0]; DatItem copyFrom = items[0];
var parentItems = datFile.Items[parent]; var parentItems = datFile.Items[parent!];
if (parentItems == null) if (parentItems == null)
continue; continue;
@@ -429,20 +429,20 @@ namespace SabreTools.Filtering
// Determine if the game has a parent or not // Determine if the game has a parent or not
string? parent = null; string? parent = null;
if (!string.IsNullOrWhiteSpace(items[0].Machine.CloneOf)) if (!string.IsNullOrEmpty(items[0].Machine.CloneOf))
parent = items[0].Machine.CloneOf; parent = items[0].Machine.CloneOf;
// If the parent doesnt exist, we want to continue // If the parent doesnt exist, we want to continue
if (string.IsNullOrWhiteSpace(parent)) if (string.IsNullOrEmpty(parent))
continue; continue;
// If the parent doesn't have any items, we want to continue // If the parent doesn't have any items, we want to continue
if (datFile.Items[parent]!.Count == 0) if (datFile.Items[parent!]!.Count == 0)
continue; continue;
// If the parent exists and has items, we copy the items from the parent to the current game // If the parent exists and has items, we copy the items from the parent to the current game
DatItem copyFrom = items[0]; DatItem copyFrom = items[0];
var parentItems = datFile.Items[parent]; var parentItems = datFile.Items[parent!];
foreach (DatItem item in parentItems!) foreach (DatItem item in parentItems!)
{ {
DatItem datItem = (DatItem)item.Clone(); DatItem datItem = (DatItem)item.Clone();
@@ -456,7 +456,7 @@ namespace SabreTools.Filtering
// Now we want to get the parent romof tag and put it in each of the items // Now we want to get the parent romof tag and put it in each of the items
items = datFile.Items[game]; items = datFile.Items[game];
string? romof = datFile.Items[parent]![0].Machine.RomOf; string? romof = datFile.Items[parent!]![0].Machine.RomOf;
foreach (DatItem item in items!) foreach (DatItem item in items!)
{ {
item.Machine.RomOf = romof; item.Machine.RomOf = romof;
@@ -482,16 +482,16 @@ namespace SabreTools.Filtering
// Determine if the game has a parent or not // Determine if the game has a parent or not
string? parent = null; string? parent = null;
if (!string.IsNullOrWhiteSpace(items[0].Machine.CloneOf)) if (!string.IsNullOrEmpty(items[0].Machine.CloneOf))
parent = items[0].Machine.CloneOf; parent = items[0].Machine.CloneOf;
// If there is no parent, then we continue // If there is no parent, then we continue
if (string.IsNullOrWhiteSpace(parent)) if (string.IsNullOrEmpty(parent))
continue; continue;
// Otherwise, move the items from the current game to a subfolder of the parent game // Otherwise, move the items from the current game to a subfolder of the parent game
DatItem copyFrom; DatItem copyFrom;
if (datFile.Items[parent]!.Count == 0) if (datFile.Items[parent!]!.Count == 0)
{ {
copyFrom = new Rom(); copyFrom = new Rom();
copyFrom.Machine.Name = parent; copyFrom.Machine.Name = parent;
@@ -499,7 +499,7 @@ namespace SabreTools.Filtering
} }
else else
{ {
copyFrom = datFile.Items[parent]![0]; copyFrom = datFile.Items[parent!]![0];
} }
items = datFile.Items[game]; items = datFile.Items[game];
@@ -511,23 +511,23 @@ namespace SabreTools.Filtering
Disk disk = (item as Disk)!; Disk disk = (item as Disk)!;
// If the merge tag exists and the parent already contains it, skip // If the merge tag exists and the parent already contains it, skip
if (disk.MergeTag != null && datFile.Items[parent]!.Where(i => i.ItemType == ItemType.Disk).Select(i => (i as Disk)!.Name).Contains(disk.MergeTag)) if (disk.MergeTag != null && datFile.Items[parent!]!.Where(i => i.ItemType == ItemType.Disk).Select(i => (i as Disk)!.Name).Contains(disk.MergeTag))
{ {
continue; continue;
} }
// If the merge tag exists but the parent doesn't contain it, add to parent // If the merge tag exists but the parent doesn't contain it, add to parent
else if (disk.MergeTag != null && !datFile.Items[parent]!.Where(i => i.ItemType == ItemType.Disk).Select(i => (i as Disk)!.Name).Contains(disk.MergeTag)) else if (disk.MergeTag != null && !datFile.Items[parent!]!.Where(i => i.ItemType == ItemType.Disk).Select(i => (i as Disk)!.Name).Contains(disk.MergeTag))
{ {
disk.CopyMachineInformation(copyFrom); disk.CopyMachineInformation(copyFrom);
datFile.Items.Add(parent, disk); datFile.Items.Add(parent!, disk);
} }
// If there is no merge tag, add to parent // If there is no merge tag, add to parent
else if (disk.MergeTag == null) else if (disk.MergeTag == null)
{ {
disk.CopyMachineInformation(copyFrom); disk.CopyMachineInformation(copyFrom);
datFile.Items.Add(parent, disk); datFile.Items.Add(parent!, disk);
} }
} }
@@ -537,40 +537,40 @@ namespace SabreTools.Filtering
Rom rom = (item as Rom)!; Rom rom = (item as Rom)!;
// If the merge tag exists and the parent already contains it, skip // If the merge tag exists and the parent already contains it, skip
if (rom.MergeTag != null && datFile.Items[parent]!.Where(i => i.ItemType == ItemType.Rom).Select(i => (i as Rom)!.Name).Contains(rom.MergeTag)) if (rom.MergeTag != null && datFile.Items[parent!]!.Where(i => i.ItemType == ItemType.Rom).Select(i => (i as Rom)!.Name).Contains(rom.MergeTag))
{ {
continue; continue;
} }
// If the merge tag exists but the parent doesn't contain it, add to subfolder of parent // If the merge tag exists but the parent doesn't contain it, add to subfolder of parent
else if (rom.MergeTag != null && !datFile.Items[parent]!.Where(i => i.ItemType == ItemType.Rom).Select(i => (i as Rom)!.Name).Contains(rom.MergeTag)) else if (rom.MergeTag != null && !datFile.Items[parent!]!.Where(i => i.ItemType == ItemType.Rom).Select(i => (i as Rom)!.Name).Contains(rom.MergeTag))
{ {
if (subfolder) if (subfolder)
rom.Name = $"{rom.Machine.Name}\\{rom.Name}"; rom.Name = $"{rom.Machine.Name}\\{rom.Name}";
rom.CopyMachineInformation(copyFrom); rom.CopyMachineInformation(copyFrom);
datFile.Items.Add(parent, rom); datFile.Items.Add(parent!, rom);
} }
// If the parent doesn't already contain this item, add to subfolder of parent // If the parent doesn't already contain this item, add to subfolder of parent
else if (!datFile.Items[parent]!.Contains(item) || skipDedup) else if (!datFile.Items[parent!]!.Contains(item) || skipDedup)
{ {
if (subfolder) if (subfolder)
rom.Name = $"{item.Machine.Name}\\{rom.Name}"; rom.Name = $"{item.Machine.Name}\\{rom.Name}";
rom.CopyMachineInformation(copyFrom); rom.CopyMachineInformation(copyFrom);
datFile.Items.Add(parent, rom); datFile.Items.Add(parent!, rom);
} }
} }
// All other that would be missing to subfolder of parent // All other that would be missing to subfolder of parent
else if (!datFile.Items[parent]!.Contains(item)) else if (!datFile.Items[parent!]!.Contains(item))
{ {
if (subfolder) if (subfolder)
item.SetName($"{item.Machine.Name}\\{item.GetName()}"); item.SetName($"{item.Machine.Name}\\{item.GetName()}");
item.CopyMachineInformation(copyFrom); item.CopyMachineInformation(copyFrom);
datFile.Items.Add(parent, item); datFile.Items.Add(parent!, item);
} }
} }
@@ -632,19 +632,19 @@ namespace SabreTools.Filtering
// Determine if the game has a parent or not // Determine if the game has a parent or not
string? parent = null; string? parent = null;
if (!string.IsNullOrWhiteSpace(items[0].Machine.RomOf)) if (!string.IsNullOrEmpty(items[0].Machine.RomOf))
parent = items[0].Machine.RomOf; parent = items[0].Machine.RomOf;
// If the parent doesnt exist, we want to continue // If the parent doesnt exist, we want to continue
if (string.IsNullOrWhiteSpace(parent)) if (string.IsNullOrEmpty(parent))
continue; continue;
// If the parent doesn't have any items, we want to continue // If the parent doesn't have any items, we want to continue
if (datFile.Items[parent]!.Count == 0) if (datFile.Items[parent!]!.Count == 0)
continue; continue;
// If the parent exists and has items, we remove the items that are in the parent from the current game // If the parent exists and has items, we remove the items that are in the parent from the current game
var parentItems = datFile.Items[parent]; var parentItems = datFile.Items[parent!];
if (parentItems == null) if (parentItems == null)
continue; continue;
@@ -678,19 +678,19 @@ namespace SabreTools.Filtering
// Determine if the game has a parent or not // Determine if the game has a parent or not
string? parent = null; string? parent = null;
if (!string.IsNullOrWhiteSpace(items[0].Machine.CloneOf)) if (!string.IsNullOrEmpty(items[0].Machine.CloneOf))
parent = items[0].Machine.CloneOf; parent = items[0].Machine.CloneOf;
// If the parent doesnt exist, we want to continue // If the parent doesnt exist, we want to continue
if (string.IsNullOrWhiteSpace(parent)) if (string.IsNullOrEmpty(parent))
continue; continue;
// If the parent doesn't have any items, we want to continue // If the parent doesn't have any items, we want to continue
if (datFile.Items[parent] == null || datFile.Items[parent]!.Count == 0) if (datFile.Items[parent!] == null || datFile.Items[parent!]!.Count == 0)
continue; continue;
// If the parent exists and has items, we remove the parent items from the current game // If the parent exists and has items, we remove the parent items from the current game
var parentItems = datFile.Items[parent]; var parentItems = datFile.Items[parent!];
foreach (DatItem item in parentItems!) foreach (DatItem item in parentItems!)
{ {
DatItem datItem = (DatItem)item.Clone(); DatItem datItem = (DatItem)item.Clone();
@@ -702,7 +702,7 @@ namespace SabreTools.Filtering
// Now we want to get the parent romof tag and put it in each of the remaining items // Now we want to get the parent romof tag and put it in each of the remaining items
items = datFile.Items[game]; items = datFile.Items[game];
string? romof = datFile.Items[parent]![0].Machine.RomOf; string? romof = datFile.Items[parent!]![0].Machine.RomOf;
foreach (DatItem item in items!) foreach (DatItem item in items!)
{ {
item.Machine.RomOf = romof; item.Machine.RomOf = romof;