diff --git a/SabreTools.Core/ArrayExtensions.cs b/SabreTools.Core/ArrayExtensions.cs
new file mode 100644
index 00000000..e5d632af
--- /dev/null
+++ b/SabreTools.Core/ArrayExtensions.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace SabreTools.Core
+{
+ public static class ArrayExtensions
+ {
+ ///
+ /// Indicates whether the specified array is null or has a length of zero
+ ///
+ public static bool IsNullOrEmpty(this Array? array)
+ {
+ return array == null || array.Length == 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Core/DictionaryBaseExtensions.cs b/SabreTools.Core/DictionaryBaseExtensions.cs
new file mode 100644
index 00000000..4aad835c
--- /dev/null
+++ b/SabreTools.Core/DictionaryBaseExtensions.cs
@@ -0,0 +1,479 @@
+using System;
+using System.Linq;
+using SabreTools.Models.Internal;
+
+namespace SabreTools.Core
+{
+ public static class DictionaryBaseExtensions
+ {
+ #region Cloning
+
+ ///
+ /// Deep clone a DictionaryBase object
+ ///
+ public static DictionaryBase? Clone(this DictionaryBase dictionaryBase)
+ {
+ // Create a new object of the same type
+ var clone = dictionaryBase
+ .GetType()
+ .GetConstructor(System.Reflection.BindingFlags.Public, Array.Empty())?
+ .Invoke(null) as DictionaryBase;
+
+ // If construction failed, we can't do anything
+ if (clone == null)
+ return null;
+
+ // Loop through and clone per type
+ foreach (string key in dictionaryBase.Keys)
+ {
+ object? value = dictionaryBase[key];
+ switch (value)
+ {
+ // Primative types
+ case bool:
+ case long:
+ case double:
+ case string:
+ clone[key] = value;
+ break;
+
+ // DictionaryBase types
+ case DictionaryBase db:
+ clone[key] = db.Clone();
+ break;
+
+ // Enumerable types
+ case byte[] bytArr:
+ clone[key] = bytArr.Clone();
+ break;
+ case string[] strArr:
+ clone[key] = strArr.Clone();
+ break;
+ case DictionaryBase[] enDb:
+ clone[key] = enDb.Select(Clone).ToArray();
+ break;
+
+ // Everything else just copies
+ default:
+ clone[key] = value;
+ break;
+ }
+ }
+
+ return clone;
+ }
+
+ #endregion
+
+ #region Equality Checking
+
+ ///
+ /// Check equality of two DictionaryBase objects
+ ///
+ public static bool EqualTo(this DictionaryBase self, DictionaryBase other)
+ {
+ // Check types first
+ if (self.GetType() != other.GetType())
+ return false;
+
+ // Check based on the item type
+ return (self, other) switch
+ {
+ (Disk diskSelf, Disk diskOther) => EqualsImpl(diskSelf, diskOther),
+ (Media mediaSelf, Media mediaOther) => EqualsImpl(mediaSelf, mediaOther),
+ (Rom romSelf, Rom romOther) => EqualsImpl(romSelf, romOther),
+ _ => EqualsImpl(self, other),
+ };
+ }
+
+ ///
+ /// Check equality of two DictionaryBase objects
+ ///
+ private static bool EqualsImpl(this DictionaryBase self, DictionaryBase other)
+ {
+ // If the number of key-value pairs doesn't match, they can't match
+ if (self.Count != other.Count)
+ return false;
+
+ // If any keys are missing on either side, they can't match
+ if (self.Keys.Except(other.Keys).Any())
+ return false;
+ if (other.Keys.Except(self.Keys).Any())
+ return false;
+
+ // Check all pairs to see if they're equal
+ foreach (var kvp in self)
+ {
+ switch (kvp.Value, other[kvp.Key])
+ {
+ case (string selfString, string otherString):
+ if (!string.Equals(selfString, otherString, StringComparison.OrdinalIgnoreCase))
+ return false;
+ break;
+
+ case (DictionaryBase selfDb, DictionaryBase otherDb):
+ if (!selfDb.Equals(otherDb))
+ return false;
+ break;
+
+ // TODO: Make this case-insensitive
+ case (string[] selfStrArr, string[] otherStrArr):
+ if (selfStrArr.Length != otherStrArr.Length)
+ return false;
+ if (selfStrArr.Except(otherStrArr).Any())
+ return false;
+ if (otherStrArr.Except(selfStrArr).Any())
+ return false;
+ break;
+
+ // TODO: Fix the logic here for real equality
+ case (DictionaryBase[] selfDbArr, DictionaryBase[] otherDbArr):
+ if (selfDbArr.Length != otherDbArr.Length)
+ return false;
+ if (selfDbArr.Except(otherDbArr).Any())
+ return false;
+ if (otherDbArr.Except(selfDbArr).Any())
+ return false;
+ break;
+
+ default:
+ if (kvp.Value != other[kvp.Key])
+ return false;
+ break;
+ }
+ }
+
+ return true;
+ }
+
+ ///
+ /// Check equality of two Disk objects
+ ///
+ private static bool EqualsImpl(this Disk self, Disk other)
+ {
+ string? selfStatus = self.ReadString(Disk.StatusKey);
+ string? otherStatus = other.ReadString(Disk.StatusKey);
+
+ string? selfName = self.ReadString(Disk.NameKey);
+ string? otherName = other.ReadString(Disk.NameKey);
+
+ // If all hashes are empty but they're both nodump and the names match, then they're dupes
+ if (string.Equals(selfStatus, "nodump", StringComparison.OrdinalIgnoreCase)
+ && string.Equals(otherStatus, "nodump", StringComparison.OrdinalIgnoreCase)
+ && string.Equals(selfName, otherName, StringComparison.OrdinalIgnoreCase)
+ && !self.HasHashes()
+ && !other.HasHashes())
+ {
+ return true;
+ }
+
+ // If we get a partial match
+ if (self.HashMatch(other))
+ return true;
+
+ // All other cases fail
+ return false;
+ }
+
+ ///
+ /// Check equality of two Media objects
+ ///
+ private static bool EqualsImpl(this Media self, Media other)
+ {
+ // If we get a partial match
+ if (self.HashMatch(other))
+ return true;
+
+ // All other cases fail
+ return false;
+ }
+
+ ///
+ /// Check equality of two Rom objects
+ ///
+ private static bool EqualsImpl(this Rom self, Rom other)
+ {
+ string? selfStatus = self.ReadString(Rom.StatusKey);
+ string? otherStatus = other.ReadString(Rom.StatusKey);
+
+ string? selfName = self.ReadString(Rom.NameKey);
+ string? otherName = other.ReadString(Rom.NameKey);
+
+ long? selfSize = self.ReadLong(Rom.SizeKey);
+ long? otherSize = other.ReadLong(Rom.SizeKey);
+
+ // If all hashes are empty but they're both nodump and the names match, then they're dupes
+ if (string.Equals(selfStatus, "nodump", StringComparison.OrdinalIgnoreCase)
+ && string.Equals(otherStatus, "nodump", StringComparison.OrdinalIgnoreCase)
+ && string.Equals(selfName, otherName, StringComparison.OrdinalIgnoreCase)
+ && !self.HasHashes()
+ && !other.HasHashes())
+ {
+ return true;
+ }
+
+ // If we have a file that has no known size, rely on the hashes only
+ if (selfSize == null && self.HashMatch(other))
+
+ // If we get a partial match
+ if (selfSize == otherSize && self.HashMatch(other))
+ return true;
+
+ // All other cases fail
+ return false;
+ }
+
+ #endregion
+
+ #region Hash Checking
+
+ ///
+ /// Returns if any hashes are common
+ ///
+ public static bool HashMatch(this Disk self, Disk other)
+ {
+ // If either have no hashes, we return false, otherwise this would be a false positive
+ if (!self.HasHashes() || !other.HasHashes())
+ return false;
+
+ // If neither have hashes in common, we return false, otherwise this would be a false positive
+ if (!self.HasCommonHash(other))
+ return false;
+
+ // Return if all hashes match according to merge rules
+ return ConditionalHashEquals(self.ReadString(Disk.MD5Key), other.ReadString(Disk.MD5Key))
+ && ConditionalHashEquals(self.ReadString(Disk.SHA1Key), other.ReadString(Disk.SHA1Key));
+ }
+
+ ///
+ /// Returns if any hashes are common
+ ///
+ public static bool HashMatch(this Media self, Media other)
+ {
+ // If either have no hashes, we return false, otherwise this would be a false positive
+ if (!self.HasHashes() || !other.HasHashes())
+ return false;
+
+ // If neither have hashes in common, we return false, otherwise this would be a false positive
+ if (!self.HasCommonHash(other))
+ return false;
+
+ // Return if all hashes match according to merge rules
+ return ConditionalHashEquals(self.ReadString(Media.MD5Key), other.ReadString(Media.MD5Key))
+ && ConditionalHashEquals(self.ReadString(Media.SHA1Key), other.ReadString(Media.SHA1Key))
+ && ConditionalHashEquals(self.ReadString(Media.SHA256Key), other.ReadString(Media.SHA256Key))
+ && ConditionalHashEquals(self.ReadString(Media.SpamSumKey), other.ReadString(Media.SpamSumKey));
+ }
+
+ ///
+ /// Returns if any hashes are common
+ ///
+ public static bool HashMatch(this Rom self, Rom other)
+ {
+ // If either have no hashes, we return false, otherwise this would be a false positive
+ if (!self.HasHashes() || !other.HasHashes())
+ return false;
+
+ // If neither have hashes in common, we return false, otherwise this would be a false positive
+ if (!self.HasCommonHash(other))
+ return false;
+
+ // Return if all hashes match according to merge rules
+ return ConditionalHashEquals(self.ReadString(Rom.CRCKey), other.ReadString(Rom.CRCKey))
+ && ConditionalHashEquals(self.ReadString(Rom.MD5Key), other.ReadString(Rom.MD5Key))
+ && ConditionalHashEquals(self.ReadString(Rom.SHA1Key), other.ReadString(Rom.SHA1Key))
+ && ConditionalHashEquals(self.ReadString(Rom.SHA256Key), other.ReadString(Rom.SHA256Key))
+ && ConditionalHashEquals(self.ReadString(Rom.SHA384Key), other.ReadString(Rom.SHA384Key))
+ && ConditionalHashEquals(self.ReadString(Rom.SHA512Key), other.ReadString(Rom.SHA512Key))
+ && ConditionalHashEquals(self.ReadString(Rom.SpamSumKey), other.ReadString(Rom.SpamSumKey));
+ }
+
+ ///
+ /// Returns if any hashes exist
+ ///
+ public static bool HasHashes(this Disk disk)
+ {
+ bool md5Null = string.IsNullOrWhiteSpace(disk.ReadString(Disk.MD5Key));
+ bool sha1Null = string.IsNullOrWhiteSpace(disk.ReadString(Disk.SHA1Key));
+
+ return !md5Null || !sha1Null;
+ }
+
+ ///
+ /// Returns if any hashes exist
+ ///
+ public static bool HasHashes(this Media media)
+ {
+ bool md5Null = string.IsNullOrWhiteSpace(media.ReadString(Media.MD5Key));
+ bool sha1Null = string.IsNullOrWhiteSpace(media.ReadString(Media.SHA1Key));
+ bool sha256Null = string.IsNullOrWhiteSpace(media.ReadString(Media.SHA256Key));
+ bool spamsumNull = string.IsNullOrWhiteSpace(media.ReadString(Media.SpamSumKey));
+
+ return !md5Null || !sha1Null || !sha256Null || !spamsumNull;
+ }
+
+ ///
+ /// Returns if any hashes exist
+ ///
+ public static bool HasHashes(this Rom rom)
+ {
+ bool crcNull = string.IsNullOrWhiteSpace(rom.ReadString(Rom.CRCKey));
+ bool md5Null = string.IsNullOrWhiteSpace(rom.ReadString(Rom.MD5Key));
+ bool sha1Null = string.IsNullOrWhiteSpace(rom.ReadString(Rom.SHA1Key));
+ bool sha256Null = string.IsNullOrWhiteSpace(rom.ReadString(Rom.SHA256Key));
+ bool sha384Null = string.IsNullOrWhiteSpace(rom.ReadString(Rom.SHA384Key));
+ bool sha512Null = string.IsNullOrWhiteSpace(rom.ReadString(Rom.SHA512Key));
+ bool spamsumNull = string.IsNullOrWhiteSpace(rom.ReadString(Rom.SpamSumKey));
+
+ return !crcNull || !md5Null || !sha1Null || !sha256Null || !sha384Null || !sha512Null || !spamsumNull;
+ }
+
+ ///
+ /// Returns if all of the hashes are set to their 0-byte values or null
+ ///
+ public static bool HasZeroHash(this Disk disk)
+ {
+ string? md5 = disk.ReadString(Disk.MD5Key);
+ bool md5Null = string.IsNullOrWhiteSpace(md5) || string.Equals(md5, Constants.MD5Zero, StringComparison.OrdinalIgnoreCase);
+
+ string? sha1 = disk.ReadString(Disk.SHA1Key);
+ bool sha1Null = string.IsNullOrWhiteSpace(sha1) || string.Equals(sha1, Constants.SHA1Zero, StringComparison.OrdinalIgnoreCase);
+
+ return md5Null && sha1Null;
+ }
+
+ ///
+ /// Returns if all of the hashes are set to their 0-byte values or null
+ ///
+ public static bool HasZeroHash(this Media media)
+ {
+ string? md5 = media.ReadString(Media.MD5Key);
+ bool md5Null = string.IsNullOrWhiteSpace(md5) || string.Equals(md5, Constants.MD5Zero, StringComparison.OrdinalIgnoreCase);
+
+ string? sha1 = media.ReadString(Media.SHA1Key);
+ bool sha1Null = string.IsNullOrWhiteSpace(sha1) || string.Equals(sha1, Constants.SHA1Zero, StringComparison.OrdinalIgnoreCase);
+
+ string? sha256 = media.ReadString(Media.SHA256Key);
+ bool sha256Null = string.IsNullOrWhiteSpace(sha256) || string.Equals(sha256, Constants.SHA256Zero, StringComparison.OrdinalIgnoreCase);
+
+ string? spamsum = media.ReadString(Media.SpamSumKey);
+ bool spamsumNull = string.IsNullOrWhiteSpace(spamsum) || string.Equals(spamsum, Constants.SpamSumZero, StringComparison.OrdinalIgnoreCase);
+
+ return md5Null && sha1Null && sha256Null && spamsumNull;
+ }
+
+ ///
+ /// Returns if all of the hashes are set to their 0-byte values or null
+ ///
+ public static bool HasZeroHash(this Rom rom)
+ {
+ string? crc = rom.ReadString(Rom.CRCKey);
+ bool crcNull = string.IsNullOrWhiteSpace(crc) || string.Equals(crc, Constants.CRCZero, StringComparison.OrdinalIgnoreCase);
+
+ string? md5 = rom.ReadString(Rom.MD5Key);
+ bool md5Null = string.IsNullOrWhiteSpace(md5) || string.Equals(md5, Constants.MD5Zero, StringComparison.OrdinalIgnoreCase);
+
+ string? sha1 = rom.ReadString(Rom.SHA1Key);
+ bool sha1Null = string.IsNullOrWhiteSpace(sha1) || string.Equals(sha1, Constants.SHA1Zero, StringComparison.OrdinalIgnoreCase);
+
+ string? sha256 = rom.ReadString(Rom.SHA256Key);
+ bool sha256Null = string.IsNullOrWhiteSpace(sha256) || string.Equals(sha256, Constants.SHA256Zero, StringComparison.OrdinalIgnoreCase);
+
+ string? sha384 = rom.ReadString(Rom.SHA384Key);
+ bool sha384Null = string.IsNullOrWhiteSpace(sha384) || string.Equals(sha384, Constants.SHA384Zero, StringComparison.OrdinalIgnoreCase);
+
+ string? sha512 = rom.ReadString(Rom.SHA512Key);
+ bool sha512Null = string.IsNullOrWhiteSpace(sha512) || string.Equals(sha512, Constants.SHA512Zero, StringComparison.OrdinalIgnoreCase);
+
+ string? spamsum = rom.ReadString(Rom.SpamSumKey);
+ bool spamsumNull = string.IsNullOrWhiteSpace(spamsum) || string.Equals(spamsum, Constants.SpamSumZero, StringComparison.OrdinalIgnoreCase);
+
+ return crcNull && md5Null && sha1Null && sha256Null && sha384Null && sha512Null && spamsumNull;
+ }
+
+ ///
+ /// Determine if two hashes are equal for the purposes of merging
+ ///
+ private static bool ConditionalHashEquals(string? firstHash, string? secondHash)
+ {
+ // If either hash is empty, we say they're equal for merging
+ if (string.IsNullOrWhiteSpace(firstHash) || string.IsNullOrWhiteSpace(secondHash))
+ return true;
+
+ // If they're different sizes, they can't match
+ if (firstHash!.Length != secondHash!.Length)
+ return false;
+
+ // Otherwise, they need to match exactly
+ return string.Equals(firstHash, secondHash, StringComparison.OrdinalIgnoreCase);
+ }
+
+ ///
+ /// Returns if there are no, non-empty hashes in common
+ ///
+ private static bool HasCommonHash(this Disk self, Disk other)
+ {
+ bool md5Null = string.IsNullOrWhiteSpace(self.ReadString(Disk.MD5Key));
+ md5Null ^= string.IsNullOrWhiteSpace(other.ReadString(Disk.MD5Key));
+
+ bool sha1Null = string.IsNullOrWhiteSpace(self.ReadString(Disk.SHA1Key));
+ sha1Null ^= string.IsNullOrWhiteSpace(other.ReadString(Disk.SHA1Key));
+
+ return !md5Null || !sha1Null;
+ }
+
+ ///
+ /// Returns if there are no, non-empty hashes in common
+ ///
+ private static bool HasCommonHash(this Media self, Media other)
+ {
+ bool md5Null = string.IsNullOrWhiteSpace(self.ReadString(Media.MD5Key));
+ md5Null ^= string.IsNullOrWhiteSpace(other.ReadString(Media.MD5Key));
+
+ bool sha1Null = string.IsNullOrWhiteSpace(self.ReadString(Media.SHA1Key));
+ sha1Null ^= string.IsNullOrWhiteSpace(other.ReadString(Media.SHA1Key));
+
+ bool sha256Null = string.IsNullOrWhiteSpace(self.ReadString(Media.SHA256Key));
+ sha256Null ^= string.IsNullOrWhiteSpace(other.ReadString(Media.SHA256Key));
+
+ bool spamsumNull = string.IsNullOrWhiteSpace(self.ReadString(Media.SpamSumKey));
+ spamsumNull ^= string.IsNullOrWhiteSpace(other.ReadString(Media.SpamSumKey));
+
+ return !md5Null || !sha1Null || !sha256Null || !spamsumNull;
+ }
+
+ ///
+ /// Returns if there are no, non-empty hashes in common
+ ///
+ private static bool HasCommonHash(this Rom self, Rom other)
+ {
+ bool crcNull = string.IsNullOrWhiteSpace(self.ReadString(Rom.CRCKey));
+ crcNull ^= string.IsNullOrWhiteSpace(other.ReadString(Rom.CRCKey));
+
+ bool md5Null = string.IsNullOrWhiteSpace(self.ReadString(Rom.MD5Key));
+ md5Null ^= string.IsNullOrWhiteSpace(other.ReadString(Rom.MD5Key));
+
+ bool sha1Null = string.IsNullOrWhiteSpace(self.ReadString(Rom.SHA1Key));
+ sha1Null ^= string.IsNullOrWhiteSpace(other.ReadString(Rom.SHA1Key));
+
+ bool sha256Null = string.IsNullOrWhiteSpace(self.ReadString(Rom.SHA256Key));
+ sha256Null ^= string.IsNullOrWhiteSpace(other.ReadString(Rom.SHA256Key));
+
+ bool sha384Null = string.IsNullOrWhiteSpace(self.ReadString(Rom.SHA384Key));
+ sha384Null ^= string.IsNullOrWhiteSpace(other.ReadString(Rom.SHA384Key));
+
+ bool sha512Null = string.IsNullOrWhiteSpace(self.ReadString(Rom.SHA512Key));
+ sha512Null ^= string.IsNullOrWhiteSpace(other.ReadString(Rom.SHA512Key));
+
+ bool spamsumNull = string.IsNullOrWhiteSpace(self.ReadString(Rom.SpamSumKey));
+ spamsumNull ^= string.IsNullOrWhiteSpace(other.ReadString(Rom.SpamSumKey));
+
+ return !crcNull || !md5Null || !sha1Null || !sha256Null || !sha384Null || !sha512Null || !spamsumNull;
+ }
+
+ #endregion
+
+ // TODO: Add DatItem conversion extensions here
+ // TODO: Once done with the above, replace innards on each current model
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Core/Enums.cs b/SabreTools.Core/Enums.cs
index f3ee2937..eaccc295 100644
--- a/SabreTools.Core/Enums.cs
+++ b/SabreTools.Core/Enums.cs
@@ -452,6 +452,12 @@ namespace SabreTools.Core
[Mapping("configuration")]
Configuration,
+ [Mapping("conflocation")]
+ ConfLocation,
+
+ [Mapping("confsetting")]
+ ConfSetting,
+
[Mapping("control")]
Control,
@@ -464,9 +470,15 @@ namespace SabreTools.Core
[Mapping("device_ref", "deviceref")]
DeviceReference,
+ [Mapping("diplocation")]
+ DipLocation,
+
[Mapping("dipswitch")]
DipSwitch,
+ [Mapping("dipvalue")]
+ DipValue,
+
[Mapping("diskarea")]
DiskArea,
@@ -491,9 +503,6 @@ namespace SabreTools.Core
[Mapping("instance")]
Instance,
- [Mapping("location")]
- Location,
-
[Mapping("original")]
Original,
@@ -521,9 +530,6 @@ namespace SabreTools.Core
[Mapping("serials")]
Serials,
- [Mapping("setting")]
- Setting,
-
[Mapping("sharedfeat", "shared_feat", "sharedfeature", "shared_feature")]
SharedFeature,
diff --git a/SabreTools.Core/SabreTools.Core.csproj b/SabreTools.Core/SabreTools.Core.csproj
index 9e23202e..2223d477 100644
--- a/SabreTools.Core/SabreTools.Core.csproj
+++ b/SabreTools.Core/SabreTools.Core.csproj
@@ -9,6 +9,10 @@
+
+
+
+
diff --git a/SabreTools.Core/Tools/TextHelper.cs b/SabreTools.Core/Tools/TextHelper.cs
index d085122d..8a5c0ac4 100644
--- a/SabreTools.Core/Tools/TextHelper.cs
+++ b/SabreTools.Core/Tools/TextHelper.cs
@@ -25,7 +25,43 @@ namespace SabreTools.Core.Tools
return input;
}
- //
+ ///
+ /// Normalize a CRC32 string and pad to the correct size
+ ///
+ public static string NormalizeCRC32(string? hash)
+ => NormalizeHashData(hash, Constants.CRCLength);
+
+ ///
+ /// Normalize a MD5 string and pad to the correct size
+ ///
+ public static string NormalizeMD5(string? hash)
+ => NormalizeHashData(hash, Constants.MD5Length);
+
+ ///
+ /// Normalize a SHA1 string and pad to the correct size
+ ///
+ public static string NormalizeSHA1(string? hash)
+ => NormalizeHashData(hash, Constants.SHA1Length);
+
+ ///
+ /// Normalize a SHA256 string and pad to the correct size
+ ///
+ public static string NormalizeSHA256(string? hash)
+ => NormalizeHashData(hash, Constants.SHA256Length);
+
+ ///
+ /// Normalize a SHA384 string and pad to the correct size
+ ///
+ public static string NormalizeSHA384(string? hash)
+ => NormalizeHashData(hash, Constants.SHA384Length);
+
+ ///
+ /// Normalize a SHA512 string and pad to the correct size
+ ///
+ public static string NormalizeSHA512(string? hash)
+ => NormalizeHashData(hash, Constants.SHA512Length);
+
+ ///
/// Remove all chars that are considered path unsafe
///
public static string? RemovePathUnsafeCharacters(string? input)
@@ -33,6 +69,8 @@ namespace SabreTools.Core.Tools
if (string.IsNullOrWhiteSpace(input))
return input;
+ input = input.ToLowerInvariant();
+
List invalidPath = Path.GetInvalidPathChars().ToList();
return new string(input.Where(c => !invalidPath.Contains(c)).ToArray());
}
@@ -90,6 +128,40 @@ namespace SabreTools.Core.Tools
return input;
}
+ ///
+ /// Normalize a hash string and pad to the correct size
+ ///
+ private static string NormalizeHashData(string? hash, int expectedLength)
+ {
+ // If we have a known blank hash, return blank
+ if (string.IsNullOrWhiteSpace(hash) || hash == "-" || hash == "_")
+ return string.Empty;
+
+ // Check to see if it's a "hex" hash
+ hash = hash.Trim().Replace("0x", string.Empty);
+
+ // If we have a blank hash now, return blank
+ if (string.IsNullOrWhiteSpace(hash))
+ return string.Empty;
+
+ // If the hash shorter than the required length, pad it
+ if (hash.Length < expectedLength)
+ hash = hash.PadLeft(expectedLength, '0');
+
+ // If the hash is longer than the required length, it's invalid
+ else if (hash.Length > expectedLength)
+ return string.Empty;
+
+ // Now normalize the hash
+ hash = hash.ToLowerInvariant();
+
+ // Otherwise, make sure that every character is a proper match
+ if (hash.Any(c => (c < '0' || c > '9') && (c < 'a' || c > 'f')))
+ hash = string.Empty;
+
+ return hash;
+ }
+
///
/// Convert Cyrillic lettering to Latin lettering
///
diff --git a/SabreTools.Core/Tools/Utilities.cs b/SabreTools.Core/Tools/Utilities.cs
index f4a1acf3..add94037 100644
--- a/SabreTools.Core/Tools/Utilities.cs
+++ b/SabreTools.Core/Tools/Utilities.cs
@@ -163,16 +163,6 @@ namespace SabreTools.Core.Tools
};
}
- /// Indicates whether the specified array is null or has a length of zero
- ///
- /// The array to test
- /// true if the array parameter is null or has a length of zero; otherwise, false.
- /// https://stackoverflow.com/questions/8560106/isnullorempty-equivalent-for-array-c-sharp
- public static bool IsNullOrEmpty(this Array array)
- {
- return array == null || array.Length == 0;
- }
-
////
/// Returns if the first byte array starts with the second array
///
diff --git a/SabreTools.DatFiles/DatFile.cs b/SabreTools.DatFiles/DatFile.cs
index 7fc9e370..c7b9939b 100644
--- a/SabreTools.DatFiles/DatFile.cs
+++ b/SabreTools.DatFiles/DatFile.cs
@@ -316,7 +316,7 @@ namespace SabreTools.DatFiles
{
// Initialize strings
string fix,
- game = item.Machine.Name,
+ game = item.Machine?.Name ?? string.Empty,
name = item.GetName() ?? item.ItemType.ToString(),
crc = string.Empty,
md5 = string.Empty,
@@ -365,9 +365,9 @@ namespace SabreTools.DatFiles
.Replace("%game%", game)
.Replace("%machine%", game)
.Replace("%name%", name)
- .Replace("%manufacturer%", item.Machine.Manufacturer ?? string.Empty)
- .Replace("%publisher%", item.Machine.Publisher ?? string.Empty)
- .Replace("%category%", item.Machine.Category ?? string.Empty)
+ .Replace("%manufacturer%", item.Machine?.Manufacturer ?? string.Empty)
+ .Replace("%publisher%", item.Machine?.Publisher ?? string.Empty)
+ .Replace("%category%", item.Machine?.Category ?? string.Empty)
.Replace("%crc%", crc)
.Replace("%md5%", md5)
.Replace("%sha1%", sha1)
@@ -397,7 +397,7 @@ namespace SabreTools.DatFiles
Header.UseRomName = true;
// Get the name to update
- string? name = (Header.UseRomName ? item.GetName() : item.Machine.Name) ?? string.Empty;
+ string? name = (Header.UseRomName ? item.GetName() : item.Machine?.Name) ?? string.Empty;
// Create the proper Prefix and Postfix
string pre = CreatePrefixPostfix(item, true);
@@ -454,13 +454,13 @@ namespace SabreTools.DatFiles
name += Header.AddExtension;
if (Header.UseRomName && Header.GameName)
- name = Path.Combine(item.Machine.Name, name);
+ name = Path.Combine(item.Machine?.Name ?? string.Empty, name);
// Now assign back the formatted name
name = $"{pre}{name}{post}";
if (Header.UseRomName)
item.SetName(name);
- else
+ else if (item.Machine != null)
item.Machine.Name = name;
// Restore all relevant values
@@ -489,7 +489,7 @@ namespace SabreTools.DatFiles
// If the Rom has "null" characteristics, ensure all fields
if (rom.Size == null && rom.CRC == "null")
{
- logger.Verbose($"Empty folder found: {datItem.Machine.Name}");
+ logger.Verbose($"Empty folder found: {datItem.Machine?.Name}");
rom.Name = (rom.Name == "null" ? "-" : rom.Name);
rom.Size = Constants.SizeZero;
diff --git a/SabreTools.DatFiles/Formats/ArchiveDotOrg.Reader.cs b/SabreTools.DatFiles/Formats/ArchiveDotOrg.Reader.cs
index 68e3038e..556929fb 100644
--- a/SabreTools.DatFiles/Formats/ArchiveDotOrg.Reader.cs
+++ b/SabreTools.DatFiles/Formats/ArchiveDotOrg.Reader.cs
@@ -113,7 +113,7 @@ namespace SabreTools.DatFiles.Formats
SHA1 = file.SHA1,
//FileCount = file.FileCount, // TODO: Add to internal model
ArchiveDotOrgFormat = file.Format,
- //Original = file.Original, // TODO: Add to internal model
+ OriginalFilename = file.Original,
Summation = file.Summation,
//MatrixNumber = file.MatrixNumber, // TODO: Add to internal model
//CollectionCatalogNumber = file.CollectionCatalogNumber, // TODO: Add to internal model
diff --git a/SabreTools.DatFiles/Formats/AttractMode.Writer.cs b/SabreTools.DatFiles/Formats/AttractMode.Writer.cs
index 3c3bacf6..662f1107 100644
--- a/SabreTools.DatFiles/Formats/AttractMode.Writer.cs
+++ b/SabreTools.DatFiles/Formats/AttractMode.Writer.cs
@@ -121,23 +121,23 @@ namespace SabreTools.DatFiles.Formats
{
var row = new Models.AttractMode.Row
{
- Name = rom.Machine.Name,
- Title = rom.Machine.Description,
+ Name = rom.Machine?.Name,
+ Title = rom.Machine?.Description,
Emulator = Header.FileName,
- CloneOf = rom.Machine.CloneOf,
- Year = rom.Machine.Year,
- Manufacturer = rom.Machine.Manufacturer,
- Category = rom.Machine.Category,
- Players = rom.Machine.Players,
- Rotation = rom.Machine.Rotation,
- Control = rom.Machine.Control,
- Status = rom.Machine.Status,
- DisplayCount = rom.Machine.DisplayCount,
- DisplayType = rom.Machine.DisplayType,
+ CloneOf = rom.Machine?.CloneOf,
+ Year = rom.Machine?.Year,
+ Manufacturer = rom.Machine?.Manufacturer,
+ Category = rom.Machine?.Category,
+ Players = rom.Machine?.Players,
+ Rotation = rom.Machine?.Rotation,
+ Control = rom.Machine?.Control,
+ Status = rom.Machine?.Status,
+ DisplayCount = rom.Machine?.DisplayCount,
+ DisplayType = rom.Machine?.DisplayType,
AltRomname = rom.AltName,
AltTitle = rom.AltTitle,
- Extra = rom.Machine.Comment,
- Buttons = rom.Machine.Buttons,
+ Extra = rom.Machine?.Comment,
+ Buttons = rom.Machine?.Buttons,
// TODO: Add extended fields
};
return row;
diff --git a/SabreTools.DatFiles/Formats/ClrMamePro.Reader.cs b/SabreTools.DatFiles/Formats/ClrMamePro.Reader.cs
index a8d9e449..d67099a5 100644
--- a/SabreTools.DatFiles/Formats/ClrMamePro.Reader.cs
+++ b/SabreTools.DatFiles/Formats/ClrMamePro.Reader.cs
@@ -571,7 +571,7 @@ namespace SabreTools.DatFiles.Formats
var item = new DipSwitch
{
Name = dipswitch.Name,
- Values = new List(),
+ Values = new List(),
Source = new Source
{
@@ -582,13 +582,13 @@ namespace SabreTools.DatFiles.Formats
foreach (string entry in dipswitch.Entry ?? Array.Empty())
{
- var setting = new Setting
+ var dipValue = new DipValue
{
Name = dipswitch.Name,
Value = entry,
Default = entry == dipswitch.Default,
};
- item.Values.Add(setting);
+ item.Values.Add(dipValue);
}
item.CopyMachineInformation(machine);
diff --git a/SabreTools.DatFiles/Formats/ClrMamePro.Writer.cs b/SabreTools.DatFiles/Formats/ClrMamePro.Writer.cs
index e68fb5d1..85be11af 100644
--- a/SabreTools.DatFiles/Formats/ClrMamePro.Writer.cs
+++ b/SabreTools.DatFiles/Formats/ClrMamePro.Writer.cs
@@ -232,14 +232,14 @@ namespace SabreTools.DatFiles.Formats
// We normalize to all "game"
var game = new Models.ClrMamePro.Game
{
- Name = machine.Name,
- Description = machine.Description,
- Year = machine.Year,
- Manufacturer = machine.Manufacturer,
- Category = machine.Category,
- CloneOf = machine.CloneOf,
- RomOf = machine.RomOf,
- SampleOf = machine.SampleOf,
+ Name = machine?.Name,
+ Description = machine?.Description,
+ Year = machine?.Year,
+ Manufacturer = machine?.Manufacturer,
+ Category = machine?.Category,
+ CloneOf = machine?.CloneOf,
+ RomOf = machine?.RomOf,
+ SampleOf = machine?.SampleOf,
};
// Create holders for all item types
@@ -535,7 +535,7 @@ namespace SabreTools.DatFiles.Formats
};
if (item.ControlsSpecified)
- input.Buttons = item.Controls[0].Buttons?.ToString();
+ input.Buttons = item.Controls![0].Buttons?.ToString();
return input;
}
@@ -553,9 +553,9 @@ namespace SabreTools.DatFiles.Formats
if (item.ValuesSpecified)
{
var entries = new List();
- foreach (var setting in item.Values)
+ foreach (var setting in item.Values!)
{
- entries.Add(setting.Value);
+ entries.Add(setting.Value!);
if (setting.Default == true)
dipswitch.Default = setting.Value;
}
diff --git a/SabreTools.DatFiles/Formats/DosCenter.Writer.cs b/SabreTools.DatFiles/Formats/DosCenter.Writer.cs
index dec0996c..a1d163b1 100644
--- a/SabreTools.DatFiles/Formats/DosCenter.Writer.cs
+++ b/SabreTools.DatFiles/Formats/DosCenter.Writer.cs
@@ -134,7 +134,7 @@ namespace SabreTools.DatFiles.Formats
// We re-add the missing parts of the game name
var game = new Models.DosCenter.Game
{
- Name = $"\"{machine.Name}.zip\""
+ Name = $"\"{machine?.Name ?? string.Empty}.zip\""
};
// Create holders for all item types
diff --git a/SabreTools.DatFiles/Formats/EverdriveSMDB.Writer.cs b/SabreTools.DatFiles/Formats/EverdriveSMDB.Writer.cs
index 3bd6133f..3bdcf9f0 100644
--- a/SabreTools.DatFiles/Formats/EverdriveSMDB.Writer.cs
+++ b/SabreTools.DatFiles/Formats/EverdriveSMDB.Writer.cs
@@ -139,7 +139,7 @@ namespace SabreTools.DatFiles.Formats
var row = new Models.EverdriveSMDB.Row
{
SHA256 = rom.SHA256,
- Name = $"{rom.Machine.Name}/{rom.Name}",
+ Name = $"{rom.Machine?.Name ?? string.Empty}/{rom.Name}",
SHA1 = rom.SHA1,
MD5 = rom.MD5,
CRC32 = rom.CRC,
diff --git a/SabreTools.DatFiles/Formats/Listrom.Writer.cs b/SabreTools.DatFiles/Formats/Listrom.Writer.cs
index c4c70ca1..02b8c698 100644
--- a/SabreTools.DatFiles/Formats/Listrom.Writer.cs
+++ b/SabreTools.DatFiles/Formats/Listrom.Writer.cs
@@ -116,8 +116,8 @@ namespace SabreTools.DatFiles.Formats
var set = new Models.Listrom.Set
{
- Driver = !items[0].Machine.MachineType.HasFlag(MachineType.Device) ? items[0].Machine.Name : null,
- Device = items[0].Machine.MachineType.HasFlag(MachineType.Device) ? items[0].Machine.Name : null,
+ Driver = items[0]!.Machine!.MachineType.HasFlag(MachineType.Device) ? items[0]!.Machine!.Name : null,
+ Device = items[0]!.Machine!.MachineType.HasFlag(MachineType.Device) ? items[0]!.Machine!.Name : null,
};
// Loop through and convert the items to respective lists
diff --git a/SabreTools.DatFiles/Formats/Listxml.Reader.cs b/SabreTools.DatFiles/Formats/Listxml.Reader.cs
index d86eac52..a2d5dab4 100644
--- a/SabreTools.DatFiles/Formats/Listxml.Reader.cs
+++ b/SabreTools.DatFiles/Formats/Listxml.Reader.cs
@@ -615,10 +615,10 @@ namespace SabreTools.DatFiles.Formats
item.Conditions = new List { condition };
}
- var locations = new List();
+ var locations = new List();
foreach (var diplocation in dipswitch.DipLocation ?? Array.Empty())
{
- var locationItem = new Location
+ var locationItem = new DipLocation
{
Name = diplocation.Name,
Number = NumberHelper.ConvertToInt64(diplocation.Number),
@@ -630,10 +630,10 @@ namespace SabreTools.DatFiles.Formats
if (locations.Any())
item.Locations = locations;
- var settings = new List();
+ var settings = new List();
foreach (var dipvalue in dipswitch.DipValue ?? Array.Empty())
{
- var settingItem = new Setting
+ var dipValueItem = new DipValue
{
Name = dipvalue.Name,
Value = dipvalue.Value,
@@ -649,10 +649,10 @@ namespace SabreTools.DatFiles.Formats
Relation = dipvalue.Condition.Relation.AsRelation(),
Value = dipvalue.Condition.Value,
};
- settingItem.Conditions = new List { condition };
+ dipValueItem.Conditions = new List { condition };
}
- settings.Add(settingItem);
+ settings.Add(dipValueItem);
}
if (settings.Any())
@@ -696,20 +696,20 @@ namespace SabreTools.DatFiles.Formats
if (configuration.Condition != null)
{
- var condition = new Condition
+ var condition = new DatItems.Formats.Condition
{
Tag = configuration.Condition.Tag,
Mask = configuration.Condition.Mask,
Relation = configuration.Condition.Relation.AsRelation(),
Value = configuration.Condition.Value,
};
- item.Conditions = new List { condition };
+ item.Conditions = new List { condition };
}
- var locations = new List();
+ var locations = new List();
foreach (var confLocation in configuration.ConfLocation ?? Array.Empty())
{
- var locationItem = new Location
+ var locationItem = new ConfLocation
{
Name = confLocation.Name,
Number = NumberHelper.ConvertToInt64(confLocation.Number),
@@ -721,10 +721,10 @@ namespace SabreTools.DatFiles.Formats
if (locations.Any())
item.Locations = locations;
- var settings = new List();
+ var settings = new List();
foreach (var dipvalue in configuration.ConfSetting ?? Array.Empty())
{
- var settingItem = new Setting
+ var settingItem = new ConfSetting
{
Name = dipvalue.Name,
Value = dipvalue.Value,
@@ -1094,6 +1094,7 @@ namespace SabreTools.DatFiles.Formats
{
Name = ramoption.Name,
Default = ramoption.Default.AsYesNo(),
+ Content = ramoption.Content,
Source = new Source
{
diff --git a/SabreTools.DatFiles/Formats/Listxml.Writer.cs b/SabreTools.DatFiles/Formats/Listxml.Writer.cs
index 7c9a5da2..92fb166a 100644
--- a/SabreTools.DatFiles/Formats/Listxml.Writer.cs
+++ b/SabreTools.DatFiles/Formats/Listxml.Writer.cs
@@ -244,7 +244,7 @@ namespace SabreTools.DatFiles.Formats
// Get the first item for game information
var machine = items[0].Machine;
- var game = CreateGame(machine);
+ var game = CreateGame(machine!);
// Create holders for all item types
var biosSets = new List();
@@ -604,19 +604,19 @@ namespace SabreTools.DatFiles.Formats
if (item.ConditionsSpecified)
{
- var conditionItem = item.Conditions[0];
+ var conditionItem = item.Conditions?.FirstOrDefault();
var condition = new Models.Listxml.Condition
{
- Tag = conditionItem.Tag,
- Mask = conditionItem.Mask,
- Relation = conditionItem.Relation.FromRelation(),
- Value = conditionItem.Value,
+ Tag = conditionItem?.Tag,
+ Mask = conditionItem?.Mask,
+ Relation = conditionItem?.Relation.FromRelation(),
+ Value = conditionItem?.Value,
};
dipswitch.Condition = condition;
}
var diplocations = new List();
- foreach (var locationItem in item.Locations ?? new List())
+ foreach (var locationItem in item.Locations ?? new List())
{
var control = CreateDipLocation(locationItem);
diplocations.Add(control);
@@ -626,9 +626,9 @@ namespace SabreTools.DatFiles.Formats
dipswitch.DipLocation = diplocations.ToArray();
var dipvalues = new List();
- foreach (var settingItem in item.Values ?? new List())
+ foreach (var dipValueItem in item.Values ?? new List())
{
- var dipvalue = CreateDipValue(settingItem);
+ var dipvalue = CreateDipValue(dipValueItem);
dipvalues.Add(dipvalue);
}
@@ -639,9 +639,9 @@ namespace SabreTools.DatFiles.Formats
}
///
- /// Create a DipLocation from the current Location DatItem
+ /// Create a DipLocation from the current DipLocation DatItem
///
- private static Models.Listxml.DipLocation CreateDipLocation(Location item)
+ private static Models.Listxml.DipLocation CreateDipLocation(DipLocation item)
{
var diplocation = new Models.Listxml.DipLocation
{
@@ -654,9 +654,9 @@ namespace SabreTools.DatFiles.Formats
}
///
- /// Create a DipValue from the current Setting DatItem
+ /// Create a DipValue from the current DipValue DatItem
///
- private static Models.Listxml.DipValue CreateDipValue(Setting item)
+ private static Models.Listxml.DipValue CreateDipValue(DipValue item)
{
var dipvalue = new Models.Listxml.DipValue
{
@@ -667,13 +667,13 @@ namespace SabreTools.DatFiles.Formats
if (item.ConditionsSpecified)
{
- var conditionItem = item.Conditions[0];
+ var conditionItem = item.Conditions?.FirstOrDefault();
var condition = new Models.Listxml.Condition
{
- Tag = conditionItem.Tag,
- Mask = conditionItem.Mask,
- Relation = conditionItem.Relation.FromRelation(),
- Value = conditionItem.Value,
+ Tag = conditionItem?.Tag,
+ Mask = conditionItem?.Mask,
+ Relation = conditionItem?.Relation.FromRelation(),
+ Value = conditionItem?.Value,
};
dipvalue.Condition = condition;
}
@@ -695,19 +695,19 @@ namespace SabreTools.DatFiles.Formats
if (item.ConditionsSpecified)
{
- var conditionItem = item.Conditions[0];
+ var conditionItem = item.Conditions?.FirstOrDefault();
var condition = new Models.Listxml.Condition
{
- Tag = conditionItem.Tag,
- Mask = conditionItem.Mask,
- Relation = conditionItem.Relation.FromRelation(),
- Value = conditionItem.Value,
+ Tag = conditionItem?.Tag,
+ Mask = conditionItem?.Mask,
+ Relation = conditionItem?.Relation.FromRelation(),
+ Value = conditionItem?.Value,
};
configuration.Condition = condition;
}
var confLocations = new List();
- foreach (var location in item.Locations ?? new List())
+ foreach (var location in item.Locations ?? new List())
{
var control = CreateConfLocation(location);
confLocations.Add(control);
@@ -717,9 +717,9 @@ namespace SabreTools.DatFiles.Formats
configuration.ConfLocation = confLocations.ToArray();
var confsettings = new List();
- foreach (var settingItem in item.Settings ?? new List())
+ foreach (var confSettingItem in item.Settings ?? new List())
{
- var dipvalue = CreateConfSetting(settingItem);
+ var dipvalue = CreateConfSetting(confSettingItem);
confsettings.Add(dipvalue);
}
@@ -730,9 +730,9 @@ namespace SabreTools.DatFiles.Formats
}
///
- /// Create a ConfLocation from the current Location DatItem
+ /// Create a ConfLocation from the current ConfLocation DatItem
///
- private static Models.Listxml.ConfLocation CreateConfLocation(Location item)
+ private static Models.Listxml.ConfLocation CreateConfLocation(ConfLocation item)
{
var conflocation = new Models.Listxml.ConfLocation
{
@@ -745,9 +745,9 @@ namespace SabreTools.DatFiles.Formats
}
///
- /// Create a ConfSetting from the current Setting DatItem
+ /// Create a ConfSetting from the current ConfSetting DatItem
///
- private static Models.Listxml.ConfSetting CreateConfSetting(Setting item)
+ private static Models.Listxml.ConfSetting CreateConfSetting(ConfSetting item)
{
var confsetting = new Models.Listxml.ConfSetting
{
@@ -758,13 +758,13 @@ namespace SabreTools.DatFiles.Formats
if (item.ConditionsSpecified)
{
- var conditionItem = item.Conditions[0];
+ var conditionItem = item.Conditions?.FirstOrDefault();
var condition = new Models.Listxml.Condition
{
- Tag = conditionItem.Tag,
- Mask = conditionItem.Mask,
- Relation = conditionItem.Relation.FromRelation(),
- Value = conditionItem.Value,
+ Tag = conditionItem?.Tag,
+ Mask = conditionItem?.Mask,
+ Relation = conditionItem?.Relation.FromRelation(),
+ Value = conditionItem?.Value,
};
confsetting.Condition = condition;
}
@@ -798,13 +798,13 @@ namespace SabreTools.DatFiles.Formats
if (item.ConditionsSpecified)
{
- var conditionItem = item.Conditions[0];
+ var conditionItem = item.Conditions?.FirstOrDefault();
var condition = new Models.Listxml.Condition
{
- Tag = conditionItem.Tag,
- Mask = conditionItem.Mask,
- Relation = conditionItem.Relation.FromRelation(),
- Value = conditionItem.Value,
+ Tag = conditionItem?.Tag,
+ Mask = conditionItem?.Mask,
+ Relation = conditionItem?.Relation.FromRelation(),
+ Value = conditionItem?.Value,
};
adjuster.Condition = condition;
}
@@ -866,11 +866,11 @@ namespace SabreTools.DatFiles.Formats
if (item.InstancesSpecified)
{
- var instanceItem = item.Instances[0];
+ var instanceItem = item.Instances?.FirstOrDefault();
var instance = new Models.Listxml.Instance
{
- Name = instanceItem.Name,
- BriefName = instanceItem.BriefName,
+ Name = instanceItem?.Name,
+ BriefName = instanceItem?.BriefName,
};
device.Instance = instance;
}
@@ -944,6 +944,7 @@ namespace SabreTools.DatFiles.Formats
{
Name = item.Name,
Default = item.Default.FromYesNo(),
+ Content = item.Content,
};
return softwarelist;
diff --git a/SabreTools.DatFiles/Formats/Logiqx.Writer.cs b/SabreTools.DatFiles/Formats/Logiqx.Writer.cs
index 20193809..166735f4 100644
--- a/SabreTools.DatFiles/Formats/Logiqx.Writer.cs
+++ b/SabreTools.DatFiles/Formats/Logiqx.Writer.cs
@@ -303,7 +303,7 @@ namespace SabreTools.DatFiles.Formats
// Get the first item for game information
var machine = items[0].Machine;
- var game = CreateGame(machine);
+ var game = CreateGame(machine!);
// Create holders for all item types
var releases = new List();
diff --git a/SabreTools.DatFiles/Formats/Missfile.Writer.cs b/SabreTools.DatFiles/Formats/Missfile.Writer.cs
index 393d2aa7..24d44448 100644
--- a/SabreTools.DatFiles/Formats/Missfile.Writer.cs
+++ b/SabreTools.DatFiles/Formats/Missfile.Writer.cs
@@ -63,7 +63,7 @@ namespace SabreTools.DatFiles.Formats
WriteDatItem(sw, datItem, lastgame);
// Set the new data to compare against
- lastgame = datItem.Machine.Name;
+ lastgame = datItem.Machine?.Name;
}
}
@@ -94,8 +94,8 @@ namespace SabreTools.DatFiles.Formats
// Romba mode automatically uses item name
if (Header.OutputDepot?.IsActive == true || Header.UseRomName)
sw.Write($"{datItem.GetName() ?? string.Empty}\n");
- else if (!Header.UseRomName && datItem.Machine.Name != lastgame)
- sw.Write($"{datItem.Machine.Name}\n");
+ else if (!Header.UseRomName && datItem.Machine?.Name != lastgame)
+ sw.Write($"{datItem.Machine?.Name ?? string.Empty}\n");
sw.Flush();
}
diff --git a/SabreTools.DatFiles/Formats/OfflineList.Writer.cs b/SabreTools.DatFiles/Formats/OfflineList.Writer.cs
index da966a8a..b5e0b3b8 100644
--- a/SabreTools.DatFiles/Formats/OfflineList.Writer.cs
+++ b/SabreTools.DatFiles/Formats/OfflineList.Writer.cs
@@ -321,7 +321,7 @@ namespace SabreTools.DatFiles.Formats
// Get the first item for game information
var machine = items[0].Machine;
- var game = CreateGame(machine);
+ var game = CreateGame(machine!);
// Create holders for all item types
var romCRCs = new List();
diff --git a/SabreTools.DatFiles/Formats/OpenMSX.Writer.cs b/SabreTools.DatFiles/Formats/OpenMSX.Writer.cs
index 2ae7d05e..10f847da 100644
--- a/SabreTools.DatFiles/Formats/OpenMSX.Writer.cs
+++ b/SabreTools.DatFiles/Formats/OpenMSX.Writer.cs
@@ -105,12 +105,12 @@ namespace SabreTools.DatFiles.Formats
var machine = items[0].Machine;
var software = new Models.OpenMSX.Software
{
- Title = machine.Name,
- GenMSXID = machine.GenMSXID,
- System = machine.System,
- Company = machine.Manufacturer,
- Year = machine.Year,
- Country = machine.Country,
+ Title = machine?.Name,
+ GenMSXID = machine?.GenMSXID,
+ System = machine?.System,
+ Company = machine?.Manufacturer,
+ Year = machine?.Year,
+ Country = machine?.Country,
};
// Create holder for dumps
diff --git a/SabreTools.DatFiles/Formats/RomCenter.Writer.cs b/SabreTools.DatFiles/Formats/RomCenter.Writer.cs
index aeabd613..e98f6bc8 100644
--- a/SabreTools.DatFiles/Formats/RomCenter.Writer.cs
+++ b/SabreTools.DatFiles/Formats/RomCenter.Writer.cs
@@ -183,14 +183,14 @@ namespace SabreTools.DatFiles.Formats
{
var rom = new Models.RomCenter.Rom
{
- ParentName = item.Machine.CloneOf,
- //ParentDescription = item.Machine.CloneOfDescription, // TODO: Add to internal model or find mapping
- GameName = item.Machine.Name,
- GameDescription = item.Machine.Description,
+ ParentName = item.Machine?.CloneOf,
+ //ParentDescription = item.Machine?.CloneOfDescription, // TODO: Add to internal model or find mapping
+ GameName = item.Machine?.Name,
+ GameDescription = item.Machine?.Description,
RomName = item.Name,
RomCRC = item.CRC,
RomSize = item.Size?.ToString(),
- RomOf = item.Machine.RomOf,
+ RomOf = item.Machine?.RomOf,
MergeName = item.MergeTag,
};
return rom;
diff --git a/SabreTools.DatFiles/Formats/SabreJSON.cs b/SabreTools.DatFiles/Formats/SabreJSON.cs
index cef8f4f0..7fb68288 100644
--- a/SabreTools.DatFiles/Formats/SabreJSON.cs
+++ b/SabreTools.DatFiles/Formats/SabreJSON.cs
@@ -235,6 +235,12 @@ namespace SabreTools.DatFiles.Formats
case ItemType.Configuration:
datItem = datItemObj.ToObject();
break;
+ case ItemType.ConfLocation:
+ datItem = datItemObj.ToObject();
+ break;
+ case ItemType.ConfSetting:
+ datItem = datItemObj.ToObject();
+ break;
case ItemType.Control:
datItem = datItemObj.ToObject();
break;
@@ -247,6 +253,12 @@ namespace SabreTools.DatFiles.Formats
case ItemType.DeviceReference:
datItem = datItemObj.ToObject();
break;
+ case ItemType.DipLocation:
+ datItem = datItemObj.ToObject();
+ break;
+ case ItemType.DipValue:
+ datItem = datItemObj.ToObject();
+ break;
case ItemType.DipSwitch:
datItem = datItemObj.ToObject();
break;
@@ -277,9 +289,6 @@ namespace SabreTools.DatFiles.Formats
case ItemType.Instance:
datItem = datItemObj.ToObject();
break;
- case ItemType.Location:
- datItem = datItemObj.ToObject();
- break;
case ItemType.Media:
datItem = datItemObj.ToObject();
break;
@@ -310,9 +319,6 @@ namespace SabreTools.DatFiles.Formats
case ItemType.Serials:
datItem = datItemObj.ToObject();
break;
- case ItemType.Setting:
- datItem = datItemObj.ToObject();
- break;
case ItemType.SharedFeature:
datItem = datItemObj.ToObject();
break;
@@ -389,11 +395,11 @@ namespace SabreTools.DatFiles.Formats
DatItem datItem = datItems[index];
// If we have a different game and we're not at the start of the list, output the end of last item
- if (lastgame != null && lastgame.ToLowerInvariant() != datItem.Machine.Name.ToLowerInvariant())
+ if (lastgame != null && lastgame.ToLowerInvariant() != datItem.Machine?.Name?.ToLowerInvariant())
WriteEndGame(jtw);
// If we have a new game, output the beginning of the new item
- if (lastgame == null || lastgame.ToLowerInvariant() != datItem.Machine.Name.ToLowerInvariant())
+ if (lastgame == null || lastgame.ToLowerInvariant() != datItem.Machine?.Name?.ToLowerInvariant())
WriteStartGame(jtw, datItem);
// Check for a "null" item
@@ -404,7 +410,7 @@ namespace SabreTools.DatFiles.Formats
WriteDatItem(jtw, datItem);
// Set the new data to compare against
- lastgame = datItem.Machine.Name;
+ lastgame = datItem.Machine?.Name;
}
}
@@ -451,7 +457,8 @@ namespace SabreTools.DatFiles.Formats
private void WriteStartGame(JsonTextWriter jtw, DatItem datItem)
{
// No game should start with a path separator
- datItem.Machine.Name = datItem.Machine.Name.TrimStart(Path.DirectorySeparatorChar) ?? string.Empty;
+ if (!string.IsNullOrWhiteSpace(datItem.Machine?.Name))
+ datItem.Machine.Name = datItem.Machine.Name.TrimStart(Path.DirectorySeparatorChar) ?? string.Empty;
// Build the state
jtw.WriteStartObject();
diff --git a/SabreTools.DatFiles/Formats/SabreXML.cs b/SabreTools.DatFiles/Formats/SabreXML.cs
index 92414ffc..67c49c3f 100644
--- a/SabreTools.DatFiles/Formats/SabreXML.cs
+++ b/SabreTools.DatFiles/Formats/SabreXML.cs
@@ -223,11 +223,11 @@ namespace SabreTools.DatFiles.Formats
DatItem datItem = datItems[index];
// If we have a different game and we're not at the start of the list, output the end of last item
- if (lastgame != null && lastgame.ToLowerInvariant() != datItem.Machine.Name.ToLowerInvariant())
+ if (lastgame != null && lastgame.ToLowerInvariant() != datItem.Machine?.Name?.ToLowerInvariant())
WriteEndGame(xtw);
// If we have a new game, output the beginning of the new item
- if (lastgame == null || lastgame.ToLowerInvariant() != datItem.Machine.Name.ToLowerInvariant())
+ if (lastgame == null || lastgame.ToLowerInvariant() != datItem.Machine?.Name?.ToLowerInvariant())
WriteStartGame(xtw, datItem);
// Check for a "null" item
@@ -238,7 +238,7 @@ namespace SabreTools.DatFiles.Formats
WriteDatItem(xtw, datItem);
// Set the new data to compare against
- lastgame = datItem.Machine.Name;
+ lastgame = datItem.Machine?.Name;
}
}
@@ -286,7 +286,7 @@ namespace SabreTools.DatFiles.Formats
private void WriteStartGame(XmlTextWriter xtw, DatItem datItem)
{
// No game should start with a path separator
- datItem.Machine.Name = datItem.Machine.Name?.TrimStart(Path.DirectorySeparatorChar) ?? string.Empty;
+ datItem.Machine!.Name = datItem.Machine.Name?.TrimStart(Path.DirectorySeparatorChar) ?? string.Empty;
// Write the machine
xtw.WriteStartElement("directory");
diff --git a/SabreTools.DatFiles/Formats/SeparatedValue.Writer.cs b/SabreTools.DatFiles/Formats/SeparatedValue.Writer.cs
index 8540a9b6..d59d46b8 100644
--- a/SabreTools.DatFiles/Formats/SeparatedValue.Writer.cs
+++ b/SabreTools.DatFiles/Formats/SeparatedValue.Writer.cs
@@ -162,8 +162,8 @@ namespace SabreTools.DatFiles.Formats
FileName = Header.FileName,
InternalName = Header.Name,
Description = Header.Description,
- GameName = disk.Machine.Name,
- GameDescription = disk.Machine.Description,
+ GameName = disk.Machine?.Name,
+ GameDescription = disk.Machine?.Description,
Type = disk.ItemType.FromItemType(),
RomName = string.Empty,
DiskName = disk.Name,
@@ -190,8 +190,8 @@ namespace SabreTools.DatFiles.Formats
FileName = Header.FileName,
InternalName = Header.Name,
Description = Header.Description,
- GameName = media.Machine.Name,
- GameDescription = media.Machine.Description,
+ GameName = media.Machine?.Name,
+ GameDescription = media.Machine?.Description,
Type = media.ItemType.FromItemType(),
RomName = string.Empty,
DiskName = media.Name,
@@ -218,8 +218,8 @@ namespace SabreTools.DatFiles.Formats
FileName = Header.FileName,
InternalName = Header.Name,
Description = Header.Description,
- GameName = rom.Machine.Name,
- GameDescription = rom.Machine.Description,
+ GameName = rom.Machine?.Name,
+ GameDescription = rom.Machine?.Description,
Type = rom.ItemType.FromItemType(),
RomName = rom.Name,
DiskName = string.Empty,
diff --git a/SabreTools.DatFiles/Formats/SoftwareList.Reader.cs b/SabreTools.DatFiles/Formats/SoftwareList.Reader.cs
index 047184c9..dffe9962 100644
--- a/SabreTools.DatFiles/Formats/SoftwareList.Reader.cs
+++ b/SabreTools.DatFiles/Formats/SoftwareList.Reader.cs
@@ -418,7 +418,7 @@ namespace SabreTools.DatFiles.Formats
Name = dipswitch.Name,
Tag = dipswitch.Tag,
Mask = dipswitch.Mask,
- Values = CreateSettings(dipswitch.DipValue, machine, filename, indexId),
+ Values = CreateDipValues(dipswitch.DipValue, machine, filename, indexId),
Part = part,
@@ -441,16 +441,16 @@ namespace SabreTools.DatFiles.Formats
/// Prefilled machine to use
/// Name of the file to be parsed
/// Index ID for the DAT
- private static List? CreateSettings(Models.SoftwareList.DipValue[]? dipvalues, Machine machine, string filename, int indexId)
+ private static List? CreateDipValues(Models.SoftwareList.DipValue[]? dipvalues, Machine machine, string filename, int indexId)
{
// If the feature array is missing, we can't do anything
if (dipvalues == null || !dipvalues.Any())
return null;
- var settings = new List();
+ var settings = new List();
foreach (var dipvalue in dipvalues)
{
- var item = new Setting
+ var item = new DipValue
{
Name = dipvalue.Name,
Value = dipvalue.Value,
diff --git a/SabreTools.DatFiles/Formats/SoftwareList.Writer.cs b/SabreTools.DatFiles/Formats/SoftwareList.Writer.cs
index dcea6fcd..2063fbfd 100644
--- a/SabreTools.DatFiles/Formats/SoftwareList.Writer.cs
+++ b/SabreTools.DatFiles/Formats/SoftwareList.Writer.cs
@@ -41,7 +41,7 @@ namespace SabreTools.DatFiles.Formats
}
else
{
- if (string.IsNullOrWhiteSpace(dipSwitch.Part.Name))
+ if (string.IsNullOrWhiteSpace(dipSwitch.Part!.Name))
missingFields.Add(DatItemField.Part_Name);
if (string.IsNullOrWhiteSpace(dipSwitch.Part.Interface))
missingFields.Add(DatItemField.Part_Interface);
@@ -54,9 +54,9 @@ namespace SabreTools.DatFiles.Formats
missingFields.Add(DatItemField.Mask);
if (dipSwitch.ValuesSpecified)
{
- if (dipSwitch.Values.Any(dv => string.IsNullOrWhiteSpace(dv.Name)))
+ if (dipSwitch.Values!.Any(dv => string.IsNullOrWhiteSpace(dv.Name)))
missingFields.Add(DatItemField.Part_Feature_Name);
- if (dipSwitch.Values.Any(dv => string.IsNullOrWhiteSpace(dv.Value)))
+ if (dipSwitch.Values!.Any(dv => string.IsNullOrWhiteSpace(dv.Value)))
missingFields.Add(DatItemField.Part_Feature_Value);
}
@@ -70,7 +70,7 @@ namespace SabreTools.DatFiles.Formats
}
else
{
- if (string.IsNullOrWhiteSpace(disk.Part.Name))
+ if (string.IsNullOrWhiteSpace(disk.Part!.Name))
missingFields.Add(DatItemField.Part_Name);
if (string.IsNullOrWhiteSpace(disk.Part.Interface))
missingFields.Add(DatItemField.Part_Interface);
@@ -81,7 +81,7 @@ namespace SabreTools.DatFiles.Formats
}
else
{
- if (string.IsNullOrWhiteSpace(disk.DiskArea.Name))
+ if (string.IsNullOrWhiteSpace(disk.DiskArea!.Name))
missingFields.Add(DatItemField.AreaName);
}
if (string.IsNullOrWhiteSpace(disk.Name))
@@ -101,7 +101,7 @@ namespace SabreTools.DatFiles.Formats
}
else
{
- if (string.IsNullOrWhiteSpace(rom.Part.Name))
+ if (string.IsNullOrWhiteSpace(rom.Part!.Name))
missingFields.Add(DatItemField.Part_Name);
if (string.IsNullOrWhiteSpace(rom.Part.Interface))
missingFields.Add(DatItemField.Part_Interface);
@@ -113,7 +113,7 @@ namespace SabreTools.DatFiles.Formats
}
else
{
- if (string.IsNullOrWhiteSpace(rom.DataArea.Name))
+ if (string.IsNullOrWhiteSpace(rom.DataArea!.Name))
missingFields.Add(DatItemField.AreaName);
if (!rom.DataArea.SizeSpecified)
missingFields.Add(DatItemField.AreaSize);
@@ -197,7 +197,7 @@ namespace SabreTools.DatFiles.Formats
// Get the first item for game information
var machine = items[0].Machine;
- var sw = CreateSoftware(machine);
+ var sw = CreateSoftware(machine!);
// Create holders for all item types
var infos = new List();
@@ -304,9 +304,9 @@ namespace SabreTools.DatFiles.Formats
{
var part = new Models.SoftwareList.Part
{
- Name = item.Part.Name,
- Interface = item.Part.Interface,
- Feature = CreateFeatures(item.Part.Features),
+ Name = item.Part?.Name,
+ Interface = item.Part?.Interface,
+ Feature = CreateFeatures(item.Part?.Features),
DataArea = CreateDataAreas(item),
DiskArea = null,
DipSwitch = null,
@@ -321,9 +321,9 @@ namespace SabreTools.DatFiles.Formats
{
var part = new Models.SoftwareList.Part
{
- Name = item.Part.Name,
- Interface = item.Part.Interface,
- Feature = CreateFeatures(item.Part.Features),
+ Name = item.Part?.Name,
+ Interface = item.Part?.Interface,
+ Feature = CreateFeatures(item.Part?.Features),
DataArea = null,
DiskArea = CreateDiskAreas(item),
DipSwitch = null,
@@ -338,9 +338,9 @@ namespace SabreTools.DatFiles.Formats
{
var part = new Models.SoftwareList.Part
{
- Name = item.Part.Name,
- Interface = item.Part.Interface,
- Feature = CreateFeatures(item.Part.Features),
+ Name = item.Part?.Name,
+ Interface = item.Part?.Interface,
+ Feature = CreateFeatures(item.Part?.Features),
DataArea = null,
DiskArea = null,
DipSwitch = CreateDipSwitches(item),
@@ -351,7 +351,7 @@ namespace SabreTools.DatFiles.Formats
///
/// Create a Feature array from the current list of PartFeature DatItems
///
- private static Models.SoftwareList.Feature[]? CreateFeatures(List items)
+ private static Models.SoftwareList.Feature[]? CreateFeatures(List? items)
{
// If we don't have features, we can't do anything
if (items == null || !items.Any())
@@ -378,10 +378,10 @@ namespace SabreTools.DatFiles.Formats
{
var dataArea = new Models.SoftwareList.DataArea
{
- Name = item.DataArea.Name,
- Size = item.DataArea.Size?.ToString(),
- Width = item.DataArea.Width?.ToString(),
- Endianness = item.DataArea.Endianness.FromEndianness(),
+ Name = item.DataArea?.Name,
+ Size = item.DataArea?.Size?.ToString(),
+ Width = item.DataArea?.Width?.ToString(),
+ Endianness = item.DataArea?.Endianness.FromEndianness(),
Rom = CreateRom(item),
};
return new Models.SoftwareList.DataArea[] { dataArea };
@@ -441,7 +441,7 @@ namespace SabreTools.DatFiles.Formats
private static Models.SoftwareList.DipSwitch[]? CreateDipSwitches(DipSwitch item)
{
var dipValues = new List();
- foreach (var setting in item.Values ?? new List())
+ foreach (var setting in item.Values ?? new List())
{
var dipValue = new Models.SoftwareList.DipValue
{
diff --git a/SabreTools.DatFiles/Setter.cs b/SabreTools.DatFiles/Setter.cs
index 8d95ce90..28d4d9f0 100644
--- a/SabreTools.DatFiles/Setter.cs
+++ b/SabreTools.DatFiles/Setter.cs
@@ -231,10 +231,14 @@ namespace SabreTools.DatFiles
case Chip chip: SetFields(chip); break;
case Condition condition: SetFields(condition); break;
case Configuration condition: SetFields(condition); break;
+ case ConfLocation confLocation: SetFields(confLocation); break;
+ case ConfSetting confSetting: SetFields(confSetting); break;
case Control control: SetFields(control); break;
case DataArea dataArea: SetFields(dataArea); break;
case Device device: SetFields(device); break;
+ case DipLocation dipLocation: SetFields(dipLocation); break;
case DipSwitch dipSwitch: SetFields(dipSwitch); break;
+ case DipValue dipValue: SetFields(dipValue); break;
case Disk disk: SetFields(disk); break;
case DiskArea diskArea: SetFields(diskArea); break;
case Display display: SetFields(display); break;
@@ -243,7 +247,6 @@ namespace SabreTools.DatFiles
case Feature feature: SetFields(feature); break;
case Input input: SetFields(input); break;
case Instance instance: SetFields(instance); break;
- case Location location: SetFields(location); break;
case Media media: SetFields(media); break;
case Part part: SetFields(part); break;
case PartFeature partFeature: SetFields(partFeature); break;
@@ -251,7 +254,6 @@ namespace SabreTools.DatFiles
case RamOption ramOption: SetFields(ramOption); break;
case Release release: SetFields(release); break;
case Rom rom: SetFields(rom); break;
- case Setting setting: SetFields(setting); break;
case SharedFeature sharedFeat: SetFields(sharedFeat); break;
case Slot slot: SetFields(slot); break;
case SlotOption slotOption: SetFields(slotOption); break;
@@ -398,7 +400,7 @@ namespace SabreTools.DatFiles
// Field.DatItem_Conditions does not apply here
if (adjuster.ConditionsSpecified)
{
- foreach (Condition subCondition in adjuster.Conditions)
+ foreach (Condition subCondition in adjuster.Conditions!)
{
SetFields(subCondition, true);
}
@@ -529,7 +531,7 @@ namespace SabreTools.DatFiles
if (configuration.ConditionsSpecified)
{
- foreach (Condition subCondition in configuration.Conditions)
+ foreach (Condition subCondition in configuration.Conditions!)
{
SetFields(subCondition, true);
}
@@ -537,7 +539,7 @@ namespace SabreTools.DatFiles
if (configuration.LocationsSpecified)
{
- foreach (Location subLocation in configuration.Locations)
+ foreach (ConfLocation subLocation in configuration.Locations!)
{
SetFields(subLocation);
}
@@ -545,13 +547,53 @@ namespace SabreTools.DatFiles
if (configuration.SettingsSpecified)
{
- foreach (Setting subSetting in configuration.Settings)
+ foreach (ConfSetting subSetting in configuration.Settings!)
{
SetFields(subSetting);
}
}
}
+ ///
+ /// Set fields with given values
+ ///
+ /// ConfLocation to remove replace fields in
+ private void SetFields(ConfLocation confLocation)
+ {
+ if (DatItemMappings!.ContainsKey(DatItemField.Location_Inverted))
+ confLocation.Inverted = DatItemMappings[DatItemField.Location_Inverted].AsYesNo();
+
+ if (DatItemMappings!.ContainsKey(DatItemField.Location_Name))
+ confLocation.Name = DatItemMappings[DatItemField.Location_Name];
+
+ if (DatItemMappings!.ContainsKey(DatItemField.Location_Number))
+ confLocation.Number = NumberHelper.ConvertToInt64(DatItemMappings[DatItemField.Location_Number]);
+ }
+
+ ///
+ /// Set fields with given values
+ ///
+ /// ConfSetting to remove replace fields in
+ private void SetFields(ConfSetting confSetting)
+ {
+ if (DatItemMappings!.ContainsKey(DatItemField.Setting_Default))
+ confSetting.Default = DatItemMappings[DatItemField.Setting_Default].AsYesNo();
+
+ if (DatItemMappings!.ContainsKey(DatItemField.Setting_Name))
+ confSetting.Name = DatItemMappings[DatItemField.Setting_Name];
+
+ if (DatItemMappings!.ContainsKey(DatItemField.Setting_Value))
+ confSetting.Value = DatItemMappings[DatItemField.Setting_Value];
+
+ if (confSetting.ConditionsSpecified)
+ {
+ foreach (Condition subCondition in confSetting.Conditions!)
+ {
+ SetFields(subCondition, true);
+ }
+ }
+ }
+
///
/// Set fields with given values
///
@@ -637,7 +679,7 @@ namespace SabreTools.DatFiles
if (device.ExtensionsSpecified)
{
- foreach (Extension subExtension in device.Extensions)
+ foreach (Extension subExtension in device.Extensions!)
{
SetFields(subExtension);
}
@@ -645,13 +687,29 @@ namespace SabreTools.DatFiles
if (device.InstancesSpecified)
{
- foreach (Instance subInstance in device.Instances)
+ foreach (Instance subInstance in device.Instances!)
{
SetFields(subInstance);
}
}
}
+ ///
+ /// Set fields with given values
+ ///
+ /// DipLocation to remove replace fields in
+ private void SetFields(DipLocation dipLocation)
+ {
+ if (DatItemMappings!.ContainsKey(DatItemField.Location_Inverted))
+ dipLocation.Inverted = DatItemMappings[DatItemField.Location_Inverted].AsYesNo();
+
+ if (DatItemMappings!.ContainsKey(DatItemField.Location_Name))
+ dipLocation.Name = DatItemMappings[DatItemField.Location_Name];
+
+ if (DatItemMappings!.ContainsKey(DatItemField.Location_Number))
+ dipLocation.Number = NumberHelper.ConvertToInt64(DatItemMappings[DatItemField.Location_Number]);
+ }
+
///
/// Set fields with given values
///
@@ -666,7 +724,7 @@ namespace SabreTools.DatFiles
if (dipSwitch.ConditionsSpecified)
{
- foreach (Condition subCondition in dipSwitch.Conditions)
+ foreach (Condition subCondition in dipSwitch.Conditions!)
{
SetFields(subCondition, true);
}
@@ -674,7 +732,7 @@ namespace SabreTools.DatFiles
if (dipSwitch.LocationsSpecified)
{
- foreach (Location subLocation in dipSwitch.Locations)
+ foreach (DipLocation subLocation in dipSwitch.Locations!)
{
SetFields(subLocation);
}
@@ -682,7 +740,7 @@ namespace SabreTools.DatFiles
if (dipSwitch.ValuesSpecified)
{
- foreach (Setting subValue in dipSwitch.Values)
+ foreach (DipValue subValue in dipSwitch.Values!)
{
SetFields(subValue);
}
@@ -692,6 +750,30 @@ namespace SabreTools.DatFiles
SetFields(dipSwitch.Part);
}
+ ///
+ /// Set fields with given values
+ ///
+ /// DipValue to remove replace fields in
+ private void SetFields(DipValue dipValue)
+ {
+ if (DatItemMappings!.ContainsKey(DatItemField.Setting_Default))
+ dipValue.Default = DatItemMappings[DatItemField.Setting_Default].AsYesNo();
+
+ if (DatItemMappings!.ContainsKey(DatItemField.Setting_Name))
+ dipValue.Name = DatItemMappings[DatItemField.Setting_Name];
+
+ if (DatItemMappings!.ContainsKey(DatItemField.Setting_Value))
+ dipValue.Value = DatItemMappings[DatItemField.Setting_Value];
+
+ if (dipValue.ConditionsSpecified)
+ {
+ foreach (Condition subCondition in dipValue.Conditions!)
+ {
+ SetFields(subCondition, true);
+ }
+ }
+ }
+
///
/// Set fields with given values
///
@@ -875,7 +957,7 @@ namespace SabreTools.DatFiles
if (input.ControlsSpecified)
{
- foreach (Control subControl in input.Controls)
+ foreach (Control subControl in input.Controls!)
{
SetFields(subControl);
}
@@ -895,22 +977,6 @@ namespace SabreTools.DatFiles
instance.BriefName = DatItemMappings[DatItemField.Instance_Name];
}
- ///
- /// Set fields with given values
- ///
- /// Location to remove replace fields in
- private void SetFields(Location location)
- {
- if (DatItemMappings!.ContainsKey(DatItemField.Location_Inverted))
- location.Inverted = DatItemMappings[DatItemField.Location_Inverted].AsYesNo();
-
- if (DatItemMappings!.ContainsKey(DatItemField.Location_Name))
- location.Name = DatItemMappings[DatItemField.Location_Name];
-
- if (DatItemMappings!.ContainsKey(DatItemField.Location_Number))
- location.Number = NumberHelper.ConvertToInt64(DatItemMappings[DatItemField.Location_Number]);
- }
-
///
/// Set fields with given values
///
@@ -944,7 +1010,7 @@ namespace SabreTools.DatFiles
if (part.FeaturesSpecified)
{
- foreach (PartFeature subPartFeature in part.Features)
+ foreach (PartFeature subPartFeature in part.Features!)
{
SetFields(subPartFeature);
}
@@ -975,7 +1041,7 @@ namespace SabreTools.DatFiles
if (port.AnalogsSpecified)
{
- foreach (Analog subAnalog in port.Analogs)
+ foreach (Analog subAnalog in port.Analogs!)
{
SetFields(subAnalog);
}
@@ -1120,30 +1186,6 @@ namespace SabreTools.DatFiles
SetFields(rom.Part);
}
- ///
- /// Set fields with given values
- ///
- /// Setting to remove replace fields in
- private void SetFields(Setting setting)
- {
- if (DatItemMappings!.ContainsKey(DatItemField.Setting_Default))
- setting.Default = DatItemMappings[DatItemField.Setting_Default].AsYesNo();
-
- if (DatItemMappings!.ContainsKey(DatItemField.Setting_Name))
- setting.Name = DatItemMappings[DatItemField.Setting_Name];
-
- if (DatItemMappings!.ContainsKey(DatItemField.Setting_Value))
- setting.Value = DatItemMappings[DatItemField.Setting_Value];
-
- if (setting.ConditionsSpecified)
- {
- foreach (Condition subCondition in setting.Conditions)
- {
- SetFields(subCondition, true);
- }
- }
- }
-
///
/// Set fields with given values
///
@@ -1162,7 +1204,7 @@ namespace SabreTools.DatFiles
{
if (slot.SlotOptionsSpecified)
{
- foreach (SlotOption subSlotOption in slot.SlotOptions)
+ foreach (SlotOption subSlotOption in slot.SlotOptions!)
{
SetFields(subSlotOption);
}
diff --git a/SabreTools.DatItems/DatItem.cs b/SabreTools.DatItems/DatItem.cs
index 199d7fbb..97db2745 100644
--- a/SabreTools.DatItems/DatItem.cs
+++ b/SabreTools.DatItems/DatItem.cs
@@ -2,15 +2,14 @@
using System.IO;
using System.Linq;
using System.Xml.Serialization;
-
+using NaturalSort;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
using SabreTools.Core;
using SabreTools.Core.Tools;
using SabreTools.DatItems.Formats;
using SabreTools.FileTypes;
using SabreTools.Logging;
-using NaturalSort;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Converters;
namespace SabreTools.DatItems
{
@@ -29,11 +28,15 @@ namespace SabreTools.DatItems
[XmlInclude(typeof(Chip))]
[XmlInclude(typeof(Condition))]
[XmlInclude(typeof(Configuration))]
+ [XmlInclude(typeof(ConfLocation))]
+ [XmlInclude(typeof(ConfSetting))]
[XmlInclude(typeof(Control))]
[XmlInclude(typeof(DataArea))]
[XmlInclude(typeof(Device))]
[XmlInclude(typeof(DeviceReference))]
+ [XmlInclude(typeof(DipLocation))]
[XmlInclude(typeof(DipSwitch))]
+ [XmlInclude(typeof(DipValue))]
[XmlInclude(typeof(Disk))]
[XmlInclude(typeof(DiskArea))]
[XmlInclude(typeof(Display))]
@@ -43,7 +46,6 @@ namespace SabreTools.DatItems
[XmlInclude(typeof(Info))]
[XmlInclude(typeof(Input))]
[XmlInclude(typeof(Instance))]
- [XmlInclude(typeof(Location))]
[XmlInclude(typeof(Media))]
[XmlInclude(typeof(Part))]
[XmlInclude(typeof(PartFeature))]
@@ -52,7 +54,6 @@ namespace SabreTools.DatItems
[XmlInclude(typeof(Release))]
[XmlInclude(typeof(Rom))]
[XmlInclude(typeof(Sample))]
- [XmlInclude(typeof(Setting))]
[XmlInclude(typeof(SharedFeature))]
[XmlInclude(typeof(Slot))]
[XmlInclude(typeof(SlotOption))]
@@ -86,7 +87,7 @@ namespace SabreTools.DatItems
/// Machine values
///
[JsonIgnore, XmlIgnore]
- public Machine Machine { get; set; } = new Machine();
+ public Machine? Machine { get; set; } = new Machine();
#endregion
@@ -96,7 +97,7 @@ namespace SabreTools.DatItems
/// Source information
///
[JsonIgnore, XmlIgnore]
- public Source Source { get; set; } = new Source();
+ public Source? Source { get; set; } = new Source();
///
/// Flag if item should be removed
@@ -132,13 +133,13 @@ namespace SabreTools.DatItems
/// Gets the name to use for a DatItem
///
/// Name if available, null otherwise
- public virtual string GetName() => null;
+ public virtual string? GetName() => null;
///
/// Sets the name to use for a DatItem
///
/// Name to set for the item
- public virtual void SetName(string name) { }
+ public virtual void SetName(string? name) { }
#endregion
@@ -169,8 +170,10 @@ namespace SabreTools.DatItems
ItemType.Chip => new Chip(),
ItemType.Condition => new Condition(),
ItemType.Configuration => new Configuration(),
+ ItemType.ConfLocation => new ConfLocation(),
ItemType.Device => new Device(),
ItemType.DeviceReference => new DeviceReference(),
+ ItemType.DipLocation => new DipLocation(),
ItemType.DipSwitch => new DipSwitch(),
ItemType.Disk => new Disk(),
ItemType.Display => new Display(),
@@ -180,7 +183,6 @@ namespace SabreTools.DatItems
ItemType.File => new Formats.File(),
ItemType.Info => new Info(),
ItemType.Instance => new Instance(),
- ItemType.Location => new Location(),
ItemType.Media => new Media(),
ItemType.PartFeature => new PartFeature(),
ItemType.Port => new Port(),
@@ -205,7 +207,7 @@ namespace SabreTools.DatItems
///
/// BaseFile containing information to be created
/// DatItem of the specific internal type that corresponds to the inputs
- public static DatItem Create(BaseFile baseFile)
+ public static DatItem? Create(BaseFile baseFile)
{
return baseFile.Type switch
{
@@ -265,14 +267,14 @@ namespace SabreTools.DatItems
#region Comparision Methods
///
- public int CompareTo(DatItem other)
+ public int CompareTo(DatItem? other)
{
try
{
- if (GetName() == other.GetName())
+ if (GetName() == other?.GetName())
return Equals(other) ? 0 : 1;
- return string.Compare(GetName(), other.GetName());
+ return string.Compare(GetName(), other?.GetName());
}
catch
{
@@ -285,14 +287,14 @@ namespace SabreTools.DatItems
///
/// DatItem to use as a baseline
/// True if the items are duplicates, false otherwise
- public abstract bool Equals(DatItem other);
+ public abstract bool Equals(DatItem? other);
///
/// Return the duplicate status of two items
///
/// DatItem to check against
/// The DupeType corresponding to the relationship between the two
- public DupeType GetDuplicateStatus(DatItem lastItem)
+ public DupeType GetDuplicateStatus(DatItem? lastItem)
{
DupeType output = 0x00;
@@ -301,9 +303,9 @@ namespace SabreTools.DatItems
return output;
// If the duplicate is external already or should be, set it
- if (lastItem.DupeType.HasFlag(DupeType.External) || lastItem.Source.Index != Source.Index)
+ if (lastItem.DupeType.HasFlag(DupeType.External) || lastItem?.Source?.Index != Source?.Index)
{
- if (lastItem.Machine.Name == Machine.Name && lastItem.GetName() == GetName())
+ if (lastItem?.Machine?.Name == Machine?.Name && lastItem?.GetName() == GetName())
output = DupeType.External | DupeType.All;
else
output = DupeType.External | DupeType.Hash;
@@ -312,7 +314,7 @@ namespace SabreTools.DatItems
// Otherwise, it's considered an internal dupe
else
{
- if (lastItem.Machine.Name == Machine.Name && lastItem.GetName() == GetName())
+ if (lastItem?.Machine?.Name == Machine?.Name && lastItem?.GetName() == GetName())
output = DupeType.Internal | DupeType.All;
else
output = DupeType.Internal | DupeType.Hash;
@@ -323,113 +325,6 @@ namespace SabreTools.DatItems
#endregion
- #region Filtering
-
- ///
- /// Clean a CRC32 string and pad to the correct size
- ///
- /// Hash string to sanitize
- /// Cleaned string
- protected static string CleanCRC32(string hash)
- {
- return CleanHashData(hash, Constants.CRCLength);
- }
-
- ///
- /// Clean a MD5 string and pad to the correct size
- ///
- /// Hash string to sanitize
- /// Cleaned string
- protected static string CleanMD5(string hash)
- {
- return CleanHashData(hash, Constants.MD5Length);
- }
-
- ///
- /// Clean a SHA1 string and pad to the correct size
- ///
- /// Hash string to sanitize
- /// Cleaned string
- protected static string CleanSHA1(string hash)
- {
- return CleanHashData(hash, Constants.SHA1Length);
- }
-
- ///
- /// Clean a SHA256 string and pad to the correct size
- ///
- /// Hash string to sanitize
- /// Cleaned string
- protected static string CleanSHA256(string hash)
- {
- return CleanHashData(hash, Constants.SHA256Length);
- }
-
- ///
- /// Clean a SHA384 string and pad to the correct size
- ///
- /// Hash string to sanitize
- /// Cleaned string
- protected static string CleanSHA384(string hash)
- {
- return CleanHashData(hash, Constants.SHA384Length);
- }
-
- ///
- /// Clean a SHA512 string and pad to the correct size
- ///
- /// Hash string to sanitize
- /// Cleaned string
- protected static string CleanSHA512(string hash)
- {
- return CleanHashData(hash, Constants.SHA512Length);
- }
-
- ///
- /// Clean a hash string and pad to the correct size
- ///
- /// Hash string to sanitize
- /// Amount of characters to pad to
- /// Cleaned string
- private static string CleanHashData(string hash, int padding)
- {
- // If we have a known blank hash, return blank
- if (string.IsNullOrWhiteSpace(hash) || hash == "-" || hash == "_")
- return string.Empty;
-
- // Check to see if it's a "hex" hash
- hash = hash.Trim().Replace("0x", string.Empty);
-
- // If we have a blank hash now, return blank
- if (string.IsNullOrWhiteSpace(hash))
- return string.Empty;
-
- // If the hash shorter than the required length, pad it
- if (hash.Length < padding)
- hash = hash.PadLeft(padding, '0');
-
- // If the hash is longer than the required length, it's invalid
- else if (hash.Length > padding)
- return string.Empty;
-
- // Now normalize the hash
- hash = hash.ToLowerInvariant();
-
- // Otherwise, make sure that every character is a proper match
- for (int i = 0; i < hash.Length; i++)
- {
- if ((hash[i] < '0' || hash[i] > '9') && (hash[i] < 'a' || hash[i] > 'f'))
- {
- hash = string.Empty;
- break;
- }
- }
-
- return hash;
- }
-
- #endregion
-
#region Sorting and Merging
///
@@ -453,9 +348,9 @@ namespace SabreTools.DatItems
case ItemKey.Machine:
key = (norename ? string.Empty
- : Source.Index.ToString().PadLeft(10, '0')
+ : Source?.Index.ToString().PadLeft(10, '0')
+ "-")
- + (string.IsNullOrWhiteSpace(Machine.Name)
+ + (string.IsNullOrWhiteSpace(Machine?.Name)
? "Default"
: Machine.Name);
if (lower)
@@ -510,14 +405,14 @@ namespace SabreTools.DatItems
/// First hash to compare
/// Second hash to compare
/// True if either is empty OR the hashes exactly match, false otherwise
- public static bool ConditionalHashEquals(byte[] firstHash, byte[] secondHash)
+ public static bool ConditionalHashEquals(byte[]? firstHash, byte[]? secondHash)
{
// If either hash is empty, we say they're equal for merging
if (firstHash.IsNullOrEmpty() || secondHash.IsNullOrEmpty())
return true;
// If they're different sizes, they can't match
- if (firstHash.Length != secondHash.Length)
+ if (firstHash!.Length != secondHash!.Length)
return false;
// Otherwise, they need to match exactly
@@ -556,13 +451,13 @@ namespace SabreTools.DatItems
}
// If it's a nodump, add and skip
- if (file.ItemType == ItemType.Rom && (file as Rom).ItemStatus == ItemStatus.Nodump)
+ if (file is Rom rom && rom.ItemStatus == ItemStatus.Nodump)
{
outfiles.Add(file);
nodumpCount++;
continue;
}
- else if (file.ItemType == ItemType.Disk && (file as Disk).ItemStatus == ItemStatus.Nodump)
+ else if (file is Disk disk && disk.ItemStatus == ItemStatus.Nodump)
{
outfiles.Add(file);
nodumpCount++;
@@ -593,19 +488,19 @@ namespace SabreTools.DatItems
pos = i;
// Disks, Media, and Roms have more information to fill
- if (file.ItemType == ItemType.Disk)
- (saveditem as Disk).FillMissingInformation(file as Disk);
- else if (file.ItemType == ItemType.File)
- (saveditem as Formats.File).FillMissingInformation(file as Formats.File);
- else if (file.ItemType == ItemType.Media)
- (saveditem as Media).FillMissingInformation(file as Media);
- else if (file.ItemType == ItemType.Rom)
- (saveditem as Rom).FillMissingInformation(file as Rom);
+ if (file is Disk disk && saveditem is Disk savedDisk)
+ savedDisk.FillMissingInformation(disk);
+ else if (file is Formats.File fileItem && saveditem is Formats.File savedFile)
+ savedFile.FillMissingInformation(fileItem);
+ else if (file is Media media && saveditem is Media savedMedia)
+ savedMedia.FillMissingInformation(media);
+ else if (file is Rom romItem && saveditem is Rom savedRom)
+ savedRom.FillMissingInformation(romItem);
saveditem.DupeType = dupetype;
// If the current system has a lower ID than the previous, set the system accordingly
- if (file.Source.Index < saveditem.Source.Index)
+ if (file.Source?.Index < saveditem.Source?.Index)
{
saveditem.Source = file.Source.Clone() as Source;
saveditem.CopyMachineInformation(file);
@@ -613,7 +508,7 @@ namespace SabreTools.DatItems
}
// 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)
+ if (saveditem.Machine?.CloneOf == file.Machine?.Name || saveditem.Machine?.RomOf == file.Machine?.Name)
{
saveditem.CopyMachineInformation(file);
saveditem.SetName(file.GetName());
@@ -654,8 +549,8 @@ namespace SabreTools.DatItems
Sort(ref infiles, true);
// Now we want to loop through and check names
- DatItem lastItem = null;
- string lastrenamed = null;
+ DatItem? lastItem = null;
+ string? lastrenamed = null;
int lastid = 0;
for (int i = 0; i < infiles.Count; i++)
{
@@ -735,16 +630,14 @@ namespace SabreTools.DatItems
///
private static string GetDuplicateSuffix(DatItem datItem)
{
- if (datItem.ItemType == ItemType.Disk)
- return (datItem as Disk).GetDuplicateSuffix();
- else if (datItem.ItemType == ItemType.File)
- return (datItem as Formats.File).GetDuplicateSuffix();
- else if (datItem.ItemType == ItemType.Media)
- return (datItem as Media).GetDuplicateSuffix();
- else if (datItem.ItemType == ItemType.Rom)
- return (datItem as Rom).GetDuplicateSuffix();
-
- return "_1";
+ return datItem switch
+ {
+ Disk disk => disk.GetDuplicateSuffix(),
+ Formats.File file => file.GetDuplicateSuffix(),
+ Media media => media.GetDuplicateSuffix(),
+ Rom rom => rom.GetDuplicateSuffix(),
+ _ => "_1",
+ };
}
///
@@ -762,23 +655,23 @@ namespace SabreTools.DatItems
NaturalComparer nc = new();
// If machine names match, more refinement is needed
- if (x.Machine.Name == y.Machine.Name)
+ if (x.Machine?.Name == y.Machine?.Name)
{
// If item types match, more refinement is needed
if (x.ItemType == y.ItemType)
{
- string xDirectoryName = Path.GetDirectoryName(TextHelper.RemovePathUnsafeCharacters(x.GetName() ?? string.Empty));
- string yDirectoryName = Path.GetDirectoryName(TextHelper.RemovePathUnsafeCharacters(y.GetName() ?? string.Empty));
+ string? xDirectoryName = Path.GetDirectoryName(TextHelper.RemovePathUnsafeCharacters(x.GetName() ?? string.Empty));
+ string? yDirectoryName = Path.GetDirectoryName(TextHelper.RemovePathUnsafeCharacters(y.GetName() ?? string.Empty));
// If item directory names match, more refinement is needed
if (xDirectoryName == yDirectoryName)
{
- string xName = Path.GetFileName(TextHelper.RemovePathUnsafeCharacters(x.GetName() ?? string.Empty));
- string yName = Path.GetFileName(TextHelper.RemovePathUnsafeCharacters(y.GetName() ?? string.Empty));
+ string? xName = Path.GetFileName(TextHelper.RemovePathUnsafeCharacters(x.GetName() ?? string.Empty));
+ string? yName = Path.GetFileName(TextHelper.RemovePathUnsafeCharacters(y.GetName() ?? string.Empty));
// If item names match, then compare on machine or source, depending on the flag
if (xName == yName)
- return (norename ? nc.Compare(x.Machine.Name, y.Machine.Name) : x.Source.Index - y.Source.Index);
+ return (norename ? nc.Compare(x.Machine?.Name, y.Machine?.Name) : (x.Source?.Index - y.Source?.Index) ?? 0);
// Otherwise, just sort based on item names
return nc.Compare(xName, yName);
@@ -793,7 +686,7 @@ namespace SabreTools.DatItems
}
// Otherwise, just sort based on machine name
- return nc.Compare(x.Machine.Name, y.Machine.Name);
+ return nc.Compare(x.Machine?.Name, y.Machine?.Name);
}
catch
{
diff --git a/SabreTools.DatItems/Formats/Adjuster.cs b/SabreTools.DatItems/Formats/Adjuster.cs
index 59346c6b..d3a47d6f 100644
--- a/SabreTools.DatItems/Formats/Adjuster.cs
+++ b/SabreTools.DatItems/Formats/Adjuster.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Linq;
using System.Xml.Serialization;
using Newtonsoft.Json;
using SabreTools.Core;
@@ -17,13 +18,21 @@ namespace SabreTools.DatItems.Formats
/// Name of the item
///
[JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _adjuster.ReadString(Models.Internal.Adjuster.NameKey);
+ set => _adjuster[Models.Internal.Adjuster.NameKey] = value;
+ }
///
/// Determine whether the value is default
///
[JsonProperty("default", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("default")]
- public bool? Default { get; set; }
+ public bool? Default
+ {
+ get => _adjuster.ReadBool(Models.Internal.Adjuster.DefaultKey);
+ set => _adjuster[Models.Internal.Adjuster.DefaultKey] = value;
+ }
[JsonIgnore]
public bool DefaultSpecified { get { return Default != null; } }
@@ -32,20 +41,30 @@ namespace SabreTools.DatItems.Formats
/// Conditions associated with the adjustment
///
[JsonProperty("conditions", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("conditions")]
- public List Conditions { get; set; }
+ public List? Conditions
+ {
+ get => _adjuster.Read(Models.Internal.Adjuster.ConditionKey)?.ToList();
+ set => _adjuster[Models.Internal.Adjuster.ConditionKey] = value?.ToArray();
+ }
[JsonIgnore]
public bool ConditionsSpecified { get { return Conditions != null && Conditions.Count > 0; } }
+ ///
+ /// Internal Adjuster model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Adjuster _adjuster = new();
+
#endregion
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -72,13 +91,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Name = this.Name,
- Default = this.Default,
- Conditions = this.Conditions,
+ _adjuster = this._adjuster?.Clone() as Models.Internal.Adjuster ?? new Models.Internal.Adjuster(),
};
}
@@ -87,31 +104,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
// If we don't have a Adjuster, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType || other is not Adjuster otherInternal)
return false;
- // Otherwise, treat it as a Adjuster
- Adjuster newOther = other as Adjuster;
-
- // If the Adjuster information matches
- bool match = (Name == newOther.Name
- && Default == newOther.Default);
- if (!match)
- return match;
-
- // If the conditions match
- if (ConditionsSpecified)
- {
- foreach (Condition condition in Conditions)
- {
- match &= newOther.Conditions.Contains(condition);
- }
- }
-
- return match;
+ // Compare the internal models
+ return _adjuster.EqualTo(otherInternal._adjuster);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/Analog.cs b/SabreTools.DatItems/Formats/Analog.cs
index 7daccaf8..b1c1cb93 100644
--- a/SabreTools.DatItems/Formats/Analog.cs
+++ b/SabreTools.DatItems/Formats/Analog.cs
@@ -16,7 +16,17 @@ namespace SabreTools.DatItems.Formats
/// Analog mask value
///
[JsonProperty("mask", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("mask")]
- public string Mask { get; set; }
+ public string? Mask
+ {
+ get => _analog.ReadString(Models.Internal.Analog.MaskKey);
+ set => _analog[Models.Internal.Analog.MaskKey] = value;
+ }
+
+ ///
+ /// Internal Analog model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Analog _analog = new();
#endregion
@@ -42,11 +52,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Mask = this.Mask,
+ _analog = this._analog?.Clone() as Models.Internal.Analog ?? new Models.Internal.Analog(),
};
}
@@ -55,17 +65,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
// If we don't have a Analog, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType || other is not Analog otherInternal)
return false;
- // Otherwise, treat it as a Analog
- Analog newOther = other as Analog;
-
- // If the Feature information matches
- return (Mask == newOther.Mask);
+ // Compare the internal models
+ return _analog.EqualTo(otherInternal._analog);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/Archive.cs b/SabreTools.DatItems/Formats/Archive.cs
index 8bdd0225..0c946f5e 100644
--- a/SabreTools.DatItems/Formats/Archive.cs
+++ b/SabreTools.DatItems/Formats/Archive.cs
@@ -16,82 +16,92 @@ namespace SabreTools.DatItems.Formats
/// Name of the item
///
[JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _archive.ReadString(Models.Internal.Archive.NameKey);
+ set => _archive[Models.Internal.Archive.NameKey] = value;
+ }
///
/// Archive ID number
///
- /// No-Intro database export only
+ /// TODO: No-Intro database export only
[JsonProperty("number"), XmlElement("number")]
- public string Number { get; set; }
+ public string? Number { get; set; }
///
/// Clone value
///
- /// No-Intro database export only
+ /// TODO: No-Intro database export only
[JsonProperty("clone"), XmlElement("clone")]
- public string CloneValue { get; set; }
+ public string? CloneValue { get; set; }
///
/// Regional parent value
///
- /// No-Intro database export only
+ /// TODO: No-Intro database export only
[JsonProperty("regparent"), XmlElement("regparent")]
- public string RegParent { get; set; }
+ public string? RegParent { get; set; }
///
/// Region value
///
- /// No-Intro database export only
+ /// TODO: No-Intro database export only
[JsonProperty("region"), XmlElement("region")]
- public string Region { get; set; }
+ public string? Region { get; set; }
///
/// Languages value
///
- /// No-Intro database export only
+ /// TODO: No-Intro database export only
[JsonProperty("languages"), XmlElement("languages")]
- public string Languages { get; set; }
+ public string? Languages { get; set; }
///
/// Development status value
///
- /// No-Intro database export only
+ /// TODO: No-Intro database export only
[JsonProperty("devstatus"), XmlElement("devstatus")]
- public string DevStatus { get; set; }
+ public string? DevStatus { get; set; }
///
/// Physical value
///
- /// No-Intro database export only
+ /// TODO: No-Intro database export only
/// TODO: Is this numeric or a flag?
[JsonProperty("physical"), XmlElement("physical")]
- public string Physical { get; set; }
+ public string? Physical { get; set; }
///
/// Complete value
///
- /// No-Intro database export only
+ /// TODO: No-Intro database export only
/// TODO: Is this numeric or a flag?
[JsonProperty("complete"), XmlElement("complete")]
- public string Complete { get; set; }
+ public string? Complete { get; set; }
///
/// Categories value
///
- /// No-Intro database export only
+ /// TODO: No-Intro database export only
[JsonProperty("categories"), XmlElement("categories")]
- public string Categories { get; set; }
+ public string? Categories { get; set; }
+
+ ///
+ /// Internal Archive model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Archive _archive = new();
#endregion
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -118,20 +128,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Name = this.Name,
- Number = this.Number,
- CloneValue = this.CloneValue,
- RegParent = this.RegParent,
- Region = this.Region,
- Languages = this.Languages,
- DevStatus = this.DevStatus,
- Physical = this.Physical,
- Complete = this.Complete,
- Categories = this.Categories,
+ _archive = this._archive?.Clone() as Models.Internal.Archive ?? new Models.Internal.Archive(),
};
}
@@ -140,26 +141,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
- // If we don't have an archive, return false
- if (ItemType != other.ItemType)
+ // If we don't have a Archive, return false
+ if (ItemType != other?.ItemType || other is not Archive otherInternal)
return false;
- // Otherwise, treat it as an archive
- Archive newOther = other as Archive;
-
- // If the archive information matches
- return (Name == newOther.Name
- && Number == newOther.Number
- && CloneValue == newOther.CloneValue
- && RegParent == newOther.RegParent
- && Region == newOther.Region
- && Languages == newOther.Languages
- && DevStatus == newOther.DevStatus
- && Physical == newOther.Physical
- && Complete == newOther.Complete
- && Categories == newOther.Categories);
+ // Compare the internal models
+ return _archive.EqualTo(otherInternal._archive);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/Auxiliary.cs b/SabreTools.DatItems/Formats/Auxiliary.cs
index 7a793b29..fed1f72a 100644
--- a/SabreTools.DatItems/Formats/Auxiliary.cs
+++ b/SabreTools.DatItems/Formats/Auxiliary.cs
@@ -17,10 +17,24 @@ namespace SabreTools.DatItems.Formats
public class Original
{
[JsonProperty("value"), XmlElement("value")]
- public bool? Value { get; set; }
+ public bool? Value
+ {
+ get => _original.ReadBool(Models.Internal.Original.ValueKey);
+ set => _original[Models.Internal.Original.ValueKey] = value;
+ }
[JsonProperty("content"), XmlElement("content")]
- public string Content { get; set; }
+ public string? Content
+ {
+ get => _original.ReadString(Models.Internal.Original.ContentKey);
+ set => _original[Models.Internal.Original.ContentKey] = value;
+ }
+
+ ///
+ /// Internal Original model
+ ///
+ [JsonIgnore]
+ private readonly Models.Internal.Original _original = new();
}
#endregion
diff --git a/SabreTools.DatItems/Formats/BiosSet.cs b/SabreTools.DatItems/Formats/BiosSet.cs
index e56bffd0..8bf80800 100644
--- a/SabreTools.DatItems/Formats/BiosSet.cs
+++ b/SabreTools.DatItems/Formats/BiosSet.cs
@@ -16,32 +16,50 @@ namespace SabreTools.DatItems.Formats
/// Name of the item
///
[JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _biosSet.ReadString(Models.Internal.BiosSet.NameKey);
+ set => _biosSet[Models.Internal.BiosSet.NameKey] = value;
+ }
///
/// Description of the BIOS
///
[JsonProperty("description", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("description")]
- public string Description { get; set; }
+ public string? Description
+ {
+ get => _biosSet.ReadString(Models.Internal.BiosSet.DescriptionKey);
+ set => _biosSet[Models.Internal.BiosSet.DescriptionKey] = value;
+ }
///
/// Determine whether the BIOS is default
///
[JsonProperty("default", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("default")]
- public bool? Default { get; set; }
+ public bool? Default
+ {
+ get => _biosSet.ReadBool(Models.Internal.BiosSet.DefaultKey);
+ set => _biosSet[Models.Internal.BiosSet.DefaultKey] = value;
+ }
[JsonIgnore]
public bool DefaultSpecified { get { return Default != null; } }
+ ///
+ /// Internal BiosSet model
+ ///
+ [JsonIgnore]
+ private Models.Internal.BiosSet _biosSet = new();
+
#endregion
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -68,13 +86,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Name = this.Name,
- Description = this.Description,
- Default = this.Default,
+ _biosSet = this._biosSet?.Clone() as Models.Internal.BiosSet ?? new Models.Internal.BiosSet(),
};
}
@@ -83,19 +99,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
// If we don't have a BiosSet, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType || other is not BiosSet otherInternal)
return false;
- // Otherwise, treat it as a BiosSet
- BiosSet newOther = other as BiosSet;
-
- // If the BiosSet information matches
- return (Name == newOther.Name
- && Description == newOther.Description
- && Default == newOther.Default);
+ // Compare the internal models
+ return _biosSet.EqualTo(otherInternal._biosSet);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/Blank.cs b/SabreTools.DatItems/Formats/Blank.cs
index 93a3b154..1264952f 100644
--- a/SabreTools.DatItems/Formats/Blank.cs
+++ b/SabreTools.DatItems/Formats/Blank.cs
@@ -32,8 +32,8 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
};
}
@@ -43,17 +43,17 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
// If we don't have a blank, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType)
return false;
// Otherwise, treat it as a Blank
- Blank newOther = other as Blank;
+ Blank? newOther = other as Blank;
// If the archive information matches
- return (Machine == newOther.Machine);
+ return (Machine == newOther!.Machine);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/Chip.cs b/SabreTools.DatItems/Formats/Chip.cs
index 8a59bae8..85237c70 100644
--- a/SabreTools.DatItems/Formats/Chip.cs
+++ b/SabreTools.DatItems/Formats/Chip.cs
@@ -2,6 +2,7 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using SabreTools.Core;
+using SabreTools.Core.Tools;
namespace SabreTools.DatItems.Formats
{
@@ -17,20 +18,32 @@ namespace SabreTools.DatItems.Formats
/// Name of the item
///
[JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _chip.ReadString(Models.Internal.Chip.NameKey);
+ set => _chip[Models.Internal.Chip.NameKey] = value;
+ }
///
/// Internal tag
///
[JsonProperty("tag", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("tag")]
- public string Tag { get; set; }
+ public string? Tag
+ {
+ get => _chip.ReadString(Models.Internal.Chip.TagKey);
+ set => _chip[Models.Internal.Chip.TagKey] = value;
+ }
///
/// Type of the chip
///
[JsonProperty("type", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("type")]
[JsonConverter(typeof(StringEnumConverter))]
- public ChipType ChipType { get; set; }
+ public ChipType ChipType
+ {
+ get => _chip.ReadString(Models.Internal.Chip.ChipTypeKey).AsChipType();
+ set => _chip[Models.Internal.Chip.ChipTypeKey] = value.FromChipType();
+ }
[JsonIgnore]
public bool ChipTypeSpecified { get { return ChipType != ChipType.NULL; } }
@@ -39,20 +52,30 @@ namespace SabreTools.DatItems.Formats
/// Clock speed
///
[JsonProperty("clock", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("clock")]
- public long? Clock { get; set; }
+ public long? Clock
+ {
+ get => _chip.ReadLong(Models.Internal.Chip.ClockKey);
+ set => _chip[Models.Internal.Chip.ClockKey] = value;
+ }
[JsonIgnore]
public bool ClockSpecified { get { return Clock != null; } }
+ ///
+ /// Internal Chip model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Chip _chip = new();
+
#endregion
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -79,14 +102,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Name = this.Name,
- Tag = this.Tag,
- ChipType = this.ChipType,
- Clock = this.Clock,
+ _chip = this._chip?.Clone() as Models.Internal.Chip ?? new Models.Internal.Chip(),
};
}
@@ -95,20 +115,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
- // If we don't have a chip, return false
- if (ItemType != other.ItemType)
+ // If we don't have a Chip, return false
+ if (ItemType != other?.ItemType || other is not Chip otherInternal)
return false;
- // Otherwise, treat it as a chip
- Chip newOther = other as Chip;
-
- // If the chip information matches
- return (Name == newOther.Name
- && Tag == newOther.Tag
- && ChipType == newOther.ChipType
- && Clock == newOther.Clock);
+ // Compare the internal models
+ return _chip.EqualTo(otherInternal._chip);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/Condition.cs b/SabreTools.DatItems/Formats/Condition.cs
index 72aeab5d..7a452542 100644
--- a/SabreTools.DatItems/Formats/Condition.cs
+++ b/SabreTools.DatItems/Formats/Condition.cs
@@ -2,6 +2,7 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using SabreTools.Core;
+using SabreTools.Core.Tools;
namespace SabreTools.DatItems.Formats
{
@@ -17,29 +18,51 @@ namespace SabreTools.DatItems.Formats
/// Condition tag value
///
[JsonProperty("tag", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("tag")]
- public string Tag { get; set; }
+ public string? Tag
+ {
+ get => _condition.ReadString(Models.Internal.Condition.TagKey);
+ set => _condition[Models.Internal.Condition.TagKey] = value;
+ }
///
/// Condition mask
///
[JsonProperty("mask", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("mask")]
- public string Mask { get; set; }
+ public string? Mask
+ {
+ get => _condition.ReadString(Models.Internal.Condition.MaskKey);
+ set => _condition[Models.Internal.Condition.MaskKey] = value;
+ }
///
/// Condition relationship
///
[JsonProperty("relation", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("relation")]
[JsonConverter(typeof(StringEnumConverter))]
- public Relation Relation { get; set; }
+ public Relation Relation
+ {
+ get => _condition.ReadString(Models.Internal.Condition.RelationKey).AsRelation();
+ set => _condition[Models.Internal.Condition.RelationKey] = value.FromRelation();
+ }
[JsonIgnore]
- public bool RelationSpecified { get { return Relation != Relation.NULL; } }
+ public bool RelationSpecified { get { return Relation != Core.Relation.NULL; } }
///
/// Condition value
///
[JsonProperty("value", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("value")]
- public string Value { get; set; }
+ public string? Value
+ {
+ get => _condition.ReadString(Models.Internal.Condition.ValueKey);
+ set => _condition[Models.Internal.Condition.ValueKey] = value;
+ }
+
+ ///
+ /// Internal Condition model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Condition _condition = new();
#endregion
@@ -65,14 +88,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Tag = this.Tag,
- Mask = this.Mask,
- Relation = this.Relation,
- Value = this.Value,
+ _condition = this._condition?.Clone() as Models.Internal.Condition ?? new Models.Internal.Condition(),
};
}
@@ -81,20 +101,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
// If we don't have a Condition, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType || other is not Condition otherInternal)
return false;
- // Otherwise, treat it as a Condition
- Condition newOther = other as Condition;
-
- // If the Feature information matches
- return (Tag == newOther.Tag
- && Mask == newOther.Mask
- && Relation == newOther.Relation
- && Value == newOther.Value);
+ // Compare the internal models
+ return _condition.EqualTo(otherInternal._condition);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/ConfLocation.cs b/SabreTools.DatItems/Formats/ConfLocation.cs
new file mode 100644
index 00000000..2400f91e
--- /dev/null
+++ b/SabreTools.DatItems/Formats/ConfLocation.cs
@@ -0,0 +1,117 @@
+using System.Xml.Serialization;
+using Newtonsoft.Json;
+using SabreTools.Core;
+
+namespace SabreTools.DatItems.Formats
+{
+ ///
+ /// Represents one conflocation
+ ///
+ [JsonObject("conflocation"), XmlRoot("conflocation")]
+ public class ConfLocation : DatItem
+ {
+ #region Fields
+
+ ///
+ /// Location name
+ ///
+ [JsonProperty("name"), XmlElement("name")]
+ public string? Name
+ {
+ get => _confLocation.ReadString(Models.Internal.ConfLocation.NameKey);
+ set => _confLocation[Models.Internal.ConfLocation.NameKey] = value;
+ }
+
+ ///
+ /// Location ID
+ ///
+ [JsonProperty("number", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("number")]
+ public long? Number
+ {
+ get => _confLocation.ReadLong(Models.Internal.ConfLocation.NumberKey);
+ set => _confLocation[Models.Internal.ConfLocation.NumberKey] = value;
+ }
+
+ [JsonIgnore]
+ public bool NumberSpecified { get { return Number != null; } }
+
+ ///
+ /// Determines if location is inverted or not
+ ///
+ [JsonProperty("inverted", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("inverted")]
+ public bool? Inverted
+ {
+ get => _confLocation.ReadBool(Models.Internal.ConfLocation.InvertedKey);
+ set => _confLocation[Models.Internal.ConfLocation.InvertedKey] = value;
+ }
+
+ [JsonIgnore]
+ public bool InvertedSpecified { get { return Inverted != null; } }
+
+ ///
+ /// Internal ConfLocation model
+ ///
+ [JsonIgnore]
+ private Models.Internal.ConfLocation _confLocation = new();
+
+ #endregion
+
+ #region Accessors
+
+ ///
+ public override string? GetName() => Name;
+
+ ///
+ public override void SetName(string? name) => Name = name;
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Create a default, empty ConfLocation object
+ ///
+ public ConfLocation()
+ {
+ Name = string.Empty;
+ ItemType = ItemType.ConfLocation;
+ }
+
+ #endregion
+
+ #region Cloning Methods
+
+ ///
+ public override object Clone()
+ {
+ return new ConfLocation()
+ {
+ ItemType = this.ItemType,
+ DupeType = this.DupeType,
+
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
+ Remove = this.Remove,
+
+ _confLocation = this._confLocation?.Clone() as Models.Internal.ConfLocation ?? new Models.Internal.ConfLocation(),
+ };
+ }
+
+ #endregion
+
+ #region Comparision Methods
+
+ ///
+ public override bool Equals(DatItem? other)
+ {
+ // If we don't have a v, return false
+ if (ItemType != other?.ItemType || other is not ConfLocation otherInternal)
+ return false;
+
+ // Compare the internal models
+ return _confLocation.EqualTo(otherInternal._confLocation);
+ }
+
+ #endregion
+ }
+}
diff --git a/SabreTools.DatItems/Formats/ConfSetting.cs b/SabreTools.DatItems/Formats/ConfSetting.cs
new file mode 100644
index 00000000..d5b40546
--- /dev/null
+++ b/SabreTools.DatItems/Formats/ConfSetting.cs
@@ -0,0 +1,129 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml.Serialization;
+using Newtonsoft.Json;
+using SabreTools.Core;
+
+namespace SabreTools.DatItems.Formats
+{
+ ///
+ /// Represents one ListXML confsetting
+ ///
+ [JsonObject("confsetting"), XmlRoot("confsetting")]
+ public class ConfSetting : DatItem
+ {
+ #region Fields
+
+ ///
+ /// Setting name
+ ///
+ [JsonProperty("name"), XmlElement("name")]
+ public string? Name
+ {
+ get => _confSetting.ReadString(Models.Internal.ConfSetting.NameKey);
+ set => _confSetting[Models.Internal.ConfSetting.NameKey] = value;
+ }
+
+ ///
+ /// Setting value
+ ///
+ [JsonProperty("value", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("value")]
+ public string? Value
+ {
+ get => _confSetting.ReadString(Models.Internal.ConfSetting.ValueKey);
+ set => _confSetting[Models.Internal.ConfSetting.ValueKey] = value;
+ }
+
+ ///
+ /// Determines if the setting is default or not
+ ///
+ [JsonProperty("default", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("default")]
+ public bool? Default
+ {
+ get => _confSetting.ReadBool(Models.Internal.ConfSetting.DefaultKey);
+ set => _confSetting[Models.Internal.ConfSetting.DefaultKey] = value;
+ }
+
+ [JsonIgnore]
+ public bool DefaultSpecified { get { return Default != null; } }
+
+ ///
+ /// List of conditions on the setting
+ ///
+ [JsonProperty("conditions", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("conditions")]
+ public List? Conditions
+ {
+ get => _confSetting.Read(Models.Internal.ConfSetting.ConditionKey)?.ToList();
+ set => _confSetting[Models.Internal.ConfSetting.ConditionKey] = value?.ToArray();
+ }
+
+ [JsonIgnore]
+ public bool ConditionsSpecified { get { return Conditions != null && Conditions.Count > 0; } }
+
+ ///
+ /// Internal ConfSetting model
+ ///
+ [JsonIgnore]
+ private Models.Internal.ConfSetting _confSetting = new();
+
+ #endregion
+
+ #region Accessors
+
+ ///
+ public override string? GetName() => Name;
+
+ ///
+ public override void SetName(string? name) => Name = name;
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Create a default, empty ConfSetting object
+ ///
+ public ConfSetting()
+ {
+ Name = string.Empty;
+ ItemType = ItemType.ConfSetting;
+ }
+
+ #endregion
+
+ #region Cloning Methods
+
+ ///
+ public override object Clone()
+ {
+ return new ConfSetting()
+ {
+ ItemType = this.ItemType,
+ DupeType = this.DupeType,
+
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
+ Remove = this.Remove,
+
+ _confSetting = this._confSetting?.Clone() as Models.Internal.ConfSetting ?? new Models.Internal.ConfSetting(),
+ };
+ }
+
+ #endregion
+
+ #region Comparision Methods
+
+ ///
+ public override bool Equals(DatItem? other)
+ {
+ // If we don't have a ConfSetting, return false
+ if (ItemType != other?.ItemType || other is not ConfSetting otherInternal)
+ return false;
+
+ // Compare the internal models
+ return _confSetting.EqualTo(otherInternal._confSetting);
+ }
+
+ #endregion
+ }
+}
diff --git a/SabreTools.DatItems/Formats/Configuration.cs b/SabreTools.DatItems/Formats/Configuration.cs
index e4829b7f..dc0e2f41 100644
--- a/SabreTools.DatItems/Formats/Configuration.cs
+++ b/SabreTools.DatItems/Formats/Configuration.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Linq;
using System.Xml.Serialization;
using Newtonsoft.Json;
using SabreTools.Core;
@@ -17,25 +18,41 @@ namespace SabreTools.DatItems.Formats
/// Name of the item
///
[JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _configuration.ReadString(Models.Internal.Configuration.NameKey);
+ set => _configuration[Models.Internal.Configuration.NameKey] = value;
+ }
///
/// Tag associated with the configuration
///
[JsonProperty("tag", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("tag")]
- public string Tag { get; set; }
+ public string? Tag
+ {
+ get => _configuration.ReadString(Models.Internal.Configuration.TagKey);
+ set => _configuration[Models.Internal.Configuration.TagKey] = value;
+ }
///
/// Mask associated with the configuration
///
[JsonProperty("mask", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("mask")]
- public string Mask { get; set; }
+ public string? Mask
+ {
+ get => _configuration.ReadString(Models.Internal.Configuration.MaskKey);
+ set => _configuration[Models.Internal.Configuration.MaskKey] = value;
+ }
///
/// Conditions associated with the configuration
///
[JsonProperty("conditions", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("conditions")]
- public List Conditions { get; set; }
+ public List? Conditions
+ {
+ get => _configuration.Read(Models.Internal.Configuration.ConditionKey)?.ToList();
+ set => _configuration[Models.Internal.Configuration.ConditionKey] = value?.ToArray();
+ }
[JsonIgnore]
public bool ConditionsSpecified { get { return Conditions != null && Conditions.Count > 0; } }
@@ -44,7 +61,11 @@ namespace SabreTools.DatItems.Formats
/// Locations associated with the configuration
///
[JsonProperty("locations", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("locations")]
- public List Locations { get; set; }
+ public List? Locations
+ {
+ get => _configuration.Read(Models.Internal.Configuration.ConfLocationKey)?.ToList();
+ set => _configuration[Models.Internal.Configuration.ConfLocationKey] = value?.ToArray();
+ }
[JsonIgnore]
public bool LocationsSpecified { get { return Locations != null && Locations.Count > 0; } }
@@ -53,20 +74,30 @@ namespace SabreTools.DatItems.Formats
/// Settings associated with the configuration
///
[JsonProperty("settings", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("settings")]
- public List Settings { get; set; }
+ public List? Settings
+ {
+ get => _configuration.Read>(Models.Internal.Configuration.ConfSettingKey);
+ set => _configuration[Models.Internal.Configuration.ConfSettingKey] = value;
+ }
[JsonIgnore]
public bool SettingsSpecified { get { return Settings != null && Settings.Count > 0; } }
+ ///
+ /// Internal Configuration model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Configuration _configuration = new();
+
#endregion
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -93,16 +124,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Name = this.Name,
- Tag = this.Tag,
- Mask = this.Mask,
- Conditions = this.Conditions,
- Locations = this.Locations,
- Settings = this.Settings,
+ _configuration = this._configuration?.Clone() as Models.Internal.Configuration ?? new Models.Internal.Configuration(),
};
}
@@ -111,50 +137,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
// If we don't have a Configuration, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType || other is not Configuration otherInternal)
return false;
- // Otherwise, treat it as a Configuration
- Configuration newOther = other as Configuration;
-
- // If the Configuration information matches
- bool match = (Name == newOther.Name
- && Tag == newOther.Tag
- && Mask == newOther.Mask);
- if (!match)
- return match;
-
- // If the conditions match
- if (ConditionsSpecified)
- {
- foreach (Condition condition in Conditions)
- {
- match &= newOther.Conditions.Contains(condition);
- }
- }
-
- // If the locations match
- if (LocationsSpecified)
- {
- foreach (Location location in Locations)
- {
- match &= newOther.Locations.Contains(location);
- }
- }
-
- // If the settings match
- if (SettingsSpecified)
- {
- foreach (Setting setting in Settings)
- {
- match &= newOther.Settings.Contains(setting);
- }
- }
-
- return match;
+ // Compare the internal models
+ return _configuration.EqualTo(otherInternal._configuration);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/Control.cs b/SabreTools.DatItems/Formats/Control.cs
index e30d0dbd..dd0afb71 100644
--- a/SabreTools.DatItems/Formats/Control.cs
+++ b/SabreTools.DatItems/Formats/Control.cs
@@ -2,6 +2,7 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using SabreTools.Core;
+using SabreTools.Core.Tools;
namespace SabreTools.DatItems.Formats
{
@@ -18,7 +19,11 @@ namespace SabreTools.DatItems.Formats
///
[JsonProperty("type", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("type")]
[JsonConverter(typeof(StringEnumConverter))]
- public ControlType ControlType { get; set; }
+ public ControlType ControlType
+ {
+ get => _control.ReadString(Models.Internal.Control.ControlTypeKey).AsControlType();
+ set => _control[Models.Internal.Control.ControlTypeKey] = value.FromControlType();
+ }
[JsonIgnore]
public bool ControlTypeSpecified { get { return ControlType != ControlType.NULL; } }
@@ -27,7 +32,11 @@ namespace SabreTools.DatItems.Formats
/// Player which the input belongs to
///
[JsonProperty("player", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("player")]
- public long? Player { get; set; }
+ public long? Player
+ {
+ get => _control.ReadLong(Models.Internal.Control.PlayerKey);
+ set => _control[Models.Internal.Control.PlayerKey] = value;
+ }
[JsonIgnore]
public bool PlayerSpecified { get { return Player != null; } }
@@ -36,7 +45,11 @@ namespace SabreTools.DatItems.Formats
/// Total number of buttons
///
[JsonProperty("buttons", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("buttons")]
- public long? Buttons { get; set; }
+ public long? Buttons
+ {
+ get => _control.ReadLong(Models.Internal.Control.ButtonsKey);
+ set => _control[Models.Internal.Control.ButtonsKey] = value;
+ }
[JsonIgnore]
public bool ButtonsSpecified { get { return Buttons != null; } }
@@ -45,7 +58,11 @@ namespace SabreTools.DatItems.Formats
/// Total number of non-optional buttons
///
[JsonProperty("reqbuttons", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("reqbuttons")]
- public long? RequiredButtons { get; set; }
+ public long? RequiredButtons
+ {
+ get => _control.ReadLong(Models.Internal.Control.ReqButtonsKey);
+ set => _control[Models.Internal.Control.ReqButtonsKey] = value;
+ }
[JsonIgnore]
public bool RequiredButtonsSpecified { get { return RequiredButtons != null; } }
@@ -54,7 +71,11 @@ namespace SabreTools.DatItems.Formats
/// Analog minimum value
///
[JsonProperty("minimum", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("minimum")]
- public long? Minimum { get; set; }
+ public long? Minimum
+ {
+ get => _control.ReadLong(Models.Internal.Control.MinimumKey);
+ set => _control[Models.Internal.Control.MinimumKey] = value;
+ }
[JsonIgnore]
public bool MinimumSpecified { get { return Minimum != null; } }
@@ -63,7 +84,11 @@ namespace SabreTools.DatItems.Formats
/// Analog maximum value
///
[JsonProperty("maximum", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("maximum")]
- public long? Maximum { get; set; }
+ public long? Maximum
+ {
+ get => _control.ReadLong(Models.Internal.Control.MaximumKey);
+ set => _control[Models.Internal.Control.MaximumKey] = value;
+ }
[JsonIgnore]
public bool MaximumSpecified { get { return Maximum != null; } }
@@ -72,7 +97,11 @@ namespace SabreTools.DatItems.Formats
/// Default analog sensitivity
///
[JsonProperty("sensitivity", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("sensitivity")]
- public long? Sensitivity { get; set; }
+ public long? Sensitivity
+ {
+ get => _control.ReadLong(Models.Internal.Control.SensitivityKey);
+ set => _control[Models.Internal.Control.SensitivityKey] = value;
+ }
[JsonIgnore]
public bool SensitivitySpecified { get { return Sensitivity != null; } }
@@ -81,7 +110,11 @@ namespace SabreTools.DatItems.Formats
/// Default analog keydelta
///
[JsonProperty("keydelta", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("keydelta")]
- public long? KeyDelta { get; set; }
+ public long? KeyDelta
+ {
+ get => _control.ReadLong(Models.Internal.Control.KeyDeltaKey);
+ set => _control[Models.Internal.Control.KeyDeltaKey] = value;
+ }
[JsonIgnore]
public bool KeyDeltaSpecified { get { return KeyDelta != null; } }
@@ -90,7 +123,11 @@ namespace SabreTools.DatItems.Formats
/// Default analog reverse setting
///
[JsonProperty("reverse", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("reverse")]
- public bool? Reverse { get; set; }
+ public bool? Reverse
+ {
+ get => _control.ReadBool(Models.Internal.Control.ReverseKey);
+ set => _control[Models.Internal.Control.ReverseKey] = value;
+ }
[JsonIgnore]
public bool ReverseSpecified { get { return Reverse != null; } }
@@ -99,19 +136,37 @@ namespace SabreTools.DatItems.Formats
/// First set of ways
///
[JsonProperty("ways", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("ways")]
- public string Ways { get; set; }
+ public string? Ways
+ {
+ get => _control.ReadString(Models.Internal.Control.WaysKey);
+ set => _control[Models.Internal.Control.WaysKey] = value;
+ }
///
/// Second set of ways
///
[JsonProperty("ways2", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("ways2")]
- public string Ways2 { get; set; }
+ public string? Ways2
+ {
+ get => _control.ReadString(Models.Internal.Control.Ways2Key);
+ set => _control[Models.Internal.Control.Ways2Key] = value;
+ }
///
/// Third set of ways
///
[JsonProperty("ways3", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("ways3")]
- public string Ways3 { get; set; }
+ public string? Ways3
+ {
+ get => _control.ReadString(Models.Internal.Control.Ways3Key);
+ set => _control[Models.Internal.Control.Ways3Key] = value;
+ }
+
+ ///
+ /// Internal Control model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Control _control = new();
#endregion
@@ -137,22 +192,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- ControlType = this.ControlType,
- Player = this.Player,
- Buttons = this.Buttons,
- RequiredButtons = this.RequiredButtons,
- Minimum = this.Minimum,
- Maximum = this.Maximum,
- Sensitivity = this.Sensitivity,
- KeyDelta = this.KeyDelta,
- Reverse = this.Reverse,
- Ways = this.Ways,
- Ways2 = this.Ways2,
- Ways3 = this.Ways3,
+ _control = this._control?.Clone() as Models.Internal.Control ?? new Models.Internal.Control(),
};
}
@@ -161,28 +205,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
// If we don't have a Control, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType || other is not Control otherInternal)
return false;
- // Otherwise, treat it as a Control
- Control newOther = other as Control;
-
- // If the Control information matches
- return (ControlType == newOther.ControlType
- && Player == newOther.Player
- && Buttons == newOther.Buttons
- && RequiredButtons == newOther.RequiredButtons
- && Minimum == newOther.Minimum
- && Maximum == newOther.Maximum
- && Sensitivity == newOther.Sensitivity
- && KeyDelta == newOther.KeyDelta
- && Reverse == newOther.Reverse
- && Ways == newOther.Ways
- && Ways2 == newOther.Ways2
- && Ways3 == newOther.Ways3);
+ // Compare the internal models
+ return _control.EqualTo(otherInternal._control);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/DataArea.cs b/SabreTools.DatItems/Formats/DataArea.cs
index d629e77c..cd2a414b 100644
--- a/SabreTools.DatItems/Formats/DataArea.cs
+++ b/SabreTools.DatItems/Formats/DataArea.cs
@@ -1,6 +1,7 @@
using System.Xml.Serialization;
using Newtonsoft.Json;
using SabreTools.Core;
+using SabreTools.Core.Tools;
namespace SabreTools.DatItems.Formats
{
@@ -17,13 +18,21 @@ namespace SabreTools.DatItems.Formats
/// Name of the item
///
[JsonProperty("name", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _dataArea.ReadString(Models.Internal.DataArea.NameKey);
+ set => _dataArea[Models.Internal.DataArea.NameKey] = value;
+ }
///
/// Total size of the area
///
[JsonProperty("size", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("size")]
- public long? Size { get; set; }
+ public long? Size
+ {
+ get => _dataArea.ReadLong(Models.Internal.DataArea.SizeKey);
+ set => _dataArea[Models.Internal.DataArea.SizeKey] = value;
+ }
[JsonIgnore]
public bool SizeSpecified { get { return Size != null; } }
@@ -32,7 +41,11 @@ namespace SabreTools.DatItems.Formats
/// Word width for the area
///
[JsonProperty("width", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("width")]
- public long? Width { get; set; }
+ public long? Width
+ {
+ get => _dataArea.ReadLong(Models.Internal.DataArea.WidthKey);
+ set => _dataArea[Models.Internal.DataArea.WidthKey] = value;
+ }
[JsonIgnore]
public bool WidthSpecified { get { return Width != null; } }
@@ -41,20 +54,30 @@ namespace SabreTools.DatItems.Formats
/// Byte endianness of the area
///
[JsonProperty("endianness", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("endianness")]
- public Endianness Endianness { get; set; }
+ public Endianness Endianness
+ {
+ get => _dataArea.ReadString(Models.Internal.DataArea.WidthKey).AsEndianness();
+ set => _dataArea[Models.Internal.DataArea.WidthKey] = value.FromEndianness();
+ }
[JsonIgnore]
public bool EndiannessSpecified { get { return Endianness != Endianness.NULL; } }
+ ///
+ /// Internal DataArea model
+ ///
+ [JsonIgnore]
+ private Models.Internal.DataArea _dataArea = new();
+
#endregion
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -81,14 +104,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Name = this.Name,
- Size = this.Size,
- Width = this.Width,
- Endianness = this.Endianness,
+ _dataArea = this._dataArea?.Clone() as Models.Internal.DataArea ?? new Models.Internal.DataArea(),
};
}
@@ -97,20 +117,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
// If we don't have a DataArea, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType || other is not DataArea otherInternal)
return false;
- // Otherwise, treat it as a DataArea
- DataArea newOther = other as DataArea;
-
- // If the DataArea information matches
- return (Name == newOther.Name
- && Size == newOther.Size
- && Width == newOther.Width
- && Endianness == newOther.Endianness);
+ // Compare the internal models
+ return _dataArea.EqualTo(otherInternal._dataArea);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/Device.cs b/SabreTools.DatItems/Formats/Device.cs
index 01d4ed81..750548dd 100644
--- a/SabreTools.DatItems/Formats/Device.cs
+++ b/SabreTools.DatItems/Formats/Device.cs
@@ -1,8 +1,10 @@
using System.Collections.Generic;
+using System.Linq;
using System.Xml.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using SabreTools.Core;
+using SabreTools.Core.Tools;
namespace SabreTools.DatItems.Formats
{
@@ -19,7 +21,11 @@ namespace SabreTools.DatItems.Formats
///
[JsonProperty("type", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("type")]
[JsonConverter(typeof(StringEnumConverter))]
- public DeviceType DeviceType { get; set; }
+ public DeviceType DeviceType
+ {
+ get => _device.ReadString(Models.Internal.Device.DeviceTypeKey).AsDeviceType();
+ set => _device[Models.Internal.Device.DeviceTypeKey] = value.FromDeviceType();
+ }
[JsonIgnore]
public bool DeviceTypeSpecified { get { return DeviceType != DeviceType.NULL; } }
@@ -28,20 +34,32 @@ namespace SabreTools.DatItems.Formats
/// Device tag
///
[JsonProperty("tag", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("tag")]
- public string Tag { get; set; }
+ public string? Tag
+ {
+ get => _device.ReadString(Models.Internal.Device.TagKey);
+ set => _device[Models.Internal.Device.TagKey] = value;
+ }
///
/// Fixed image format
///
[JsonProperty("fixed_image", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("fixed_image")]
- public string FixedImage { get; set; }
+ public string? FixedImage
+ {
+ get => _device.ReadString(Models.Internal.Device.FixedImageKey);
+ set => _device[Models.Internal.Device.FixedImageKey] = value;
+ }
///
/// Determines if the devices is mandatory
///
/// Only value used seems to be 1. Used like bool, but actually int
[JsonProperty("mandatory", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("mandatory")]
- public long? Mandatory { get; set; }
+ public long? Mandatory
+ {
+ get => _device.ReadLong(Models.Internal.Device.MandatoryKey);
+ set => _device[Models.Internal.Device.MandatoryKey] = value;
+ }
[JsonIgnore]
public bool MandatorySpecified { get { return Mandatory != null; } }
@@ -50,13 +68,21 @@ namespace SabreTools.DatItems.Formats
/// Device interface
///
[JsonProperty("interface", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("interface")]
- public string Interface { get; set; }
+ public string? Interface
+ {
+ get => _device.ReadString(Models.Internal.Device.InterfaceKey);
+ set => _device[Models.Internal.Device.InterfaceKey] = value;
+ }
///
/// Device instances
///
[JsonProperty("instances", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("instances")]
- public List Instances { get; set; }
+ public List? Instances
+ {
+ get => _device.Read(Models.Internal.Device.InstanceKey)?.ToList();
+ set => _device[Models.Internal.Device.InstanceKey] = value?.ToArray();
+ }
[JsonIgnore]
public bool InstancesSpecified { get { return Instances != null && Instances.Count > 0; } }
@@ -65,11 +91,21 @@ namespace SabreTools.DatItems.Formats
/// Device extensions
///
[JsonProperty("extensions", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("extensions")]
- public List Extensions { get; set; }
+ public List? Extensions
+ {
+ get => _device.Read(Models.Internal.Device.ExtensionKey)?.ToList();
+ set => _device[Models.Internal.Device.ExtensionKey] = value?.ToArray();
+ }
[JsonIgnore]
public bool ExtensionsSpecified { get { return Extensions != null && Extensions.Count > 0; } }
+ ///
+ /// Internal Device model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Device _device = new();
+
#endregion
#region Constructors
@@ -94,17 +130,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- DeviceType = this.DeviceType,
- Tag = this.Tag,
- FixedImage = this.FixedImage,
- Mandatory = this.Mandatory,
- Interface = this.Interface,
- Instances = this.Instances,
- Extensions = this.Extensions,
+ _device = this._device?.Clone() as Models.Internal.Device ?? new Models.Internal.Device(),
};
}
@@ -113,43 +143,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
- // If we don't have a Device, return false
- if (ItemType != other.ItemType)
+ // If we don't have a Adjuster, return false
+ if (ItemType != other?.ItemType || other is not Device otherInternal)
return false;
- // Otherwise, treat it as a Device
- Device newOther = other as Device;
-
- // If the Device information matches
- bool match = (DeviceType == newOther.DeviceType
- && Tag == newOther.Tag
- && FixedImage == newOther.FixedImage
- && Mandatory == newOther.Mandatory
- && Interface == newOther.Interface);
- if (!match)
- return match;
-
- // If the instances match
- if (InstancesSpecified)
- {
- foreach (Instance instance in Instances)
- {
- match &= newOther.Instances.Contains(instance);
- }
- }
-
- // If the extensions match
- if (ExtensionsSpecified)
- {
- foreach (Extension extension in Extensions)
- {
- match &= newOther.Extensions.Contains(extension);
- }
- }
-
- return match;
+ // Compare the internal models
+ return _device.EqualTo(otherInternal._device);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/DeviceReference.cs b/SabreTools.DatItems/Formats/DeviceReference.cs
index 48d13e03..57ad0c32 100644
--- a/SabreTools.DatItems/Formats/DeviceReference.cs
+++ b/SabreTools.DatItems/Formats/DeviceReference.cs
@@ -16,17 +16,27 @@ namespace SabreTools.DatItems.Formats
/// Name of the item
///
[JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _deviceRef.ReadString(Models.Internal.DeviceRef.NameKey);
+ set => _deviceRef[Models.Internal.DeviceRef.NameKey] = value;
+ }
+
+ ///
+ /// Internal DeviceRef model
+ ///
+ [JsonIgnore]
+ private Models.Internal.DeviceRef _deviceRef = new();
#endregion
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -53,11 +63,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Name = this.Name,
+ _deviceRef = this._deviceRef?.Clone() as Models.Internal.DeviceRef ?? new Models.Internal.DeviceRef(),
};
}
@@ -66,17 +76,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
- // If we don't have a device reference, return false
- if (ItemType != other.ItemType)
+ // If we don't have a Adjuster, return false
+ if (ItemType != other?.ItemType || other is not DeviceReference otherInternal)
return false;
- // Otherwise, treat it as a device reference
- DeviceReference newOther = other as DeviceReference;
-
- // If the device reference information matches
- return (Name == newOther.Name);
+ // Compare the internal models
+ return _deviceRef.EqualTo(otherInternal._deviceRef);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/DipLocation.cs b/SabreTools.DatItems/Formats/DipLocation.cs
new file mode 100644
index 00000000..1d9f0bbf
--- /dev/null
+++ b/SabreTools.DatItems/Formats/DipLocation.cs
@@ -0,0 +1,117 @@
+using System.Xml.Serialization;
+using Newtonsoft.Json;
+using SabreTools.Core;
+
+namespace SabreTools.DatItems.Formats
+{
+ ///
+ /// Represents one diplocation
+ ///
+ [JsonObject("diplocation"), XmlRoot("diplocation")]
+ public class DipLocation : DatItem
+ {
+ #region Fields
+
+ ///
+ /// Location name
+ ///
+ [JsonProperty("name"), XmlElement("name")]
+ public string? Name
+ {
+ get => _dipLocation.ReadString(Models.Internal.DipLocation.NameKey);
+ set => _dipLocation[Models.Internal.DipLocation.NameKey] = value;
+ }
+
+ ///
+ /// Location ID
+ ///
+ [JsonProperty("number", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("number")]
+ public long? Number
+ {
+ get => _dipLocation.ReadLong(Models.Internal.DipLocation.NameKey);
+ set => _dipLocation[Models.Internal.DipLocation.NameKey] = value;
+ }
+
+ [JsonIgnore]
+ public bool NumberSpecified { get { return Number != null; } }
+
+ ///
+ /// Determines if location is inverted or not
+ ///
+ [JsonProperty("inverted", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("inverted")]
+ public bool? Inverted
+ {
+ get => _dipLocation.ReadBool(Models.Internal.DipLocation.InvertedKey);
+ set => _dipLocation[Models.Internal.DipLocation.InvertedKey] = value;
+ }
+
+ [JsonIgnore]
+ public bool InvertedSpecified { get { return Inverted != null; } }
+
+ ///
+ /// Internal DipLocation model
+ ///
+ [JsonIgnore]
+ private Models.Internal.DipLocation _dipLocation = new();
+
+ #endregion
+
+ #region Accessors
+
+ ///
+ public override string? GetName() => Name;
+
+ ///
+ public override void SetName(string? name) => Name = name;
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Create a default, empty DipLocation object
+ ///
+ public DipLocation()
+ {
+ Name = string.Empty;
+ ItemType = ItemType.DipLocation;
+ }
+
+ #endregion
+
+ #region Cloning Methods
+
+ ///
+ public override object Clone()
+ {
+ return new DipLocation()
+ {
+ ItemType = this.ItemType,
+ DupeType = this.DupeType,
+
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
+ Remove = this.Remove,
+
+ _dipLocation = this._dipLocation?.Clone() as Models.Internal.DipLocation ?? new Models.Internal.DipLocation(),
+ };
+ }
+
+ #endregion
+
+ #region Comparision Methods
+
+ ///
+ public override bool Equals(DatItem? other)
+ {
+ // If we don't have a DipLocation, return false
+ if (ItemType != other?.ItemType || other is not DipLocation otherInternal)
+ return false;
+
+ // Compare the internal models
+ return _dipLocation.EqualTo(otherInternal._dipLocation);
+ }
+
+ #endregion
+ }
+}
diff --git a/SabreTools.DatItems/Formats/DipSwitch.cs b/SabreTools.DatItems/Formats/DipSwitch.cs
index e8255064..bb4460cf 100644
--- a/SabreTools.DatItems/Formats/DipSwitch.cs
+++ b/SabreTools.DatItems/Formats/DipSwitch.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Linq;
using System.Xml.Serialization;
using Newtonsoft.Json;
using SabreTools.Core;
@@ -19,25 +20,41 @@ namespace SabreTools.DatItems.Formats
/// Name of the item
///
[JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _dipSwitch.ReadString(Models.Internal.DipSwitch.NameKey);
+ set => _dipSwitch[Models.Internal.DipSwitch.NameKey] = value;
+ }
///
/// Tag associated with the dipswitch
///
[JsonProperty("tag", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("tag")]
- public string Tag { get; set; }
+ public string? Tag
+ {
+ get => _dipSwitch.ReadString(Models.Internal.DipSwitch.TagKey);
+ set => _dipSwitch[Models.Internal.DipSwitch.TagKey] = value;
+ }
///
/// Mask associated with the dipswitch
///
[JsonProperty("mask", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("mask")]
- public string Mask { get; set; }
+ public string? Mask
+ {
+ get => _dipSwitch.ReadString(Models.Internal.DipSwitch.MaskKey);
+ set => _dipSwitch[Models.Internal.DipSwitch.MaskKey] = value;
+ }
///
/// Conditions associated with the dipswitch
///
[JsonProperty("conditions", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("conditions")]
- public List Conditions { get; set; }
+ public List? Conditions
+ {
+ get => _dipSwitch.Read(Models.Internal.DipSwitch.ConditionKey)?.ToList();
+ set => _dipSwitch[Models.Internal.DipSwitch.ConditionKey] = value?.ToArray();
+ }
[JsonIgnore]
public bool ConditionsSpecified { get { return Conditions != null && Conditions.Count > 0; } }
@@ -46,7 +63,11 @@ namespace SabreTools.DatItems.Formats
/// Locations associated with the dipswitch
///
[JsonProperty("locations", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("locations")]
- public List Locations { get; set; }
+ public List? Locations
+ {
+ get => _dipSwitch.Read(Models.Internal.DipSwitch.DipLocationKey)?.ToList();
+ set => _dipSwitch[Models.Internal.DipSwitch.DipLocationKey] = value?.ToArray();
+ }
[JsonIgnore]
public bool LocationsSpecified { get { return Locations != null && Locations.Count > 0; } }
@@ -55,7 +76,11 @@ namespace SabreTools.DatItems.Formats
/// Settings associated with the dipswitch
///
[JsonProperty("values", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("values")]
- public List Values { get; set; }
+ public List? Values
+ {
+ get => _dipSwitch.Read(Models.Internal.DipSwitch.DipValueKey)?.ToList();
+ set => _dipSwitch[Models.Internal.DipSwitch.DipValueKey] = value?.ToArray();
+ }
[JsonIgnore]
public bool ValuesSpecified { get { return Values != null && Values.Count > 0; } }
@@ -67,8 +92,9 @@ namespace SabreTools.DatItems.Formats
///
/// Original hardware part associated with the item
///
+ /// This is inverted from the internal model
[JsonProperty("part", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("part")]
- public Part Part { get; set; } = null;
+ public Part? Part { get; set; }
[JsonIgnore]
public bool PartSpecified
@@ -83,15 +109,21 @@ namespace SabreTools.DatItems.Formats
#endregion
+ ///
+ /// Internal DipSwitch model
+ ///
+ [JsonIgnore]
+ private Models.Internal.DipSwitch _dipSwitch = new();
+
#endregion // Fields
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -118,16 +150,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Name = this.Name,
- Tag = this.Tag,
- Mask = this.Mask,
- Conditions = this.Conditions,
- Locations = this.Locations,
- Values = this.Values,
+ _dipSwitch = this._dipSwitch?.Clone() as Models.Internal.DipSwitch ?? new Models.Internal.DipSwitch(),
Part = this.Part,
};
@@ -138,54 +165,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
// If we don't have a DipSwitch, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType || other is not DipSwitch otherInternal)
return false;
- // Otherwise, treat it as a DipSwitch
- DipSwitch newOther = other as DipSwitch;
-
- // If the DipSwitch information matches
- bool match = (Name == newOther.Name
- && Tag == newOther.Tag
- && Mask == newOther.Mask);
- if (!match)
- return match;
-
- // If the part matches
- if (PartSpecified)
- match &= (Part == newOther.Part);
-
- // If the conditions match
- if (ConditionsSpecified)
- {
- foreach (Condition condition in Conditions)
- {
- match &= newOther.Conditions.Contains(condition);
- }
- }
-
- // If the locations match
- if (LocationsSpecified)
- {
- foreach (Location location in Locations)
- {
- match &= newOther.Locations.Contains(location);
- }
- }
-
- // If the values match
- if (ValuesSpecified)
- {
- foreach (Setting value in Values)
- {
- match &= newOther.Values.Contains(value);
- }
- }
-
- return match;
+ // Compare the internal models
+ return _dipSwitch.EqualTo(otherInternal._dipSwitch);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/DipValue.cs b/SabreTools.DatItems/Formats/DipValue.cs
new file mode 100644
index 00000000..0e406706
--- /dev/null
+++ b/SabreTools.DatItems/Formats/DipValue.cs
@@ -0,0 +1,129 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml.Serialization;
+using Newtonsoft.Json;
+using SabreTools.Core;
+
+namespace SabreTools.DatItems.Formats
+{
+ ///
+ /// Represents one ListXML dipvalue
+ ///
+ [JsonObject("dipvalue"), XmlRoot("dipvalue")]
+ public class DipValue : DatItem
+ {
+ #region Fields
+
+ ///
+ /// Setting name
+ ///
+ [JsonProperty("name"), XmlElement("name")]
+ public string? Name
+ {
+ get => _dipValue.ReadString(Models.Internal.DipValue.NameKey);
+ set => _dipValue[Models.Internal.DipValue.NameKey] = value;
+ }
+
+ ///
+ /// Setting value
+ ///
+ [JsonProperty("value", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("value")]
+ public string? Value
+ {
+ get => _dipValue.ReadString(Models.Internal.DipValue.ValueKey);
+ set => _dipValue[Models.Internal.DipValue.ValueKey] = value;
+ }
+
+ ///
+ /// Determines if the setting is default or not
+ ///
+ [JsonProperty("default", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("default")]
+ public bool? Default
+ {
+ get => _dipValue.ReadBool(Models.Internal.DipValue.DefaultKey);
+ set => _dipValue[Models.Internal.DipValue.DefaultKey] = value;
+ }
+
+ [JsonIgnore]
+ public bool DefaultSpecified { get { return Default != null; } }
+
+ ///
+ /// List of conditions on the setting
+ ///
+ [JsonProperty("conditions", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("conditions")]
+ public List? Conditions
+ {
+ get => _dipValue.Read(Models.Internal.DipValue.ConditionKey)?.ToList();
+ set => _dipValue[Models.Internal.DipValue.ConditionKey] = value?.ToArray();
+ }
+
+ [JsonIgnore]
+ public bool ConditionsSpecified { get { return Conditions != null && Conditions.Count > 0; } }
+
+ ///
+ /// Internal DipValue model
+ ///
+ [JsonIgnore]
+ private Models.Internal.DipValue _dipValue = new();
+
+ #endregion
+
+ #region Accessors
+
+ ///
+ public override string? GetName() => Name;
+
+ ///
+ public override void SetName(string? name) => Name = name;
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Create a default, empty DipValue object
+ ///
+ public DipValue()
+ {
+ Name = string.Empty;
+ ItemType = ItemType.DipValue;
+ }
+
+ #endregion
+
+ #region Cloning Methods
+
+ ///
+ public override object Clone()
+ {
+ return new DipValue()
+ {
+ ItemType = this.ItemType,
+ DupeType = this.DupeType,
+
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
+ Remove = this.Remove,
+
+ _dipValue = this._dipValue?.Clone() as Models.Internal.DipValue ?? new Models.Internal.DipValue(),
+ };
+ }
+
+ #endregion
+
+ #region Comparision Methods
+
+ ///
+ public override bool Equals(DatItem? other)
+ {
+ // If we don't have a DipValue, return false
+ if (ItemType != other?.ItemType || other is not DipValue otherInternal)
+ return false;
+
+ // Compare the internal models
+ return _dipValue.EqualTo(otherInternal._dipValue);
+ }
+
+ #endregion
+ }
+}
diff --git a/SabreTools.DatItems/Formats/Disk.cs b/SabreTools.DatItems/Formats/Disk.cs
index a1be653e..4422f565 100644
--- a/SabreTools.DatItems/Formats/Disk.cs
+++ b/SabreTools.DatItems/Formats/Disk.cs
@@ -13,13 +13,6 @@ namespace SabreTools.DatItems.Formats
[JsonObject("disk"), XmlRoot("disk")]
public class Disk : DatItem
{
- #region Private instance variables
-
- private byte[] _md5; // 16 bytes
- private byte[] _sha1; // 20 bytes
-
- #endregion
-
#region Fields
#region Common
@@ -28,51 +21,71 @@ namespace SabreTools.DatItems.Formats
/// Name of the item
///
[JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _disk.ReadString(Models.Internal.Disk.NameKey);
+ set => _disk[Models.Internal.Disk.NameKey] = value;
+ }
///
/// Data MD5 hash
///
[JsonProperty("md5", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("md5")]
- public string MD5
+ public string? MD5
{
- get { return _md5.IsNullOrEmpty() ? null : Utilities.ByteArrayToString(_md5); }
- set { _md5 = Utilities.StringToByteArray(CleanMD5(value)); }
+ get => _disk.ReadString(Models.Internal.Disk.MD5Key);
+ set => _disk[Models.Internal.Disk.MD5Key] = TextHelper.NormalizeMD5(value);
}
///
/// Data SHA-1 hash
///
[JsonProperty("sha1", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("sha1")]
- public string SHA1
+ public string? SHA1
{
- get { return _sha1.IsNullOrEmpty() ? null : Utilities.ByteArrayToString(_sha1); }
- set { _sha1 = Utilities.StringToByteArray(CleanSHA1(value)); }
+ get => _disk.ReadString(Models.Internal.Disk.SHA1Key);
+ set => _disk[Models.Internal.Disk.SHA1Key] = TextHelper.NormalizeSHA1(value);
}
///
/// Disk name to merge from parent
///
[JsonProperty("merge", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("merge")]
- public string MergeTag { get; set; }
+ public string? MergeTag
+ {
+ get => _disk.ReadString(Models.Internal.Disk.MergeKey);
+ set => _disk[Models.Internal.Disk.MergeKey] = value;
+ }
///
/// Disk region
///
[JsonProperty("region", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("region")]
- public string Region { get; set; }
+ public string? Region
+ {
+ get => _disk.ReadString(Models.Internal.Disk.RegionKey);
+ set => _disk[Models.Internal.Disk.RegionKey] = value;
+ }
///
/// Disk index
///
[JsonProperty("index", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("index")]
- public string Index { get; set; }
+ public string? Index
+ {
+ get => _disk.ReadString(Models.Internal.Disk.IndexKey);
+ set => _disk[Models.Internal.Disk.IndexKey] = value;
+ }
///
/// Disk writable flag
///
[JsonProperty("writable", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("writable")]
- public bool? Writable { get; set; } = null;
+ public bool? Writable
+ {
+ get => _disk.ReadBool(Models.Internal.Disk.WritableKey);
+ set => _disk[Models.Internal.Disk.WritableKey] = value;
+ }
[JsonIgnore]
public bool WritableSpecified { get { return Writable != null; } }
@@ -82,7 +95,11 @@ namespace SabreTools.DatItems.Formats
///
[JsonProperty("status", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("status")]
[JsonConverter(typeof(StringEnumConverter))]
- public ItemStatus ItemStatus { get; set; }
+ public ItemStatus ItemStatus
+ {
+ get => _disk.ReadString(Models.Internal.Disk.StatusKey).AsItemStatus();
+ set => _disk[Models.Internal.Disk.StatusKey] = value.FromItemStatus(yesno: false);
+ }
[JsonIgnore]
public bool ItemStatusSpecified { get { return ItemStatus != ItemStatus.NULL; } }
@@ -91,7 +108,11 @@ namespace SabreTools.DatItems.Formats
/// Determine if the disk is optional in the set
///
[JsonProperty("optional", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("optional")]
- public bool? Optional { get; set; } = null;
+ public bool? Optional
+ {
+ get => _disk.ReadBool(Models.Internal.Disk.OptionalKey);
+ set => _disk[Models.Internal.Disk.OptionalKey] = value;
+ }
[JsonIgnore]
public bool OptionalSpecified { get { return Optional != null; } }
@@ -103,8 +124,9 @@ namespace SabreTools.DatItems.Formats
///
/// Disk area information
///
+ /// This is inverted from the internal model
[JsonProperty("diskarea", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("diskarea")]
- public DiskArea DiskArea { get; set; } = null;
+ public DiskArea? DiskArea { get; set; }
[JsonIgnore]
public bool DiskAreaSpecified
@@ -119,8 +141,9 @@ namespace SabreTools.DatItems.Formats
///
/// Original hardware part associated with the item
///
+ /// This is inverted from the internal model
[JsonProperty("part", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("part")]
- public Part Part { get; set; } = null;
+ public Part? Part { get; set; }
[JsonIgnore]
public bool PartSpecified
@@ -135,15 +158,21 @@ namespace SabreTools.DatItems.Formats
#endregion
+ ///
+ /// Internal Disk model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Disk _disk = new();
+
#endregion // Fields
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -167,8 +196,8 @@ namespace SabreTools.DatItems.Formats
public Disk(BaseFile baseFile)
{
Name = baseFile.Filename;
- _md5 = baseFile.MD5;
- _sha1 = baseFile.SHA1;
+ MD5 = Utilities.ByteArrayToString(baseFile.MD5);
+ SHA1 = Utilities.ByteArrayToString(baseFile.SHA1);
ItemType = ItemType.Disk;
DupeType = 0x00;
@@ -188,18 +217,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- _md5 = this._md5,
- _sha1 = this._sha1,
- MergeTag = this.MergeTag,
- Region = this.Region,
- Index = this.Index,
- Writable = this.Writable,
- ItemStatus = this.ItemStatus,
- Optional = this.Optional,
+ _disk = this._disk?.Clone() as Models.Internal.Disk ?? new Models.Internal.Disk(),
DiskArea = this.DiskArea,
Part = this.Part,
@@ -215,8 +237,8 @@ namespace SabreTools.DatItems.Formats
{
Filename = this.Name,
Parent = this.Machine?.Name,
- MD5 = this._md5,
- SHA1 = this._sha1,
+ MD5 = Utilities.StringToByteArray(this.MD5),
+ SHA1 = Utilities.StringToByteArray(this.SHA1),
};
}
@@ -232,8 +254,8 @@ namespace SabreTools.DatItems.Formats
ItemType = ItemType.Rom,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
MergeTag = this.MergeTag,
@@ -244,7 +266,7 @@ namespace SabreTools.DatItems.Formats
MD5 = this.MD5,
SHA1 = this.SHA1,
- DataArea = new DataArea { Name = this.DiskArea.Name },
+ DataArea = new DataArea { Name = this.DiskArea?.Name },
Part = this.Part,
};
@@ -256,32 +278,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
- bool dupefound = false;
+ // If we don't have a Disk, return false
+ if (ItemType != other?.ItemType || other is not Disk otherInternal)
+ return false;
- // If we don't have a rom, return false
- if (ItemType != other.ItemType)
- return dupefound;
-
- // Otherwise, treat it as a Disk
- Disk newOther = other as Disk;
-
- // If all hashes are empty but they're both nodump and the names match, then they're dupes
- if ((ItemStatus == ItemStatus.Nodump && newOther.ItemStatus == ItemStatus.Nodump)
- && Name == newOther.Name
- && !HasHashes() && !newOther.HasHashes())
- {
- dupefound = true;
- }
-
- // Otherwise if we get a partial match
- else if (HashMatch(newOther))
- {
- dupefound = true;
- }
-
- return dupefound;
+ // Compare the internal models
+ return _disk.EqualTo(otherInternal._disk);
}
///
@@ -290,11 +294,11 @@ namespace SabreTools.DatItems.Formats
/// Disk to fill information from
public void FillMissingInformation(Disk other)
{
- if (_md5.IsNullOrEmpty() && !other._md5.IsNullOrEmpty())
- _md5 = other._md5;
+ if (string.IsNullOrWhiteSpace(MD5) && !string.IsNullOrWhiteSpace(other.MD5))
+ MD5 = other.MD5;
- if (_sha1.IsNullOrEmpty() && !other._sha1.IsNullOrEmpty())
- _sha1 = other._sha1;
+ if (string.IsNullOrWhiteSpace(SHA1) && !string.IsNullOrWhiteSpace(other.SHA1))
+ SHA1 = other.SHA1;
}
///
@@ -303,55 +307,14 @@ namespace SabreTools.DatItems.Formats
/// String representing the suffix
public string GetDuplicateSuffix()
{
- if (!_md5.IsNullOrEmpty())
+ if (!string.IsNullOrWhiteSpace(MD5))
return $"_{MD5}";
- else if (!_sha1.IsNullOrEmpty())
+ else if (!string.IsNullOrWhiteSpace(SHA1))
return $"_{SHA1}";
else
return "_1";
}
- ///
- /// Returns if there are no, non-empty hashes in common with another Disk
- ///
- /// Disk to compare against
- /// True if at least one hash is not mutually exclusive, false otherwise
- private bool HasCommonHash(Disk other)
- {
- return !(_md5.IsNullOrEmpty() ^ other._md5.IsNullOrEmpty())
- || !(_sha1.IsNullOrEmpty() ^ other._sha1.IsNullOrEmpty());
- }
-
- ///
- /// Returns if the Disk contains any hashes
- ///
- /// True if any hash exists, false otherwise
- private bool HasHashes()
- {
- return !_md5.IsNullOrEmpty()
- || !_sha1.IsNullOrEmpty();
- }
-
- ///
- /// Returns if any hashes are common with another Disk
- ///
- /// Disk to compare against
- /// True if any hashes are in common, false otherwise
- private bool HashMatch(Disk other)
- {
- // If either have no hashes, we return false, otherwise this would be a false positive
- if (!HasHashes() || !other.HasHashes())
- return false;
-
- // If neither have hashes in common, we return false, otherwise this would be a false positive
- if (!HasCommonHash(other))
- return false;
-
- // Return if all hashes match according to merge rules
- return ConditionalHashEquals(_md5, other._md5)
- && ConditionalHashEquals(_sha1, other._sha1);
- }
-
#endregion
#region Sorting and Merging
@@ -360,7 +323,7 @@ namespace SabreTools.DatItems.Formats
public override string GetKey(ItemKey bucketedBy, bool lower = true, bool norename = true)
{
// Set the output key as the default blank string
- string key;
+ string? key;
// Now determine what the key should be based on the bucketedBy value
switch (bucketedBy)
diff --git a/SabreTools.DatItems/Formats/DiskArea.cs b/SabreTools.DatItems/Formats/DiskArea.cs
index 287e16e8..934750c2 100644
--- a/SabreTools.DatItems/Formats/DiskArea.cs
+++ b/SabreTools.DatItems/Formats/DiskArea.cs
@@ -17,17 +17,27 @@ namespace SabreTools.DatItems.Formats
/// Name of the item
///
[JsonProperty("name", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _diskArea.ReadString(Models.Internal.DiskArea.NameKey);
+ set => _diskArea[Models.Internal.DiskArea.NameKey] = value;
+ }
+
+ ///
+ /// Internal DiskArea model
+ ///
+ [JsonIgnore]
+ private Models.Internal.DiskArea _diskArea = new();
#endregion
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -54,11 +64,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Name = this.Name,
+ _diskArea = this._diskArea?.Clone() as Models.Internal.DiskArea ?? new Models.Internal.DiskArea(),
};
}
@@ -67,17 +77,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
// If we don't have a DiskArea, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType || other is not DiskArea otherInternal)
return false;
- // Otherwise, treat it as a DiskArea
- DiskArea newOther = other as DiskArea;
-
- // If the DiskArea information matches
- return (Name == newOther.Name);
+ // Compare the internal models
+ return _diskArea.EqualTo(otherInternal._diskArea);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/Display.cs b/SabreTools.DatItems/Formats/Display.cs
index 300a68b4..edb46632 100644
--- a/SabreTools.DatItems/Formats/Display.cs
+++ b/SabreTools.DatItems/Formats/Display.cs
@@ -2,6 +2,7 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using SabreTools.Core;
+using SabreTools.Core.Tools;
namespace SabreTools.DatItems.Formats
{
@@ -17,14 +18,22 @@ namespace SabreTools.DatItems.Formats
/// Display tag
///
[JsonProperty("tag", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("tag")]
- public string Tag { get; set; }
+ public string? Tag
+ {
+ get => _display.ReadString(Models.Internal.Display.TagKey);
+ set => _display[Models.Internal.Display.TagKey] = value;
+ }
///
/// Display type
///
[JsonProperty("type", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("type")]
[JsonConverter(typeof(StringEnumConverter))]
- public DisplayType DisplayType { get; set; }
+ public DisplayType DisplayType
+ {
+ get => _display.ReadString(Models.Internal.Display.DisplayTypeKey).AsDisplayType();
+ set => _display[Models.Internal.Display.DisplayTypeKey] = value.FromDisplayType();
+ }
[JsonIgnore]
public bool DisplayTypeSpecified { get { return DisplayType != DisplayType.NULL; } }
@@ -33,7 +42,11 @@ namespace SabreTools.DatItems.Formats
/// Display rotation
///
[JsonProperty("rotate", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("rotate")]
- public long? Rotate { get; set; }
+ public long? Rotate
+ {
+ get => _display.ReadLong(Models.Internal.Display.RotateKey);
+ set => _display[Models.Internal.Display.RotateKey] = value;
+ }
[JsonIgnore]
public bool RotateSpecified { get { return Rotate != null; } }
@@ -42,7 +55,11 @@ namespace SabreTools.DatItems.Formats
/// Determines if display is flipped in the X-coordinates
///
[JsonProperty("flipx", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("flipx")]
- public bool? FlipX { get; set; }
+ public bool? FlipX
+ {
+ get => _display.ReadBool(Models.Internal.Display.FlipXKey);
+ set => _display[Models.Internal.Display.FlipXKey] = value;
+ }
[JsonIgnore]
public bool FlipXSpecified { get { return FlipX != null; } }
@@ -51,7 +68,11 @@ namespace SabreTools.DatItems.Formats
/// Display width
///
[JsonProperty("width", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("width")]
- public long? Width { get; set; }
+ public long? Width
+ {
+ get => _display.ReadLong(Models.Internal.Display.WidthKey);
+ set => _display[Models.Internal.Display.WidthKey] = value;
+ }
[JsonIgnore]
public bool WidthSpecified { get { return Width != null; } }
@@ -60,7 +81,11 @@ namespace SabreTools.DatItems.Formats
/// Display height
///
[JsonProperty("height", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("height")]
- public long? Height { get; set; }
+ public long? Height
+ {
+ get => _display.ReadLong(Models.Internal.Display.HeightKey);
+ set => _display[Models.Internal.Display.HeightKey] = value;
+ }
[JsonIgnore]
public bool HeightSpecified { get { return Height != null; } }
@@ -69,7 +94,11 @@ namespace SabreTools.DatItems.Formats
/// Refresh rate
///
[JsonProperty("refresh", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("refresh")]
- public double? Refresh { get; set; }
+ public double? Refresh
+ {
+ get => _display.ReadDouble(Models.Internal.Display.RefreshKey);
+ set => _display[Models.Internal.Display.RefreshKey] = value;
+ }
[JsonIgnore]
public bool RefreshSpecified { get { return Refresh != null; } }
@@ -78,7 +107,11 @@ namespace SabreTools.DatItems.Formats
/// Pixel clock timer
///
[JsonProperty("pixclock", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("pixclock")]
- public long? PixClock { get; set; }
+ public long? PixClock
+ {
+ get => _display.ReadLong(Models.Internal.Display.PixClockKey);
+ set => _display[Models.Internal.Display.PixClockKey] = value;
+ }
[JsonIgnore]
public bool PixClockSpecified { get { return PixClock != null; } }
@@ -87,7 +120,11 @@ namespace SabreTools.DatItems.Formats
/// Total horizontal lines
///
[JsonProperty("htotal", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("htotal")]
- public long? HTotal { get; set; }
+ public long? HTotal
+ {
+ get => _display.ReadLong(Models.Internal.Display.HTotalKey);
+ set => _display[Models.Internal.Display.HTotalKey] = value;
+ }
[JsonIgnore]
public bool HTotalSpecified { get { return HTotal != null; } }
@@ -96,7 +133,11 @@ namespace SabreTools.DatItems.Formats
/// Horizontal blank end
///
[JsonProperty("hbend", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("hbend")]
- public long? HBEnd { get; set; }
+ public long? HBEnd
+ {
+ get => _display.ReadLong(Models.Internal.Display.HBEndKey);
+ set => _display[Models.Internal.Display.HBEndKey] = value;
+ }
[JsonIgnore]
public bool HBEndSpecified { get { return HBEnd != null; } }
@@ -105,7 +146,11 @@ namespace SabreTools.DatItems.Formats
/// Horizontal blank start
///
[JsonProperty("hbstart", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("hbstart")]
- public long? HBStart { get; set; }
+ public long? HBStart
+ {
+ get => _display.ReadLong(Models.Internal.Display.HBStartKey);
+ set => _display[Models.Internal.Display.HBStartKey] = value;
+ }
[JsonIgnore]
public bool HBStartSpecified { get { return HBStart != null; } }
@@ -114,7 +159,11 @@ namespace SabreTools.DatItems.Formats
/// Total vertical lines
///
[JsonProperty("vtotal", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("vtotal")]
- public long? VTotal { get; set; }
+ public long? VTotal
+ {
+ get => _display.ReadLong(Models.Internal.Display.VTotalKey);
+ set => _display[Models.Internal.Display.VTotalKey] = value;
+ }
[JsonIgnore]
public bool VTotalSpecified { get { return VTotal != null; } }
@@ -123,7 +172,11 @@ namespace SabreTools.DatItems.Formats
/// Vertical blank end
///
[JsonProperty("vbend", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("vbend")]
- public long? VBEnd { get; set; }
+ public long? VBEnd
+ {
+ get => _display.ReadLong(Models.Internal.Display.VBEndKey);
+ set => _display[Models.Internal.Display.VBEndKey] = value;
+ }
[JsonIgnore]
public bool VBEndSpecified { get { return VBEnd != null; } }
@@ -132,11 +185,21 @@ namespace SabreTools.DatItems.Formats
/// Vertical blank start
///
[JsonProperty("vbstart", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("vbstart")]
- public long? VBStart { get; set; }
+ public long? VBStart
+ {
+ get => _display.ReadLong(Models.Internal.Display.VBStartKey);
+ set => _display[Models.Internal.Display.VBStartKey] = value;
+ }
[JsonIgnore]
public bool VBStartSpecified { get { return VBStart != null; } }
+ ///
+ /// Internal Display model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Display _display = new();
+
#endregion
#region Constructors
@@ -161,24 +224,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Tag = this.Tag,
- DisplayType = this.DisplayType,
- Rotate = this.Rotate,
- FlipX = this.FlipX,
- Width = this.Width,
- Height = this.Height,
- Refresh = this.Refresh,
- PixClock = this.PixClock,
- HTotal = this.HTotal,
- HBEnd = this.HBEnd,
- HBStart = this.HBStart,
- VTotal = this.VTotal,
- VBEnd = this.VBEnd,
- VBStart = this.VBStart,
+ _display = this._display?.Clone() as Models.Internal.Display ?? new Models.Internal.Display(),
};
}
@@ -187,30 +237,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
// If we don't have a Display, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType || other is not Display otherInternal)
return false;
- // Otherwise, treat it as a Display
- Display newOther = other as Display;
-
- // If the Display information matches
- return (Tag == newOther.Tag
- && DisplayType == newOther.DisplayType
- && Rotate == newOther.Rotate
- && FlipX == newOther.FlipX
- && Width == newOther.Width
- && Height == newOther.Height
- && Refresh == newOther.Refresh
- && PixClock == newOther.PixClock
- && HTotal == newOther.HTotal
- && HBEnd == newOther.HBEnd
- && HBStart == newOther.HBStart
- && VTotal == newOther.VTotal
- && VBEnd == newOther.VBEnd
- && VBStart == newOther.VBStart);
+ // Compare the internal models
+ return _display.EqualTo(otherInternal._display);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/Driver.cs b/SabreTools.DatItems/Formats/Driver.cs
index 341e794a..a1b433fe 100644
--- a/SabreTools.DatItems/Formats/Driver.cs
+++ b/SabreTools.DatItems/Formats/Driver.cs
@@ -2,6 +2,7 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using SabreTools.Core;
+using SabreTools.Core.Tools;
namespace SabreTools.DatItems.Formats
{
@@ -21,7 +22,11 @@ namespace SabreTools.DatItems.Formats
///
[JsonProperty("status", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("status")]
[JsonConverter(typeof(StringEnumConverter))]
- public SupportStatus Status { get; set; }
+ public SupportStatus Status
+ {
+ get => _driver.ReadString(Models.Internal.Driver.StatusKey).AsSupportStatus();
+ set => _driver[Models.Internal.Driver.StatusKey] = value.FromSupportStatus();
+ }
[JsonIgnore]
public bool StatusSpecified { get { return Status != SupportStatus.NULL; } }
@@ -31,7 +36,11 @@ namespace SabreTools.DatItems.Formats
///
[JsonProperty("emulation", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("emulation")]
[JsonConverter(typeof(StringEnumConverter))]
- public SupportStatus Emulation { get; set; }
+ public SupportStatus Emulation
+ {
+ get => _driver.ReadString(Models.Internal.Driver.EmulationKey).AsSupportStatus();
+ set => _driver[Models.Internal.Driver.EmulationKey] = value.FromSupportStatus();
+ }
[JsonIgnore]
public bool EmulationSpecified { get { return Emulation != SupportStatus.NULL; } }
@@ -41,7 +50,11 @@ namespace SabreTools.DatItems.Formats
///
[JsonProperty("cocktail", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("cocktail")]
[JsonConverter(typeof(StringEnumConverter))]
- public SupportStatus Cocktail { get; set; }
+ public SupportStatus Cocktail
+ {
+ get => _driver.ReadString(Models.Internal.Driver.CocktailKey).AsSupportStatus();
+ set => _driver[Models.Internal.Driver.CocktailKey] = value.FromSupportStatus();
+ }
[JsonIgnore]
public bool CocktailSpecified { get { return Cocktail != SupportStatus.NULL; } }
@@ -51,7 +64,11 @@ namespace SabreTools.DatItems.Formats
///
[JsonProperty("savestate", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("savestate")]
[JsonConverter(typeof(StringEnumConverter))]
- public Supported SaveState { get; set; }
+ public Supported SaveState
+ {
+ get => _driver.ReadString(Models.Internal.Driver.SaveStateKey).AsSupported();
+ set => _driver[Models.Internal.Driver.SaveStateKey] = value.FromSupported(verbose: true);
+ }
[JsonIgnore]
public bool SaveStateSpecified { get { return SaveState != Supported.NULL; } }
@@ -60,7 +77,11 @@ namespace SabreTools.DatItems.Formats
/// Requires artwork
///
[JsonProperty("requiresartwork", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("requiresartwork")]
- public bool? RequiresArtwork { get; set; }
+ public bool? RequiresArtwork
+ {
+ get => _driver.ReadBool(Models.Internal.Driver.RequiresArtworkKey);
+ set => _driver[Models.Internal.Driver.RequiresArtworkKey] = value;
+ }
[JsonIgnore]
public bool RequiresArtworkSpecified { get { return RequiresArtwork != null; } }
@@ -69,7 +90,11 @@ namespace SabreTools.DatItems.Formats
/// Unofficial
///
[JsonProperty("unofficial", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("unofficial")]
- public bool? Unofficial { get; set; }
+ public bool? Unofficial
+ {
+ get => _driver.ReadBool(Models.Internal.Driver.UnofficialKey);
+ set => _driver[Models.Internal.Driver.UnofficialKey] = value;
+ }
[JsonIgnore]
public bool UnofficialSpecified { get { return Unofficial != null; } }
@@ -78,7 +103,11 @@ namespace SabreTools.DatItems.Formats
/// No sound hardware
///
[JsonProperty("nosoundhardware", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("nosoundhardware")]
- public bool? NoSoundHardware { get; set; }
+ public bool? NoSoundHardware
+ {
+ get => _driver.ReadBool(Models.Internal.Driver.NoSoundHardwareKey);
+ set => _driver[Models.Internal.Driver.NoSoundHardwareKey] = value;
+ }
[JsonIgnore]
public bool NoSoundHardwareSpecified { get { return NoSoundHardware != null; } }
@@ -87,11 +116,21 @@ namespace SabreTools.DatItems.Formats
/// Incomplete
///
[JsonProperty("incomplete", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("incomplete")]
- public bool? Incomplete { get; set; }
+ public bool? Incomplete
+ {
+ get => _driver.ReadBool(Models.Internal.Driver.IncompleteKey);
+ set => _driver[Models.Internal.Driver.IncompleteKey] = value;
+ }
[JsonIgnore]
public bool IncompleteSpecified { get { return Incomplete != null; } }
+ ///
+ /// Internal Driver model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Driver _driver = new();
+
#endregion
#region Constructors
@@ -116,18 +155,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Status = this.Status,
- Emulation = this.Emulation,
- Cocktail = this.Cocktail,
- SaveState = this.SaveState,
- RequiresArtwork = this.RequiresArtwork,
- Unofficial = this.Unofficial,
- NoSoundHardware = this.NoSoundHardware,
- Incomplete = this.Incomplete,
+ _driver = this._driver?.Clone() as Models.Internal.Driver ?? new Models.Internal.Driver(),
};
}
@@ -136,24 +168,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
// If we don't have a Driver, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType || other is not Driver otherInternal)
return false;
- // Otherwise, treat it as a Driver
- Driver newOther = other as Driver;
-
- // If the Feature information matches
- return (Status == newOther.Status
- && Emulation == newOther.Emulation
- && Cocktail == newOther.Cocktail
- && SaveState == newOther.SaveState
- && RequiresArtwork == newOther.RequiresArtwork
- && Unofficial == newOther.Unofficial
- && NoSoundHardware == newOther.NoSoundHardware
- && Incomplete == newOther.Incomplete);
+ // Compare the internal models
+ return _driver.EqualTo(otherInternal._driver);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/Extension.cs b/SabreTools.DatItems/Formats/Extension.cs
index d2c86db6..48d00a1a 100644
--- a/SabreTools.DatItems/Formats/Extension.cs
+++ b/SabreTools.DatItems/Formats/Extension.cs
@@ -16,17 +16,27 @@ namespace SabreTools.DatItems.Formats
/// Name of the item
///
[JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _extension.ReadString(Models.Internal.Extension.NameKey);
+ set => _extension[Models.Internal.Extension.NameKey] = value;
+ }
+
+ ///
+ /// Internal Extension model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Extension _extension = new();
#endregion
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -53,11 +63,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Name = this.Name,
+ _extension = this._extension?.Clone() as Models.Internal.Extension ?? new Models.Internal.Extension(),
};
}
@@ -66,17 +76,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
- // If we don't have a Extension, return false
- if (ItemType != other.ItemType)
+ // If we don't have a Adjuster, return false
+ if (ItemType != other?.ItemType || other is not Extension otherInternal)
return false;
- // Otherwise, treat it as a Extension
- Extension newOther = other as Extension;
-
- // If the Extension information matches
- return (Name == newOther.Name);
+ // Compare the internal models
+ return _extension.EqualTo(otherInternal._extension);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/Feature.cs b/SabreTools.DatItems/Formats/Feature.cs
index 5cfdb7ea..d70472dd 100644
--- a/SabreTools.DatItems/Formats/Feature.cs
+++ b/SabreTools.DatItems/Formats/Feature.cs
@@ -2,6 +2,7 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using SabreTools.Core;
+using SabreTools.Core.Tools;
namespace SabreTools.DatItems.Formats
{
@@ -18,7 +19,11 @@ namespace SabreTools.DatItems.Formats
///
[JsonProperty("type", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("type")]
[JsonConverter(typeof(StringEnumConverter))]
- public FeatureType Type { get; set; }
+ public FeatureType Type
+ {
+ get => _feature.ReadString(Models.Internal.Feature.FeatureTypeKey).AsFeatureType();
+ set => _feature[Models.Internal.Feature.FeatureTypeKey] = value.FromFeatureType();
+ }
[JsonIgnore]
public bool TypeSpecified { get { return Type != FeatureType.NULL; } }
@@ -28,7 +33,11 @@ namespace SabreTools.DatItems.Formats
///
[JsonProperty("status", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("status")]
[JsonConverter(typeof(StringEnumConverter))]
- public FeatureStatus Status { get; set; }
+ public FeatureStatus Status
+ {
+ get => _feature.ReadString(Models.Internal.Feature.StatusKey).AsFeatureStatus();
+ set => _feature[Models.Internal.Feature.StatusKey] = value.FromFeatureStatus();
+ }
[JsonIgnore]
public bool StatusSpecified { get { return Status != FeatureStatus.NULL; } }
@@ -38,11 +47,21 @@ namespace SabreTools.DatItems.Formats
///
[JsonProperty("overall", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("overall")]
[JsonConverter(typeof(StringEnumConverter))]
- public FeatureStatus Overall { get; set; }
+ public FeatureStatus Overall
+ {
+ get => _feature.ReadString(Models.Internal.Feature.OverallKey).AsFeatureStatus();
+ set => _feature[Models.Internal.Feature.OverallKey] = value.FromFeatureStatus();
+ }
[JsonIgnore]
public bool OverallSpecified { get { return Overall != FeatureStatus.NULL; } }
+ ///
+ /// Internal Feature model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Feature _feature = new();
+
#endregion
#region Constructors
@@ -67,13 +86,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Type = this.Type,
- Status = this.Status,
- Overall = this.Overall,
+ _feature = this._feature?.Clone() as Models.Internal.Feature ?? new Models.Internal.Feature(),
};
}
@@ -82,19 +99,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
// If we don't have a Feature, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType || other is not Feature otherInternal)
return false;
- // Otherwise, treat it as a Feature
- Feature newOther = other as Feature;
-
- // If the Feature information matches
- return (Type == newOther.Type
- && Status == newOther.Status
- && Overall == newOther.Overall);
+ // Compare the internal models
+ return _feature.EqualTo(otherInternal._feature);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/File.cs b/SabreTools.DatItems/Formats/File.cs
index 41ff085b..ebd021a7 100644
--- a/SabreTools.DatItems/Formats/File.cs
+++ b/SabreTools.DatItems/Formats/File.cs
@@ -17,10 +17,10 @@ namespace SabreTools.DatItems.Formats
{
#region Private instance variables
- private byte[] _crc; // 8 bytes
- private byte[] _md5; // 16 bytes
- private byte[] _sha1; // 20 bytes
- private byte[] _sha256; // 32 bytes
+ private byte[]? _crc; // 8 bytes
+ private byte[]? _md5; // 16 bytes
+ private byte[]? _sha1; // 20 bytes
+ private byte[]? _sha256; // 32 bytes
#endregion
@@ -30,13 +30,13 @@ namespace SabreTools.DatItems.Formats
/// ID value
///
[JsonProperty("id", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("id")]
- public string Id { get; set; }
+ public string? Id { get; set; }
///
/// Extension value
///
[JsonProperty("extension", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("extension")]
- public string Extension { get; set; }
+ public string? Extension { get; set; }
///
/// Byte size of the rom
@@ -51,47 +51,47 @@ namespace SabreTools.DatItems.Formats
/// File CRC32 hash
///
[JsonProperty("crc", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("crc")]
- public string CRC
+ public string? CRC
{
get { return _crc.IsNullOrEmpty() ? null : Utilities.ByteArrayToString(_crc); }
- set { _crc = (value == "null" ? Constants.CRCZeroBytes : Utilities.StringToByteArray(CleanCRC32(value))); }
+ set { _crc = (value == "null" ? Constants.CRCZeroBytes : Utilities.StringToByteArray(TextHelper.NormalizeCRC32(value))); }
}
///
/// File MD5 hash
///
[JsonProperty("md5", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("md5")]
- public string MD5
+ public string? MD5
{
get { return _md5.IsNullOrEmpty() ? null : Utilities.ByteArrayToString(_md5); }
- set { _md5 = Utilities.StringToByteArray(CleanMD5(value)); }
+ set { _md5 = Utilities.StringToByteArray(TextHelper.NormalizeMD5(value)); }
}
///
/// File SHA-1 hash
///
[JsonProperty("sha1", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("sha1")]
- public string SHA1
+ public string? SHA1
{
get { return _sha1.IsNullOrEmpty() ? null : Utilities.ByteArrayToString(_sha1); }
- set { _sha1 = Utilities.StringToByteArray(CleanSHA1(value)); }
+ set { _sha1 = Utilities.StringToByteArray(TextHelper.NormalizeSHA1(value)); }
}
///
/// File SHA-256 hash
///
[JsonProperty("sha256", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("sha256")]
- public string SHA256
+ public string? SHA256
{
get { return _sha256.IsNullOrEmpty() ? null : Utilities.ByteArrayToString(_sha256); }
- set { _sha256 = Utilities.StringToByteArray(CleanSHA256(value)); }
+ set { _sha256 = Utilities.StringToByteArray(TextHelper.NormalizeSHA256(value)); }
}
///
/// Format value
///
[JsonProperty("format", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("format")]
- public string Format { get; set; }
+ public string? Format { get; set; }
#endregion // Fields
@@ -132,8 +132,8 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
Id = this.Id,
@@ -174,8 +174,8 @@ namespace SabreTools.DatItems.Formats
ItemType = ItemType.Rom,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
CRC = this.CRC,
@@ -192,31 +192,31 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
bool dupefound = false;
// If we don't have a file, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType)
return dupefound;
// Otherwise, treat it as a File
- File newOther = other as File;
+ File? newOther = other as File;
// If all hashes are empty, then they're dupes
- if (!HasHashes() && !newOther.HasHashes())
+ if (!HasHashes() && !newOther!.HasHashes())
{
dupefound = true;
}
// If we have a file that has no known size, rely on the hashes only
- else if (Size == null && HashMatch(newOther))
+ else if (Size == null && HashMatch(newOther!))
{
dupefound = true;
}
// Otherwise if we get a partial match
- else if (Size == newOther.Size && HashMatch(newOther))
+ else if (Size == newOther!.Size && HashMatch(newOther))
{
dupefound = true;
}
@@ -331,7 +331,7 @@ namespace SabreTools.DatItems.Formats
public override string GetKey(ItemKey bucketedBy, bool lower = true, bool norename = true)
{
// Set the output key as the default blank string
- string key;
+ string? key;
// Now determine what the key should be based on the bucketedBy value
switch (bucketedBy)
diff --git a/SabreTools.DatItems/Formats/Info.cs b/SabreTools.DatItems/Formats/Info.cs
index bff88885..611e0b6d 100644
--- a/SabreTools.DatItems/Formats/Info.cs
+++ b/SabreTools.DatItems/Formats/Info.cs
@@ -16,23 +16,37 @@ namespace SabreTools.DatItems.Formats
/// Name of the item
///
[JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _info.ReadString(Models.Internal.Info.NameKey);
+ set => _info[Models.Internal.Info.NameKey] = value;
+ }
///
/// Information value
///
[JsonProperty("value"), XmlElement("value")]
- public string Value { get; set; }
+ public string? Value
+ {
+ get => _info.ReadString(Models.Internal.Info.ValueKey);
+ set => _info[Models.Internal.Info.ValueKey] = value;
+ }
+
+ ///
+ /// Internal Info model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Info _info = new();
#endregion
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -59,12 +73,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Name = this.Name,
- Value = this.Value,
+ _info = this._info?.Clone() as Models.Internal.Info ?? new Models.Internal.Info(),
};
}
@@ -73,18 +86,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
- // If we don't have a sample, return false
- if (ItemType != other.ItemType)
+ // If we don't have a Info, return false
+ if (ItemType != other?.ItemType || other is not Info otherInternal)
return false;
- // Otherwise, treat it as a Info
- Info newOther = other as Info;
-
- // If the archive information matches
- return (Name == newOther.Name
- && Value == newOther.Value);
+ // Compare the internal models
+ return _info.EqualTo(otherInternal._info);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/Input.cs b/SabreTools.DatItems/Formats/Input.cs
index ab1129df..f38fee88 100644
--- a/SabreTools.DatItems/Formats/Input.cs
+++ b/SabreTools.DatItems/Formats/Input.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Linq;
using System.Xml.Serialization;
using Newtonsoft.Json;
using SabreTools.Core;
@@ -17,7 +18,11 @@ namespace SabreTools.DatItems.Formats
/// Input service ID
///
[JsonProperty("service", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("service")]
- public bool? Service { get; set; }
+ public bool? Service
+ {
+ get => _input.ReadBool(Models.Internal.Input.ServiceKey);
+ set => _input[Models.Internal.Input.ServiceKey] = value;
+ }
[JsonIgnore]
public bool ServiceSpecified { get { return Service != null; } }
@@ -26,7 +31,11 @@ namespace SabreTools.DatItems.Formats
/// Determins if this has a tilt sensor
///
[JsonProperty("tilt", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("tilt")]
- public bool? Tilt { get; set; }
+ public bool? Tilt
+ {
+ get => _input.ReadBool(Models.Internal.Input.TiltKey);
+ set => _input[Models.Internal.Input.TiltKey] = value;
+ }
[JsonIgnore]
public bool TiltSpecified { get { return Tilt != null; } }
@@ -35,7 +44,11 @@ namespace SabreTools.DatItems.Formats
/// Number of players on the input
///
[JsonProperty("players", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("players")]
- public long? Players { get; set; }
+ public long? Players
+ {
+ get => _input.ReadLong(Models.Internal.Input.PlayersKey);
+ set => _input[Models.Internal.Input.PlayersKey] = value;
+ }
[JsonIgnore]
public bool PlayersSpecified { get { return Players != null; } }
@@ -44,7 +57,11 @@ namespace SabreTools.DatItems.Formats
/// Number of coins required
///
[JsonProperty("coins", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("coins")]
- public long? Coins { get; set; }
+ public long? Coins
+ {
+ get => _input.ReadLong(Models.Internal.Input.CoinsKey);
+ set => _input[Models.Internal.Input.CoinsKey] = value;
+ }
[JsonIgnore]
public bool CoinsSpecified { get { return Coins != null; } }
@@ -53,11 +70,21 @@ namespace SabreTools.DatItems.Formats
/// Set of controls for the input
///
[JsonProperty("controls", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("controls")]
- public List Controls { get; set; }
+ public List? Controls
+ {
+ get => _input.Read(Models.Internal.Input.ControlKey)?.ToList();
+ set => _input[Models.Internal.Input.ControlKey] = value?.ToArray();
+ }
[JsonIgnore]
public bool ControlsSpecified { get { return Controls != null && Controls.Count > 0; } }
+ ///
+ /// Internal Input model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Input _input = new();
+
#endregion
#region Constructors
@@ -82,15 +109,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Service = this.Service,
- Tilt = this.Tilt,
- Players = this.Players,
- Coins = this.Coins,
- Controls = this.Controls,
+ _input = this._input?.Clone() as Models.Internal.Input ?? new Models.Internal.Input(),
};
}
@@ -99,33 +122,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
// If we don't have a Input, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType || other is not Input otherInternal)
return false;
- // Otherwise, treat it as a Input
- Input newOther = other as Input;
-
- // If the Input information matches
- bool match = (Service == newOther.Service
- && Tilt == newOther.Tilt
- && Players == newOther.Players
- && Coins == newOther.Coins);
- if (!match)
- return match;
-
- // If the controls match
- if (ControlsSpecified)
- {
- foreach (Control control in Controls)
- {
- match &= newOther.Controls.Contains(control);
- }
- }
-
- return match;
+ // Compare the internal models
+ return _input.EqualTo(otherInternal._input);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/Instance.cs b/SabreTools.DatItems/Formats/Instance.cs
index 3aa1fef7..b77242fe 100644
--- a/SabreTools.DatItems/Formats/Instance.cs
+++ b/SabreTools.DatItems/Formats/Instance.cs
@@ -16,23 +16,37 @@ namespace SabreTools.DatItems.Formats
/// Name of the item
///
[JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _instance.ReadString(Models.Internal.Instance.NameKey);
+ set => _instance[Models.Internal.Instance.NameKey] = value;
+ }
///
/// Short name for the instance
///
[JsonProperty("briefname", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("briefname")]
- public string BriefName { get; set; }
+ public string? BriefName
+ {
+ get => _instance.ReadString(Models.Internal.Instance.BriefNameKey);
+ set => _instance[Models.Internal.Instance.BriefNameKey] = value;
+ }
+
+ ///
+ /// Internal Instance model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Instance _instance = new();
#endregion
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -59,12 +73,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Name = this.Name,
- BriefName = this.BriefName,
+ _instance = this._instance?.Clone() as Models.Internal.Instance ?? new Models.Internal.Instance(),
};
}
@@ -73,18 +86,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
// If we don't have a Instance, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType || other is not Instance otherInternal)
return false;
- // Otherwise, treat it as a Instance
- Instance newOther = other as Instance;
-
- // If the Instance information matches
- return (Name == newOther.Name
- && BriefName == newOther.BriefName);
+ // Compare the internal models
+ return _instance.EqualTo(otherInternal._instance);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/Location.cs b/SabreTools.DatItems/Formats/Location.cs
deleted file mode 100644
index 1484c13f..00000000
--- a/SabreTools.DatItems/Formats/Location.cs
+++ /dev/null
@@ -1,106 +0,0 @@
-using System.Xml.Serialization;
-using Newtonsoft.Json;
-using SabreTools.Core;
-
-namespace SabreTools.DatItems.Formats
-{
- ///
- /// Represents one conflocation or diplocation
- ///
- [JsonObject("location"), XmlRoot("location")]
- public class Location : DatItem
- {
- #region Fields
-
- ///
- /// Location name
- ///
- [JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
-
- ///
- /// Location ID
- ///
- [JsonProperty("number", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("number")]
- public long? Number { get; set; }
-
- [JsonIgnore]
- public bool NumberSpecified { get { return Number != null; } }
-
- ///
- /// Determines if location is inverted or not
- ///
- [JsonProperty("inverted", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("inverted")]
- public bool? Inverted { get; set; }
-
- [JsonIgnore]
- public bool InvertedSpecified { get { return Inverted != null; } }
-
- #endregion
-
- #region Accessors
-
- ///
- public override string GetName() => Name;
-
- ///
- public override void SetName(string name) => Name = name;
-
- #endregion
-
- #region Constructors
-
- ///
- /// Create a default, empty Location object
- ///
- public Location()
- {
- Name = string.Empty;
- ItemType = ItemType.Location;
- }
-
- #endregion
-
- #region Cloning Methods
-
- ///
- public override object Clone()
- {
- return new Location()
- {
- ItemType = this.ItemType,
- DupeType = this.DupeType,
-
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
- Remove = this.Remove,
-
- Name = this.Name,
- Number = this.Number,
- Inverted = this.Inverted,
- };
- }
-
- #endregion
-
- #region Comparision Methods
-
- ///
- public override bool Equals(DatItem other)
- {
- // If we don't have a Location, return false
- if (ItemType != other.ItemType)
- return false;
-
- // Otherwise, treat it as a Location
- Location newOther = other as Location;
-
- // If the Location information matches
- return (Name == newOther.Name
- && Number == newOther.Number
- && Inverted == newOther.Inverted);
- }
-
- #endregion
- }
-}
diff --git a/SabreTools.DatItems/Formats/Media.cs b/SabreTools.DatItems/Formats/Media.cs
index 8bd56da3..a2cb91d9 100644
--- a/SabreTools.DatItems/Formats/Media.cs
+++ b/SabreTools.DatItems/Formats/Media.cs
@@ -1,5 +1,4 @@
-using System.Text;
-using System.Xml.Serialization;
+using System.Xml.Serialization;
using Newtonsoft.Json;
using SabreTools.Core;
using SabreTools.Core.Tools;
@@ -13,72 +12,73 @@ namespace SabreTools.DatItems.Formats
[JsonObject("media"), XmlRoot("media")]
public class Media : DatItem
{
- #region Private instance variables
-
- private byte[] _md5; // 16 bytes
- private byte[] _sha1; // 20 bytes
- private byte[] _sha256; // 32 bytes
- private byte[] _spamsum; // variable bytes
-
- #endregion
-
#region Fields
///
/// Name of the item
///
[JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _media.ReadString(Models.Internal.Media.NameKey);
+ set => _media[Models.Internal.Media.NameKey] = value;
+ }
///
/// Data MD5 hash
///
[JsonProperty("md5", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("md5")]
- public string MD5
+ public string? MD5
{
- get { return _md5.IsNullOrEmpty() ? null : Utilities.ByteArrayToString(_md5); }
- set { _md5 = Utilities.StringToByteArray(CleanMD5(value)); }
+ get => _media.ReadString(Models.Internal.Media.MD5Key);
+ set => _media[Models.Internal.Media.MD5Key] = TextHelper.NormalizeMD5(value);
}
///
/// Data SHA-1 hash
///
[JsonProperty("sha1", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("sha1")]
- public string SHA1
+ public string? SHA1
{
- get { return _sha1.IsNullOrEmpty() ? null : Utilities.ByteArrayToString(_sha1); }
- set { _sha1 = Utilities.StringToByteArray(CleanSHA1(value)); }
+ get => _media.ReadString(Models.Internal.Media.SHA1Key);
+ set => _media[Models.Internal.Media.SHA1Key] = TextHelper.NormalizeSHA1(value);
}
///
/// Data SHA-256 hash
///
[JsonProperty("sha256", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("sha256")]
- public string SHA256
+ public string? SHA256
{
- get { return _sha256.IsNullOrEmpty() ? null : Utilities.ByteArrayToString(_sha256); }
- set { _sha256 = Utilities.StringToByteArray(CleanSHA256(value)); }
+ get => _media.ReadString(Models.Internal.Media.SHA256Key);
+ set => _media[Models.Internal.Media.SHA256Key] = TextHelper.NormalizeSHA256(value);
}
///
/// File SpamSum fuzzy hash
///
[JsonProperty("spamsum", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("spamsum")]
- public string SpamSum
+ public string? SpamSum
{
- get { return _spamsum.IsNullOrEmpty() ? null : Encoding.UTF8.GetString(_spamsum); }
- set { _spamsum = Encoding.UTF8.GetBytes(value ?? string.Empty); }
+ get => _media.ReadString(Models.Internal.Media.SpamSumKey);
+ set => _media[Models.Internal.Media.SpamSumKey] = value;
}
+ ///
+ /// Internal Media model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Media _media = new();
+
#endregion
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -101,10 +101,10 @@ namespace SabreTools.DatItems.Formats
public Media(BaseFile baseFile)
{
Name = baseFile.Filename;
- _md5 = baseFile.MD5;
- _sha1 = baseFile.SHA1;
- _sha256 = baseFile.SHA256;
- _spamsum = baseFile.SpamSum;
+ MD5 = Utilities.ByteArrayToString(baseFile.MD5);
+ SHA1 = Utilities.ByteArrayToString(baseFile.SHA1);
+ SHA256 = Utilities.ByteArrayToString(baseFile.SHA256);
+ SpamSum = Utilities.ByteArrayToString(baseFile.SpamSum);
ItemType = ItemType.Media;
DupeType = 0x00;
@@ -122,15 +122,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Name = this.Name,
- _md5 = this._md5,
- _sha1 = this._sha1,
- _sha256 = this._sha256,
- _spamsum = this._spamsum,
+ _media = this._media?.Clone() as Models.Internal.Media ?? new Models.Internal.Media(),
};
}
@@ -143,10 +139,10 @@ namespace SabreTools.DatItems.Formats
{
Filename = this.Name,
Parent = this.Machine?.Name,
- MD5 = this._md5,
- SHA1 = this._sha1,
- SHA256 = this._sha256,
- SpamSum = this._spamsum,
+ MD5 = Utilities.StringToByteArray(this.MD5),
+ SHA1 = Utilities.StringToByteArray(this.SHA1),
+ SHA256 = Utilities.StringToByteArray(this.SHA256),
+ SpamSum = Utilities.StringToByteArray(this.SpamSum),
};
}
@@ -161,8 +157,8 @@ namespace SabreTools.DatItems.Formats
ItemType = ItemType.Rom,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
Name = this.Name + ".aif",
@@ -180,22 +176,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
- bool dupefound = false;
-
// If we don't have a Media, return false
- if (ItemType != other.ItemType)
- return dupefound;
+ if (ItemType != other?.ItemType || other is not Media otherInternal)
+ return false;
- // Otherwise, treat it as a Media
- Media newOther = other as Media;
-
- // If we get a partial match
- if (HashMatch(newOther))
- dupefound = true;
-
- return dupefound;
+ // Compare the internal models
+ return _media.EqualTo(otherInternal._media);
}
///
@@ -204,17 +192,17 @@ namespace SabreTools.DatItems.Formats
/// Media to fill information from
public void FillMissingInformation(Media other)
{
- if (_md5.IsNullOrEmpty() && !other._md5.IsNullOrEmpty())
- _md5 = other._md5;
+ if (string.IsNullOrWhiteSpace(MD5) && !string.IsNullOrWhiteSpace(other.MD5))
+ MD5 = other.MD5;
- if (_sha1.IsNullOrEmpty() && !other._sha1.IsNullOrEmpty())
- _sha1 = other._sha1;
+ if (string.IsNullOrWhiteSpace(SHA1) && !string.IsNullOrWhiteSpace(other.SHA1))
+ SHA1 = other.SHA1;
- if (_sha256.IsNullOrEmpty() && !other._sha256.IsNullOrEmpty())
- _sha256 = other._sha256;
+ if (string.IsNullOrWhiteSpace(SHA256) && !string.IsNullOrWhiteSpace(other.SHA256))
+ SHA256 = other.SHA256;
- if (_spamsum.IsNullOrEmpty() && !other._spamsum.IsNullOrEmpty())
- _spamsum = other._spamsum;
+ if (string.IsNullOrWhiteSpace(SpamSum) && !string.IsNullOrWhiteSpace(other.SpamSum))
+ SpamSum = other.SpamSum;
}
///
@@ -223,64 +211,18 @@ namespace SabreTools.DatItems.Formats
/// String representing the suffix
public string GetDuplicateSuffix()
{
- if (!_md5.IsNullOrEmpty())
+ if (!string.IsNullOrWhiteSpace(MD5))
return $"_{MD5}";
- else if (!_sha1.IsNullOrEmpty())
+ else if (!string.IsNullOrWhiteSpace(SHA1))
return $"_{SHA1}";
- else if (!_sha256.IsNullOrEmpty())
+ else if (!string.IsNullOrWhiteSpace(SHA256))
return $"_{SHA256}";
- else if (!_spamsum.IsNullOrEmpty())
+ else if (!string.IsNullOrWhiteSpace(SpamSum))
return $"_{SpamSum}";
else
return "_1";
}
- ///
- /// Returns if there are no, non-empty hashes in common with another Media
- ///
- /// Media to compare against
- /// True if at least one hash is not mutually exclusive, false otherwise
- private bool HasCommonHash(Media other)
- {
- return !(_md5.IsNullOrEmpty() ^ other._md5.IsNullOrEmpty())
- || !(_sha1.IsNullOrEmpty() ^ other._sha1.IsNullOrEmpty())
- || !(_sha256.IsNullOrEmpty() ^ other._sha256.IsNullOrEmpty())
- || !(_spamsum.IsNullOrEmpty() ^ other._spamsum.IsNullOrEmpty());
- }
-
- ///
- /// Returns if the Media contains any hashes
- ///
- /// True if any hash exists, false otherwise
- private bool HasHashes()
- {
- return !_md5.IsNullOrEmpty()
- || !_sha1.IsNullOrEmpty()
- || !_sha256.IsNullOrEmpty()
- || !_spamsum.IsNullOrEmpty();
- }
-
- ///
- /// Returns if any hashes are common with another Media
- ///
- /// Media to compare against
- /// True if any hashes are in common, false otherwise
- private bool HashMatch(Media other)
- {
- // If either have no hashes, we return false, otherwise this would be a false positive
- if (!HasHashes() || !other.HasHashes())
- return false;
-
- // If neither have hashes in common, we return false, otherwise this would be a false positive
- if (!HasCommonHash(other))
- return false;
-
- // Return if all hashes match according to merge rules
- return ConditionalHashEquals(_md5, other._md5)
- && ConditionalHashEquals(_sha1, other._sha1)
- && ConditionalHashEquals(_spamsum, other._spamsum);
- }
-
#endregion
#region Sorting and Merging
@@ -289,7 +231,7 @@ namespace SabreTools.DatItems.Formats
public override string GetKey(ItemKey bucketedBy, bool lower = true, bool norename = true)
{
// Set the output key as the default blank string
- string key;
+ string? key;
// Now determine what the key should be based on the bucketedBy value
switch (bucketedBy)
diff --git a/SabreTools.DatItems/Formats/Part.cs b/SabreTools.DatItems/Formats/Part.cs
index fde80631..0b1c49cc 100644
--- a/SabreTools.DatItems/Formats/Part.cs
+++ b/SabreTools.DatItems/Formats/Part.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Linq;
using System.Xml.Serialization;
using Newtonsoft.Json;
using SabreTools.Core;
@@ -15,26 +16,44 @@ namespace SabreTools.DatItems.Formats
#region Fields
[JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _part.ReadString(Models.Internal.Part.NameKey);
+ set => _part[Models.Internal.Part.NameKey] = value;
+ }
[JsonProperty("interface"), XmlElement("interface")]
- public string Interface { get; set; }
+ public string? Interface
+ {
+ get => _part.ReadString(Models.Internal.Part.InterfaceKey);
+ set => _part[Models.Internal.Part.InterfaceKey] = value;
+ }
[JsonProperty("features", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("features")]
- public List Features { get; set; }
+ public List? Features
+ {
+ get => _part.Read(Models.Internal.Part.FeatureKey)?.ToList();
+ set => _part[Models.Internal.Part.FeatureKey] = value?.ToArray();
+ }
[JsonIgnore]
public bool FeaturesSpecified { get { return Features != null && Features.Count > 0; } }
+ ///
+ /// Internal Part model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Part _part = new();
+
#endregion
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -61,13 +80,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Name = this.Name,
- Interface = this.Interface,
- Features = this.Features,
+ _part = this._part?.Clone() as Models.Internal.Part ?? new Models.Internal.Part(),
};
}
@@ -76,31 +93,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
// If we don't have a Part, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType || other is not Part otherInternal)
return false;
- // Otherwise, treat it as a Part
- Part newOther = other as Part;
-
- // If the Part information matches
- bool match = (Name == newOther.Name
- && Interface == newOther.Interface);
- if (!match)
- return match;
-
- // If the features match
- if (FeaturesSpecified)
- {
- foreach (PartFeature partFeature in Features)
- {
- match &= newOther.Features.Contains(partFeature);
- }
- }
-
- return match;
+ // Compare the internal models
+ return _part.EqualTo(otherInternal._part);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/PartFeature.cs b/SabreTools.DatItems/Formats/PartFeature.cs
index 75cb0407..2182d416 100644
--- a/SabreTools.DatItems/Formats/PartFeature.cs
+++ b/SabreTools.DatItems/Formats/PartFeature.cs
@@ -16,23 +16,37 @@ namespace SabreTools.DatItems.Formats
/// Name of the item
///
[JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _feature.ReadString(Models.Internal.Feature.NameKey);
+ set => _feature[Models.Internal.Feature.NameKey] = value;
+ }
///
/// PartFeature value
///
[JsonProperty("value"), XmlElement("value")]
- public string Value { get; set; }
+ public string? Value
+ {
+ get => _feature.ReadString(Models.Internal.Feature.ValueKey);
+ set => _feature[Models.Internal.Feature.ValueKey] = value;
+ }
+
+ ///
+ /// Internal Feature model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Feature _feature = new();
#endregion
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -59,12 +73,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Name = this.Name,
- Value = this.Value,
+ _feature = this._feature?.Clone() as Models.Internal.Feature ?? new Models.Internal.Feature(),
};
}
@@ -73,18 +86,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
- // If we don't have a sample, return false
- if (ItemType != other.ItemType)
+ // If we don't have a PartFeature, return false
+ if (ItemType != other?.ItemType || other is not PartFeature otherInternal)
return false;
- // Otherwise, treat it as a PartFeature
- PartFeature newOther = other as PartFeature;
-
- // If the archive information matches
- return (Name == newOther.Name
- && Value == newOther.Value);
+ // Compare the internal models
+ return _feature.EqualTo(otherInternal._feature);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/Port.cs b/SabreTools.DatItems/Formats/Port.cs
index 8f26709d..2134e621 100644
--- a/SabreTools.DatItems/Formats/Port.cs
+++ b/SabreTools.DatItems/Formats/Port.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Linq;
using System.Xml.Serialization;
using Newtonsoft.Json;
using SabreTools.Core;
@@ -17,17 +18,31 @@ namespace SabreTools.DatItems.Formats
/// Tag for the port
///
[JsonProperty("tag", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("tag")]
- public string Tag { get; set; }
+ public string? Tag
+ {
+ get => _port.ReadString(Models.Internal.Port.TagKey);
+ set => _port[Models.Internal.Port.TagKey] = value;
+ }
///
/// List of analogs on the port
///
[JsonProperty("analogs", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("analogs")]
- public List Analogs { get; set; }
+ public List? Analogs
+ {
+ get => _port.Read(Models.Internal.Port.AnalogKey)?.ToList();
+ set => _port[Models.Internal.Port.AnalogKey] = value?.ToArray();
+ }
[JsonIgnore]
public bool AnalogsSpecified { get { return Analogs != null && Analogs.Count > 0; } }
+ ///
+ /// Internal Port model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Port _port = new();
+
#endregion
#region Constructors
@@ -52,12 +67,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Tag = this.Tag,
- Analogs = this.Analogs,
+ _port = this._port?.Clone() as Models.Internal.Port ?? new Models.Internal.Port(),
};
}
@@ -66,30 +80,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
// If we don't have a Port, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType || other is not Port otherInternal)
return false;
- // Otherwise, treat it as a Port
- Port newOther = other as Port;
-
- // If the Port information matches
- bool match = (Tag == newOther.Tag);
- if (!match)
- return match;
-
- // If the analogs match
- if (AnalogsSpecified)
- {
- foreach (Analog analog in Analogs)
- {
- match &= newOther.Analogs.Contains(analog);
- }
- }
-
- return match;
+ // Compare the internal models
+ return _port.EqualTo(otherInternal._port);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/RamOption.cs b/SabreTools.DatItems/Formats/RamOption.cs
index 7c3695c9..23ff09fb 100644
--- a/SabreTools.DatItems/Formats/RamOption.cs
+++ b/SabreTools.DatItems/Formats/RamOption.cs
@@ -16,13 +16,21 @@ namespace SabreTools.DatItems.Formats
/// Name of the item
///
[JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _ramOption.ReadString(Models.Internal.RamOption.NameKey);
+ set => _ramOption[Models.Internal.RamOption.NameKey] = value;
+ }
///
/// Determine whether the RamOption is default
///
[JsonProperty("default", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("default")]
- public bool? Default { get; set; }
+ public bool? Default
+ {
+ get => _ramOption.ReadBool(Models.Internal.RamOption.DefaultKey);
+ set => _ramOption[Models.Internal.RamOption.DefaultKey] = value;
+ }
[JsonIgnore]
public bool DefaultSpecified { get { return Default != null; } }
@@ -31,17 +39,27 @@ namespace SabreTools.DatItems.Formats
/// Determines the content of the RamOption
///
[JsonProperty("content", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("content")]
- public string Content { get; set; }
+ public string? Content
+ {
+ get => _ramOption.ReadString(Models.Internal.RamOption.ContentKey);
+ set => _ramOption[Models.Internal.RamOption.ContentKey] = value;
+ }
+
+ ///
+ /// Internal RamOption model
+ ///
+ [JsonIgnore]
+ private Models.Internal.RamOption _ramOption = new();
#endregion
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -68,13 +86,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Name = this.Name,
- Default = this.Default,
- Content = this.Content,
+ _ramOption = this._ramOption?.Clone() as Models.Internal.RamOption ?? new Models.Internal.RamOption(),
};
}
@@ -83,19 +99,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
- // If we don't have a RamOption, return false
- if (ItemType != other.ItemType)
+ // If we don't have a RamOption, return false
+ if (ItemType != other?.ItemType || other is not RamOption otherInternal)
return false;
- // Otherwise, treat it as a RamOption
- RamOption newOther = other as RamOption;
-
- // If the BiosSet information matches
- return (Name == newOther.Name
- && Default == newOther.Default
- && Content == newOther.Content);
+ // Compare the internal models
+ return _ramOption.EqualTo(otherInternal._ramOption);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/Release.cs b/SabreTools.DatItems/Formats/Release.cs
index 80ccf893..fe47fee3 100644
--- a/SabreTools.DatItems/Formats/Release.cs
+++ b/SabreTools.DatItems/Formats/Release.cs
@@ -16,44 +16,70 @@ namespace SabreTools.DatItems.Formats
/// Name of the item
///
[JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _release.ReadString(Models.Internal.Release.NameKey);
+ set => _release[Models.Internal.Release.NameKey] = value;
+ }
///
/// Release region(s)
///
[JsonProperty("region", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("region")]
- public string Region { get; set; }
+ public string? Region
+ {
+ get => _release.ReadString(Models.Internal.Release.RegionKey);
+ set => _release[Models.Internal.Release.RegionKey] = value;
+ }
///
/// Release language(s)
///
[JsonProperty("language", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("language")]
- public string Language { get; set; }
+ public string? Language
+ {
+ get => _release.ReadString(Models.Internal.Release.LanguageKey);
+ set => _release[Models.Internal.Release.LanguageKey] = value;
+ }
///
/// Date of release
///
[JsonProperty("date", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("date")]
- public string Date { get; set; }
+ public string? Date
+ {
+ get => _release.ReadString(Models.Internal.Release.DateKey);
+ set => _release[Models.Internal.Release.DateKey] = value;
+ }
///
/// Default release, if applicable
///
[JsonProperty("default", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("default")]
- public bool? Default { get; set; }
+ public bool? Default
+ {
+ get => _release.ReadBool(Models.Internal.Release.DefaultKey);
+ set => _release[Models.Internal.Release.DefaultKey] = value;
+ }
[JsonIgnore]
public bool DefaultSpecified { get { return Default != null; } }
+ ///
+ /// Internal Release model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Release _release = new();
+
#endregion
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -84,15 +110,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Name = this.Name,
- Region = this.Region,
- Language = this.Language,
- Date = this.Date,
- Default = this.Default,
+ _release = this._release?.Clone() as Models.Internal.Release ?? new Models.Internal.Release(),
};
}
@@ -101,21 +123,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
- // If we don't have a release return false
- if (ItemType != other.ItemType)
+ // If we don't have a Release, return false
+ if (ItemType != other?.ItemType || other is not Release otherInternal)
return false;
- // Otherwise, treat it as a Release
- Release newOther = other as Release;
-
- // If the archive information matches
- return (Name == newOther.Name
- && Region == newOther.Region
- && Language == newOther.Language
- && Date == newOther.Date
- && Default == newOther.Default);
+ // Compare the internal models
+ return _release.EqualTo(otherInternal._release);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/ReleaseDetails.cs b/SabreTools.DatItems/Formats/ReleaseDetails.cs
index 063e7b1b..94696135 100644
--- a/SabreTools.DatItems/Formats/ReleaseDetails.cs
+++ b/SabreTools.DatItems/Formats/ReleaseDetails.cs
@@ -18,31 +18,31 @@ namespace SabreTools.DatItems.Formats
///
/// TODO: Is this required?
[JsonProperty("id", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("id")]
- public string Id { get; set; }
+ public string? Id { get; set; }
///
/// Directory name value
///
[JsonProperty("dirname", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("dirname")]
- public string DirName { get; set; }
+ public string? DirName { get; set; }
///
/// Rom info value
///
[JsonProperty("rominfo", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("rominfo")]
- public string RomInfo { get; set; }
+ public string? RomInfo { get; set; }
///
/// Category value
///
[JsonProperty("category", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("category")]
- public string Category { get; set; }
+ public string? Category { get; set; }
///
/// NFO name value
///
[JsonProperty("nfoname", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("nfoname")]
- public string NfoName { get; set; }
+ public string? NfoName { get; set; }
///
/// NFO size value
@@ -57,55 +57,55 @@ namespace SabreTools.DatItems.Formats
/// NFO CRC value
///
[JsonProperty("nfocrc", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("nfocrc")]
- public string NfoCrc { get; set; }
+ public string? NfoCrc { get; set; }
///
/// Archive name value
///
[JsonProperty("archivename", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("archivename")]
- public string ArchiveName { get; set; }
+ public string? ArchiveName { get; set; }
///
/// Original format value
///
[JsonProperty("originalformat", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("originalformat")]
- public string OriginalFormat { get; set; }
+ public string? OriginalFormat { get; set; }
///
/// Date value
///
[JsonProperty("date", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("date")]
- public string Date { get; set; }
+ public string? Date { get; set; }
///
/// Grpup value
///
[JsonProperty("group", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("group")]
- public string Group { get; set; }
+ public string? Group { get; set; }
///
/// Comment value
///
[JsonProperty("comment", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("comment")]
- public string Comment { get; set; }
+ public string? Comment { get; set; }
///
/// Tool value
///
[JsonProperty("tool", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("tool")]
- public string Tool { get; set; }
+ public string? Tool { get; set; }
///
/// Region value
///
[JsonProperty("region", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("region")]
- public string Region { get; set; }
+ public string? Region { get; set; }
///
/// Origin value
///
[JsonProperty("origin", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("origin")]
- public string Origin { get; set; }
+ public string? Origin { get; set; }
#endregion
@@ -131,8 +131,8 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
Id = this.Id,
@@ -158,17 +158,17 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
// If we don't have a Details, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType)
return false;
// Otherwise, treat it as a Details
- ReleaseDetails newOther = other as ReleaseDetails;
+ ReleaseDetails? newOther = other as ReleaseDetails;
// If the Details information matches
- return (Id == newOther.Id
+ return (Id == newOther!.Id
&& DirName == newOther.DirName
&& RomInfo == newOther.RomInfo
&& Category == newOther.Category
diff --git a/SabreTools.DatItems/Formats/Rom.cs b/SabreTools.DatItems/Formats/Rom.cs
index 6c83ccd6..b34ecdbe 100644
--- a/SabreTools.DatItems/Formats/Rom.cs
+++ b/SabreTools.DatItems/Formats/Rom.cs
@@ -1,7 +1,4 @@
-using System;
-using System.Linq;
-using System.Text;
-using System.Xml.Serialization;
+using System.Xml.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using SabreTools.Core;
@@ -16,18 +13,6 @@ namespace SabreTools.DatItems.Formats
[JsonObject("rom"), XmlRoot("rom")]
public class Rom : DatItem
{
- #region Private instance variables
-
- private byte[] _crc; // 8 bytes
- private byte[] _md5; // 16 bytes
- private byte[] _sha1; // 20 bytes
- private byte[] _sha256; // 32 bytes
- private byte[] _sha384; // 48 bytes
- private byte[] _sha512; // 64 bytes
- private byte[] _spamsum; // variable bytes
-
- #endregion
-
#region Fields
#region Common
@@ -36,19 +21,31 @@ namespace SabreTools.DatItems.Formats
/// Name of the item
///
[JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _rom.ReadString(Models.Internal.Rom.NameKey);
+ set => _rom[Models.Internal.Rom.NameKey] = value;
+ }
///
/// What BIOS is required for this rom
///
[JsonProperty("bios", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("bios")]
- public string Bios { get; set; }
+ public string? Bios
+ {
+ get => _rom.ReadString(Models.Internal.Rom.BiosKey);
+ set => _rom[Models.Internal.Rom.BiosKey] = value;
+ }
///
/// Byte size of the rom
///
[JsonProperty("size", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("size")]
- public long? Size { get; set; } = null;
+ public long? Size
+ {
+ get => _rom.ReadLong(Models.Internal.Rom.SizeKey);
+ set => _rom[Models.Internal.Rom.SizeKey] = value;
+ }
[JsonIgnore]
public bool SizeSpecified { get { return Size != null; } }
@@ -57,102 +54,122 @@ namespace SabreTools.DatItems.Formats
/// File CRC32 hash
///
[JsonProperty("crc", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("crc")]
- public string CRC
+ public string? CRC
{
- get { return _crc.IsNullOrEmpty() ? null : Utilities.ByteArrayToString(_crc); }
- set { _crc = (value == "null" ? Constants.CRCZeroBytes : Utilities.StringToByteArray(CleanCRC32(value))); }
+ get => _rom.ReadString(Models.Internal.Rom.CRCKey);
+ set => _rom[Models.Internal.Rom.CRCKey] = TextHelper.NormalizeCRC32(value);
}
///
/// File MD5 hash
///
[JsonProperty("md5", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("md5")]
- public string MD5
+ public string? MD5
{
- get { return _md5.IsNullOrEmpty() ? null : Utilities.ByteArrayToString(_md5); }
- set { _md5 = Utilities.StringToByteArray(CleanMD5(value)); }
+ get => _rom.ReadString(Models.Internal.Rom.MD5Key);
+ set => _rom[Models.Internal.Rom.MD5Key] = TextHelper.NormalizeMD5(value);
}
///
/// File SHA-1 hash
///
[JsonProperty("sha1", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("sha1")]
- public string SHA1
+ public string? SHA1
{
- get { return _sha1.IsNullOrEmpty() ? null : Utilities.ByteArrayToString(_sha1); }
- set { _sha1 = Utilities.StringToByteArray(CleanSHA1(value)); }
+ get => _rom.ReadString(Models.Internal.Rom.SHA1Key);
+ set => _rom[Models.Internal.Rom.SHA1Key] = TextHelper.NormalizeSHA1(value);
}
///
/// File SHA-256 hash
///
[JsonProperty("sha256", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("sha256")]
- public string SHA256
+ public string? SHA256
{
- get { return _sha256.IsNullOrEmpty() ? null : Utilities.ByteArrayToString(_sha256); }
- set { _sha256 = Utilities.StringToByteArray(CleanSHA256(value)); }
+ get => _rom.ReadString(Models.Internal.Rom.SHA256Key);
+ set => _rom[Models.Internal.Rom.SHA256Key] = TextHelper.NormalizeSHA256(value);
}
///
/// File SHA-384 hash
///
[JsonProperty("sha384", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("sha384")]
- public string SHA384
+ public string? SHA384
{
- get { return _sha384.IsNullOrEmpty() ? null : Utilities.ByteArrayToString(_sha384); }
- set { _sha384 = Utilities.StringToByteArray(CleanSHA384(value)); }
+ get => _rom.ReadString(Models.Internal.Rom.SHA384Key);
+ set => _rom[Models.Internal.Rom.SHA384Key] = TextHelper.NormalizeSHA384(value);
}
///
/// File SHA-512 hash
///
[JsonProperty("sha512", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("sha512")]
- public string SHA512
+ public string? SHA512
{
- get { return _sha512.IsNullOrEmpty() ? null : Utilities.ByteArrayToString(_sha512); }
- set { _sha512 = Utilities.StringToByteArray(CleanSHA512(value)); }
+ get => _rom.ReadString(Models.Internal.Rom.SHA512Key);
+ set => _rom[Models.Internal.Rom.SHA512Key] = TextHelper.NormalizeSHA512(value);
}
///
/// File SpamSum fuzzy hash
///
[JsonProperty("spamsum", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("spamsum")]
- public string SpamSum
+ public string? SpamSum
{
- get { return _spamsum.IsNullOrEmpty() ? null : Encoding.UTF8.GetString(_spamsum); }
- set { _spamsum = Encoding.UTF8.GetBytes(value ?? string.Empty); }
+ get => _rom.ReadString(Models.Internal.Rom.SpamSumKey);
+ set => _rom[Models.Internal.Rom.SpamSumKey] = value;
}
///
/// Rom name to merge from parent
///
[JsonProperty("merge", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("merge")]
- public string MergeTag { get; set; }
+ public string? MergeTag
+ {
+ get => _rom.ReadString(Models.Internal.Rom.MergeKey);
+ set => _rom[Models.Internal.Rom.MergeKey] = value;
+ }
///
/// Rom region
///
[JsonProperty("region", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("biregionos")]
- public string Region { get; set; }
+ public string? Region
+ {
+ get => _rom.ReadString(Models.Internal.Rom.RegionKey);
+ set => _rom[Models.Internal.Rom.RegionKey] = value;
+ }
///
/// Data offset within rom
///
[JsonProperty("offset", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("offset")]
- public string Offset { get; set; }
+ public string? Offset
+ {
+ get => _rom.ReadString(Models.Internal.Rom.OffsetKey);
+ set => _rom[Models.Internal.Rom.OffsetKey] = value;
+ }
///
/// File created date
///
[JsonProperty("date", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("date")]
- public string Date { get; set; }
+ public string? Date
+ {
+ get => _rom.ReadString(Models.Internal.Rom.DateKey);
+ set => _rom[Models.Internal.Rom.DateKey] = value;
+ }
///
/// Rom dump status
///
[JsonProperty("status", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("status")]
[JsonConverter(typeof(StringEnumConverter))]
- public ItemStatus ItemStatus { get; set; }
+ public ItemStatus ItemStatus
+ {
+ get => _rom.ReadString(Models.Internal.Rom.StatusKey).AsItemStatus();
+ set => _rom[Models.Internal.Rom.StatusKey] = value.FromItemStatus(yesno: false);
+ }
[JsonIgnore]
public bool ItemStatusSpecified { get { return ItemStatus != ItemStatus.NULL && ItemStatus != ItemStatus.None; } }
@@ -161,7 +178,11 @@ namespace SabreTools.DatItems.Formats
/// Determine if the rom is optional in the set
///
[JsonProperty("optional", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("optional")]
- public bool? Optional { get; set; } = null;
+ public bool? Optional
+ {
+ get => _rom.ReadBool(Models.Internal.Rom.OptionalKey);
+ set => _rom[Models.Internal.Rom.OptionalKey] = value;
+ }
[JsonIgnore]
public bool OptionalSpecified { get { return Optional != null; } }
@@ -170,7 +191,11 @@ namespace SabreTools.DatItems.Formats
/// Determine if the CRC32 hash is inverted
///
[JsonProperty("inverted", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("inverted")]
- public bool? Inverted { get; set; } = null;
+ public bool? Inverted
+ {
+ get => _rom.ReadBool(Models.Internal.Rom.InvertedKey);
+ set => _rom[Models.Internal.Rom.InvertedKey] = value;
+ }
[JsonIgnore]
public bool InvertedSpecified { get { return Inverted != null; } }
@@ -183,19 +208,31 @@ namespace SabreTools.DatItems.Formats
/// Source of file
///
[JsonProperty("ado_source", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("ado_source")]
- public string ArchiveDotOrgSource { get; set; }
+ public string? ArchiveDotOrgSource
+ {
+ get => _rom.ReadString(Models.Internal.Rom.SourceKey);
+ set => _rom[Models.Internal.Rom.SourceKey] = value;
+ }
///
/// Archive.org recognized file format
///
[JsonProperty("ado_format", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("ado_format")]
- public string ArchiveDotOrgFormat { get; set; }
+ public string? ArchiveDotOrgFormat
+ {
+ get => _rom.ReadString(Models.Internal.Rom.FormatKey);
+ set => _rom[Models.Internal.Rom.FormatKey] = value;
+ }
///
/// Original filename
///
[JsonProperty("original_filename", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("original_filename")]
- public string OriginalFilename { get; set; }
+ public string? OriginalFilename
+ {
+ get => _rom.ReadString(Models.Internal.Rom.OriginalKey);
+ set => _rom[Models.Internal.Rom.OriginalKey] = value;
+ }
///
/// Image rotation
@@ -204,13 +241,21 @@ namespace SabreTools.DatItems.Formats
/// TODO: This might be Int32?
///
[JsonProperty("rotation", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("rotation")]
- public string Rotation { get; set; }
+ public string? Rotation
+ {
+ get => _rom.ReadString(Models.Internal.Rom.RotationKey);
+ set => _rom[Models.Internal.Rom.RotationKey] = value;
+ }
///
/// Summation value?
///
[JsonProperty("summation", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("summation")]
- public string Summation { get; set; }
+ public string? Summation
+ {
+ get => _rom.ReadString(Models.Internal.Rom.SummationKey);
+ set => _rom[Models.Internal.Rom.SummationKey] = value;
+ }
#endregion
@@ -220,13 +265,21 @@ namespace SabreTools.DatItems.Formats
/// Alternate name for the item
///
[JsonProperty("alt_romname", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("alt_romname")]
- public string AltName { get; set; }
+ public string? AltName
+ {
+ get => _rom.ReadString(Models.Internal.Rom.AltRomnameKey);
+ set => _rom[Models.Internal.Rom.AltRomnameKey] = value;
+ }
///
/// Alternate title for the item
///
[JsonProperty("alt_title", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("alt_title")]
- public string AltTitle { get; set; }
+ public string? AltTitle
+ {
+ get => _rom.ReadString(Models.Internal.Rom.AltTitleKey);
+ set => _rom[Models.Internal.Rom.AltTitleKey] = value;
+ }
#endregion
@@ -236,7 +289,11 @@ namespace SabreTools.DatItems.Formats
/// Alternate title for the item
///
[JsonProperty("mia", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("mia")]
- public bool? MIA { get; set; } = null;
+ public bool? MIA
+ {
+ get => _rom.ReadBool(Models.Internal.Rom.MIAKey);
+ set => _rom[Models.Internal.Rom.MIAKey] = value;
+ }
[JsonIgnore]
public bool MIASpecified { get { return MIA != null; } }
@@ -248,8 +305,9 @@ namespace SabreTools.DatItems.Formats
///
/// OpenMSX sub item type
///
+ /// This is inverted from the internal model
[JsonProperty("original", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("original")]
- public Original Original { get; set; } = null;
+ public Original? Original { get; set; }
[JsonIgnore]
public bool OriginalSpecified { get { return Original != null && Original != default; } }
@@ -259,7 +317,11 @@ namespace SabreTools.DatItems.Formats
///
[JsonProperty("openmsx_subtype", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("openmsx_subtype")]
[JsonConverter(typeof(StringEnumConverter))]
- public OpenMSXSubType OpenMSXSubType { get; set; }
+ public OpenMSXSubType OpenMSXSubType
+ {
+ get => _rom.ReadString(Models.Internal.Rom.OpenMSXMediaType).AsOpenMSXSubType();
+ set => _rom[Models.Internal.Rom.OpenMSXMediaType] = value.FromOpenMSXSubType();
+ }
[JsonIgnore]
public bool OpenMSXSubTypeSpecified { get { return OpenMSXSubType != OpenMSXSubType.NULL; } }
@@ -269,19 +331,28 @@ namespace SabreTools.DatItems.Formats
///
/// Not related to the subtype above
[JsonProperty("openmsx_type", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("openmsx_type")]
- public string OpenMSXType { get; set; }
+ public string? OpenMSXType
+ {
+ get => _rom.ReadString(Models.Internal.Rom.OpenMSXType);
+ set => _rom[Models.Internal.Rom.OpenMSXType] = value;
+ }
///
/// Item remark (like a comment)
///
[JsonProperty("remark", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("remark")]
- public string Remark { get; set; }
+ public string? Remark
+ {
+ get => _rom.ReadString(Models.Internal.Rom.RemarkKey);
+ set => _rom[Models.Internal.Rom.RemarkKey] = value;
+ }
///
/// Boot state
///
+ /// TODO: Investigate where this value came from?
[JsonProperty("boot", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("boot")]
- public string Boot { get; set; }
+ public string? Boot { get; set; }
#endregion
@@ -290,8 +361,9 @@ namespace SabreTools.DatItems.Formats
///
/// Data area information
///
+ /// This is inverted from the internal model
[JsonProperty("dataarea", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("dataarea")]
- public DataArea DataArea { get; set; } = null;
+ public DataArea? DataArea { get; set; } = null;
[JsonIgnore]
public bool DataAreaSpecified
@@ -311,7 +383,11 @@ namespace SabreTools.DatItems.Formats
///
[JsonProperty("loadflag", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("loadflag")]
[JsonConverter(typeof(StringEnumConverter))]
- public LoadFlag LoadFlag { get; set; }
+ public LoadFlag LoadFlag
+ {
+ get => _rom.ReadString(Models.Internal.Rom.LoadFlagKey).AsLoadFlag();
+ set => _rom[Models.Internal.Rom.LoadFlagKey] = value.FromLoadFlag();
+ }
[JsonIgnore]
public bool LoadFlagSpecified { get { return LoadFlag != LoadFlag.NULL; } }
@@ -319,8 +395,9 @@ namespace SabreTools.DatItems.Formats
///
/// Original hardware part associated with the item
///
+ /// This is inverted from the internal model
[JsonProperty("part", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("part")]
- public Part Part { get; set; } = null;
+ public Part? Part { get; set; } = null;
[JsonIgnore]
public bool PartSpecified
@@ -337,19 +414,29 @@ namespace SabreTools.DatItems.Formats
/// SoftwareList value associated with the item
///
[JsonProperty("value", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("value")]
- public string Value { get; set; }
+ public string? Value
+ {
+ get => _rom.ReadString(Models.Internal.Rom.ValueKey);
+ set => _rom[Models.Internal.Rom.ValueKey] = value;
+ }
#endregion
+ ///
+ /// Internal Rom model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Rom _rom = new();
+
#endregion // Fields
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -394,13 +481,13 @@ namespace SabreTools.DatItems.Formats
{
Name = baseFile.Filename;
Size = baseFile.Size;
- _crc = baseFile.CRC;
- _md5 = baseFile.MD5;
- _sha1 = baseFile.SHA1;
- _sha256 = baseFile.SHA256;
- _sha384 = baseFile.SHA384;
- _sha512 = baseFile.SHA512;
- _spamsum = baseFile.SpamSum;
+ CRC = Utilities.ByteArrayToString(baseFile.CRC);
+ MD5 = Utilities.ByteArrayToString(baseFile.MD5);
+ SHA1 = Utilities.ByteArrayToString(baseFile.SHA1);
+ SHA256 = Utilities.ByteArrayToString(baseFile.SHA256);
+ SHA384 = Utilities.ByteArrayToString(baseFile.SHA384);
+ SHA512 = Utilities.ByteArrayToString(baseFile.SHA512);
+ SpamSum = Utilities.ByteArrayToString(baseFile.SpamSum);
ItemType = ItemType.Rom;
DupeType = 0x00;
@@ -421,42 +508,14 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Bios = this.Bios,
- Size = this.Size,
- _crc = this._crc,
- _md5 = this._md5,
- _sha1 = this._sha1,
- _sha256 = this._sha256,
- _sha384 = this._sha384,
- _sha512 = this._sha512,
- _spamsum = this._spamsum,
- MergeTag = this.MergeTag,
- Region = this.Region,
- Offset = this.Offset,
- Date = this.Date,
- ItemStatus = this.ItemStatus,
- Optional = this.Optional,
- Inverted = this.Inverted,
-
- AltName = this.AltName,
- AltTitle = this.AltTitle,
-
- MIA = this.MIA,
-
- Original = this.Original,
- OpenMSXSubType = this.OpenMSXSubType,
- OpenMSXType = this.OpenMSXType,
- Remark = this.Remark,
- Boot = this.Boot,
-
+ _rom = this._rom?.Clone() as Models.Internal.Rom ?? new Models.Internal.Rom(),
+
DataArea = this.DataArea,
- LoadFlag = this.LoadFlag,
Part = this.Part,
- Value = this.Value,
};
}
@@ -471,13 +530,13 @@ namespace SabreTools.DatItems.Formats
Parent = this.Machine?.Name,
Date = this.Date,
Size = this.Size,
- CRC = this._crc,
- MD5 = this._md5,
- SHA1 = this._sha1,
- SHA256 = this._sha256,
- SHA384 = this._sha384,
- SHA512 = this._sha512,
- SpamSum = this._spamsum,
+ CRC = Utilities.StringToByteArray(this.CRC),
+ MD5 = Utilities.StringToByteArray(this.MD5),
+ SHA1 = Utilities.StringToByteArray(this.SHA1),
+ SHA256 = Utilities.StringToByteArray(this.SHA256),
+ SHA384 = Utilities.StringToByteArray(this.SHA384),
+ SHA512 = Utilities.StringToByteArray(this.SHA512),
+ SpamSum = Utilities.StringToByteArray(this.SpamSum),
};
}
@@ -486,38 +545,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
- bool dupefound = false;
+ // If we don't have a Rom, return false
+ if (ItemType != other?.ItemType || other is not Rom otherInternal)
+ return false;
- // If we don't have a rom, return false
- if (ItemType != other.ItemType)
- return dupefound;
-
- // Otherwise, treat it as a Rom
- Rom newOther = other as Rom;
-
- // If all hashes are empty but they're both nodump and the names match, then they're dupes
- if ((ItemStatus == ItemStatus.Nodump && newOther.ItemStatus == ItemStatus.Nodump)
- && Name == newOther.Name
- && !HasHashes() && !newOther.HasHashes())
- {
- dupefound = true;
- }
-
- // If we have a file that has no known size, rely on the hashes only
- else if (Size == null && HashMatch(newOther))
- {
- dupefound = true;
- }
-
- // Otherwise if we get a partial match
- else if (Size == newOther.Size && HashMatch(newOther))
- {
- dupefound = true;
- }
-
- return dupefound;
+ // Compare the internal models
+ return _rom.EqualTo(otherInternal._rom);
}
///
@@ -529,26 +564,26 @@ namespace SabreTools.DatItems.Formats
if (Size == null && other.Size != null)
Size = other.Size;
- if (_crc.IsNullOrEmpty() && !other._crc.IsNullOrEmpty())
- _crc = other._crc;
+ if (string.IsNullOrWhiteSpace(CRC) && !string.IsNullOrWhiteSpace(other.CRC))
+ CRC = other.CRC;
- if (_md5.IsNullOrEmpty() && !other._md5.IsNullOrEmpty())
- _md5 = other._md5;
+ if (string.IsNullOrWhiteSpace(MD5) && !string.IsNullOrWhiteSpace(other.MD5))
+ MD5 = other.MD5;
- if (_sha1.IsNullOrEmpty() && !other._sha1.IsNullOrEmpty())
- _sha1 = other._sha1;
+ if (string.IsNullOrWhiteSpace(SHA1) && !string.IsNullOrWhiteSpace(other.SHA1))
+ SHA1 = other.SHA1;
- if (_sha256.IsNullOrEmpty() && !other._sha256.IsNullOrEmpty())
- _sha256 = other._sha256;
+ if (string.IsNullOrWhiteSpace(SHA256) && !string.IsNullOrWhiteSpace(other.SHA256))
+ SHA256 = other.SHA256;
- if (_sha384.IsNullOrEmpty() && !other._sha384.IsNullOrEmpty())
- _sha384 = other._sha384;
+ if (string.IsNullOrWhiteSpace(SHA384) && !string.IsNullOrWhiteSpace(other.SHA384))
+ SHA384 = other.SHA384;
- if (_sha512.IsNullOrEmpty() && !other._sha512.IsNullOrEmpty())
- _sha512 = other._sha512;
+ if (string.IsNullOrWhiteSpace(SHA512) && !string.IsNullOrWhiteSpace(other.SHA512))
+ SHA512 = other.SHA512;
- if (_spamsum.IsNullOrEmpty() && !other._spamsum.IsNullOrEmpty())
- _spamsum = other._spamsum;
+ if (string.IsNullOrWhiteSpace(SpamSum) && !string.IsNullOrWhiteSpace(other.SpamSum))
+ SpamSum = other.SpamSum;
}
///
@@ -557,19 +592,19 @@ namespace SabreTools.DatItems.Formats
/// String representing the suffix
public string GetDuplicateSuffix()
{
- if (!_crc.IsNullOrEmpty())
+ if (!string.IsNullOrWhiteSpace(CRC))
return $"_{CRC}";
- else if (!_md5.IsNullOrEmpty())
+ else if (!string.IsNullOrWhiteSpace(MD5))
return $"_{MD5}";
- else if (!_sha1.IsNullOrEmpty())
+ else if (!string.IsNullOrWhiteSpace(SHA1))
return $"_{SHA1}";
- else if (!_sha256.IsNullOrEmpty())
+ else if (!string.IsNullOrWhiteSpace(SHA256))
return $"_{SHA256}";
- else if (!_sha384.IsNullOrEmpty())
+ else if (!string.IsNullOrWhiteSpace(SHA384))
return $"_{SHA384}";
- else if (!_sha512.IsNullOrEmpty())
+ else if (!string.IsNullOrWhiteSpace(SHA512))
return $"_{SHA512}";
- else if (!_spamsum.IsNullOrEmpty())
+ else if (!string.IsNullOrWhiteSpace(SpamSum))
return $"_{SpamSum}";
else
return "_1";
@@ -579,72 +614,13 @@ namespace SabreTools.DatItems.Formats
/// Returns if the Rom contains any hashes
///
/// True if any hash exists, false otherwise
- public bool HasHashes()
- {
- return !_crc.IsNullOrEmpty()
- || !_md5.IsNullOrEmpty()
- || !_sha1.IsNullOrEmpty()
- || !_sha256.IsNullOrEmpty()
- || !_sha384.IsNullOrEmpty()
- || !_sha512.IsNullOrEmpty()
- || !_spamsum.IsNullOrEmpty();
- }
+ public bool HasHashes() => _rom.HasHashes();
///
/// Returns if all of the hashes are set to their 0-byte values
///
/// True if any hash matches the 0-byte value, false otherwise
- public bool HasZeroHash()
- {
- return (_crc != null && _crc.SequenceEqual(Constants.CRCZeroBytes))
- || (_md5 != null && _md5.SequenceEqual(Constants.MD5ZeroBytes))
- || (_sha1 != null && _sha1.SequenceEqual(Constants.SHA1ZeroBytes))
- || (_sha256 != null && _sha256.SequenceEqual(Constants.SHA256ZeroBytes))
- || (_sha384 != null && _sha384.SequenceEqual(Constants.SHA384ZeroBytes))
- || (_sha512 != null && _sha512.SequenceEqual(Constants.SHA512ZeroBytes))
- || (_spamsum != null && _spamsum.SequenceEqual(Constants.SpamSumZeroBytes));
- }
-
- ///
- /// Returns if there are no, non-empty hashes in common with another Rom
- ///
- /// Rom to compare against
- /// True if at least one hash is not mutually exclusive, false otherwise
- private bool HasCommonHash(Rom other)
- {
- return !(_crc.IsNullOrEmpty() ^ other._crc.IsNullOrEmpty())
- || !(_md5.IsNullOrEmpty() ^ other._md5.IsNullOrEmpty())
- || !(_sha1.IsNullOrEmpty() ^ other._sha1.IsNullOrEmpty())
- || !(_sha256.IsNullOrEmpty() ^ other._sha256.IsNullOrEmpty())
- || !(_sha384.IsNullOrEmpty() ^ other._sha384.IsNullOrEmpty())
- || !(_sha512.IsNullOrEmpty() ^ other._sha512.IsNullOrEmpty())
- || !(_spamsum.IsNullOrEmpty() ^ other._spamsum.IsNullOrEmpty());
- }
-
- ///
- /// Returns if any hashes are common with another Rom
- ///
- /// Rom to compare against
- /// True if any hashes are in common, false otherwise
- private bool HashMatch(Rom other)
- {
- // If either have no hashes, we return false, otherwise this would be a false positive
- if (!HasHashes() || !other.HasHashes())
- return false;
-
- // If neither have hashes in common, we return false, otherwise this would be a false positive
- if (!HasCommonHash(other))
- return false;
-
- // Return if all hashes match according to merge rules
- return ConditionalHashEquals(_crc, other._crc)
- && ConditionalHashEquals(_md5, other._md5)
- && ConditionalHashEquals(_sha1, other._sha1)
- && ConditionalHashEquals(_sha256, other._sha256)
- && ConditionalHashEquals(_sha384, other._sha384)
- && ConditionalHashEquals(_sha512, other._sha512)
- && ConditionalHashEquals(_spamsum, other._spamsum);
- }
+ public bool HasZeroHash() => _rom.HasZeroHash();
#endregion
@@ -654,7 +630,7 @@ namespace SabreTools.DatItems.Formats
public override string GetKey(ItemKey bucketedBy, bool lower = true, bool norename = true)
{
// Set the output key as the default blank string
- string key;
+ string? key;
// Now determine what the key should be based on the bucketedBy value
switch (bucketedBy)
diff --git a/SabreTools.DatItems/Formats/Sample.cs b/SabreTools.DatItems/Formats/Sample.cs
index c127edde..cc0b8dbc 100644
--- a/SabreTools.DatItems/Formats/Sample.cs
+++ b/SabreTools.DatItems/Formats/Sample.cs
@@ -16,17 +16,27 @@ namespace SabreTools.DatItems.Formats
/// Name of the item
///
[JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _sample.ReadString(Models.Internal.Sample.NameKey);
+ set => _sample[Models.Internal.Sample.NameKey] = value;
+ }
+
+ ///
+ /// Internal Sample model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Sample _sample = new();
#endregion
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -53,11 +63,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Name = this.Name,
+ _sample = this._sample?.Clone() as Models.Internal.Sample ?? new Models.Internal.Sample(),
};
}
@@ -66,17 +76,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
- // If we don't have a sample, return false
- if (ItemType != other.ItemType)
+ // If we don't have a Sample, return false
+ if (ItemType != other?.ItemType || other is not Sample otherInternal)
return false;
- // Otherwise, treat it as a Sample
- Sample newOther = other as Sample;
-
- // If the archive information matches
- return (Name == newOther.Name);
+ // Compare the internal models
+ return _sample.EqualTo(otherInternal._sample);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/Serials.cs b/SabreTools.DatItems/Formats/Serials.cs
index 34c76606..697231a8 100644
--- a/SabreTools.DatItems/Formats/Serials.cs
+++ b/SabreTools.DatItems/Formats/Serials.cs
@@ -17,85 +17,85 @@ namespace SabreTools.DatItems.Formats
/// Digital serial 1 value
///
[JsonProperty("digital_serial1", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("digital_serial1")]
- public string DigitalSerial1 { get; set; }
+ public string? DigitalSerial1 { get; set; }
///
/// Digital serial 2 value
///
[JsonProperty("digital_serial2", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("digital_serial2")]
- public string DigitalSerial2 { get; set; }
+ public string? DigitalSerial2 { get; set; }
///
/// Media serial 1 value
///
[JsonProperty("media_serial1", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("media_serial1")]
- public string MediaSerial1 { get; set; }
+ public string? MediaSerial1 { get; set; }
///
/// Media serial 2 value
///
[JsonProperty("media_serial2", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("media_serial2")]
- public string MediaSerial2 { get; set; }
+ public string? MediaSerial2 { get; set; }
///
/// Media serial 3 value
///
[JsonProperty("media_serial3", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("media_serial3")]
- public string MediaSerial3 { get; set; }
+ public string? MediaSerial3 { get; set; }
///
/// PCB serial value
///
[JsonProperty("pcb_serial", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("pcb_serial")]
- public string PcbSerial { get; set; }
+ public string? PcbSerial { get; set; }
///
/// Rom chip serial 1 value
///
[JsonProperty("romchip_serial1", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("romchip_serial1")]
- public string RomChipSerial1 { get; set; }
+ public string? RomChipSerial1 { get; set; }
///
/// Rom chip serial 2 value
///
[JsonProperty("romchip_serial2", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("romchip_serial2")]
- public string RomChipSerial2 { get; set; }
+ public string? RomChipSerial2 { get; set; }
///
/// Lockout serial value
///
[JsonProperty("lockout_serial", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("lockout_serial")]
- public string LockoutSerial { get; set; }
+ public string? LockoutSerial { get; set; }
///
/// Save chip serial value
///
[JsonProperty("savechip_serial", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("savechip_serial")]
- public string SaveChipSerial { get; set; }
+ public string? SaveChipSerial { get; set; }
///
/// Chip serial value
///
[JsonProperty("chip_serial", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("chip_serial")]
- public string ChipSerial { get; set; }
+ public string? ChipSerial { get; set; }
///
/// Box serial value
///
[JsonProperty("box_serial", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("box_serial")]
- public string BoxSerial { get; set; }
+ public string? BoxSerial { get; set; }
///
/// Media stamp value
///
[JsonProperty("mediastamp", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("mediastamp")]
- public string MediaStamp { get; set; }
+ public string? MediaStamp { get; set; }
///
/// Box barcode value
///
[JsonProperty("box_barcode", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("box_barcode")]
- public string BoxBarcode { get; set; }
+ public string? BoxBarcode { get; set; }
#endregion
@@ -121,8 +121,8 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
DigitalSerial1 = this.DigitalSerial1,
@@ -147,17 +147,17 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
// If we don't have a Serials, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType)
return false;
// Otherwise, treat it as a Serials
- Serials newOther = other as Serials;
+ Serials? newOther = other as Serials;
// If the Serials information matches
- return (DigitalSerial1 == newOther.DigitalSerial1
+ return (DigitalSerial1 == newOther!.DigitalSerial1
&& DigitalSerial2 == newOther.DigitalSerial2
&& MediaSerial1 == newOther.MediaSerial1
&& MediaSerial2 == newOther.MediaSerial2
diff --git a/SabreTools.DatItems/Formats/Setting.cs b/SabreTools.DatItems/Formats/Setting.cs
deleted file mode 100644
index b577a74f..00000000
--- a/SabreTools.DatItems/Formats/Setting.cs
+++ /dev/null
@@ -1,127 +0,0 @@
-using System.Collections.Generic;
-using System.Xml.Serialization;
-using Newtonsoft.Json;
-using SabreTools.Core;
-
-namespace SabreTools.DatItems.Formats
-{
- ///
- /// Represents one ListXML confsetting or dipvalue
- ///
- [JsonObject("setting"), XmlRoot("setting")]
- public class Setting : DatItem
- {
- #region Fields
-
- ///
- /// Setting name
- ///
- [JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
-
- ///
- /// Setting value
- ///
- [JsonProperty("value", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("value")]
- public string Value { get; set; }
-
- ///
- /// Determines if the setting is default or not
- ///
- [JsonProperty("default", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("default")]
- public bool? Default { get; set; }
-
- [JsonIgnore]
- public bool DefaultSpecified { get { return Default != null; } }
-
- ///
- /// List of conditions on the setting
- ///
- [JsonProperty("conditions", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("conditions")]
- public List Conditions { get; set; }
-
- [JsonIgnore]
- public bool ConditionsSpecified { get { return Conditions != null && Conditions.Count > 0; } }
-
- #endregion
-
- #region Accessors
-
- ///
- public override string GetName() => Name;
-
- ///
- public override void SetName(string name) => Name = name;
-
- #endregion
-
- #region Constructors
-
- ///
- /// Create a default, empty Setting object
- ///
- public Setting()
- {
- Name = string.Empty;
- ItemType = ItemType.Setting;
- }
-
- #endregion
-
- #region Cloning Methods
-
- ///
- public override object Clone()
- {
- return new Setting()
- {
- ItemType = this.ItemType,
- DupeType = this.DupeType,
-
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
- Remove = this.Remove,
-
- Name = this.Name,
- Value = this.Value,
- Default = this.Default,
- Conditions = this.Conditions,
- };
- }
-
- #endregion
-
- #region Comparision Methods
-
- ///
- public override bool Equals(DatItem other)
- {
- // If we don't have a Setting, return false
- if (ItemType != other.ItemType)
- return false;
-
- // Otherwise, treat it as a Setting
- Setting newOther = other as Setting;
-
- // If the Setting information matches
- bool match = (Name == newOther.Name
- && Value == newOther.Value
- && Default == newOther.Default);
- if (!match)
- return match;
-
- // If the conditions match
- if (ConditionsSpecified)
- {
- foreach (Condition condition in Conditions)
- {
- match &= newOther.Conditions.Contains(condition);
- }
- }
-
- return match;
- }
-
- #endregion
- }
-}
diff --git a/SabreTools.DatItems/Formats/SharedFeature.cs b/SabreTools.DatItems/Formats/SharedFeature.cs
index fea3f89a..f3576626 100644
--- a/SabreTools.DatItems/Formats/SharedFeature.cs
+++ b/SabreTools.DatItems/Formats/SharedFeature.cs
@@ -16,23 +16,37 @@ namespace SabreTools.DatItems.Formats
/// Name of the item
///
[JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _sharedFeat.ReadString(Models.Internal.SharedFeat.NameKey);
+ set => _sharedFeat[Models.Internal.SharedFeat.NameKey] = value;
+ }
///
/// SharedFeature value
///
[JsonProperty("value"), XmlElement("value")]
- public string Value { get; set; }
+ public string? Value
+ {
+ get => _sharedFeat.ReadString(Models.Internal.SharedFeat.ValueKey);
+ set => _sharedFeat[Models.Internal.SharedFeat.ValueKey] = value;
+ }
+
+ ///
+ /// Internal SharedFeat model
+ ///
+ [JsonIgnore]
+ private Models.Internal.SharedFeat _sharedFeat = new();
#endregion
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -59,12 +73,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Name = this.Name,
- Value = this.Value,
+ _sharedFeat = this._sharedFeat?.Clone() as Models.Internal.SharedFeat ?? new Models.Internal.SharedFeat(),
};
}
@@ -73,18 +86,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
- // If we don't have a sample, return false
- if (ItemType != other.ItemType)
+ // If we don't have a SharedFeature, return false
+ if (ItemType != other?.ItemType || other is not SharedFeature otherInternal)
return false;
- // Otherwise, treat it as a SharedFeature
- SharedFeature newOther = other as SharedFeature;
-
- // If the archive information matches
- return (Name == newOther.Name
- && Value == newOther.Value);
+ // Compare the internal models
+ return _sharedFeat.EqualTo(otherInternal._sharedFeat);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/Slot.cs b/SabreTools.DatItems/Formats/Slot.cs
index a1d89df6..b63c43ce 100644
--- a/SabreTools.DatItems/Formats/Slot.cs
+++ b/SabreTools.DatItems/Formats/Slot.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Linq;
using System.Xml.Serialization;
using Newtonsoft.Json;
using SabreTools.Core;
@@ -17,26 +18,40 @@ namespace SabreTools.DatItems.Formats
/// Name of the item
///
[JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _slot.ReadString(Models.Internal.Slot.NameKey);
+ set => _slot[Models.Internal.Slot.NameKey] = value;
+ }
///
/// Slot options associated with the slot
///
[JsonProperty("slotoptions", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("slotoptions")]
- public List SlotOptions { get; set; }
+ public List? SlotOptions
+ {
+ get => _slot.Read(Models.Internal.Slot.SlotOptionKey)?.ToList();
+ set => _slot[Models.Internal.Slot.SlotOptionKey] = value?.ToArray();
+ }
[JsonIgnore]
public bool SlotOptionsSpecified { get { return SlotOptions != null && SlotOptions.Count > 0; } }
+ ///
+ /// Internal Slot model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Slot _slot = new();
+
#endregion
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -63,12 +78,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Name = this.Name,
- SlotOptions = this.SlotOptions,
+ _slot = this._slot?.Clone() as Models.Internal.Slot ?? new Models.Internal.Slot(),
};
}
@@ -77,30 +91,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
// If we don't have a Slot, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType || other is not Slot otherInternal)
return false;
- // Otherwise, treat it as a Slot
- Slot newOther = other as Slot;
-
- // If the Slot information matches
- bool match = (Name == newOther.Name);
- if (!match)
- return match;
-
- // If the slot options match
- if (SlotOptionsSpecified)
- {
- foreach (SlotOption slotOption in SlotOptions)
- {
- match &= newOther.SlotOptions.Contains(slotOption);
- }
- }
-
- return match;
+ // Compare the internal models
+ return _slot.EqualTo(otherInternal._slot);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/SlotOption.cs b/SabreTools.DatItems/Formats/SlotOption.cs
index e6796719..53c73dab 100644
--- a/SabreTools.DatItems/Formats/SlotOption.cs
+++ b/SabreTools.DatItems/Formats/SlotOption.cs
@@ -16,32 +16,50 @@ namespace SabreTools.DatItems.Formats
/// Slot option name
///
[JsonProperty("name"), XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _slotOption.ReadString(Models.Internal.SlotOption.NameKey);
+ set => _slotOption[Models.Internal.SlotOption.NameKey] = value;
+ }
///
/// Referenced device name
///
[JsonProperty("devname"), XmlElement("devname")]
- public string DeviceName { get; set; }
+ public string? DeviceName
+ {
+ get => _slotOption.ReadString(Models.Internal.SlotOption.DevNameKey);
+ set => _slotOption[Models.Internal.SlotOption.DevNameKey] = value;
+ }
///
/// Determines if this slot option is default or not
///
[JsonProperty("default", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("default")]
- public bool? Default { get; set; }
+ public bool? Default
+ {
+ get => _slotOption.ReadBool(Models.Internal.SlotOption.DefaultKey);
+ set => _slotOption[Models.Internal.SlotOption.DefaultKey] = value;
+ }
[JsonIgnore]
public bool DefaultSpecified { get { return Default != null; } }
+ ///
+ /// Internal SlotOption model
+ ///
+ [JsonIgnore]
+ private Models.Internal.SlotOption _slotOption = new();
+
#endregion
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -68,13 +86,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Name = this.Name,
- DeviceName = this.DeviceName,
- Default = this.Default,
+ _slotOption = this._slotOption?.Clone() as Models.Internal.SlotOption ?? new Models.Internal.SlotOption(),
};
}
@@ -83,19 +99,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
- // If we don't have a SlotOption, return false
- if (ItemType != other.ItemType)
+ // If we don't have a Adjuster, return false
+ if (ItemType != other?.ItemType || other is not SlotOption otherInternal)
return false;
- // Otherwise, treat it as a SlotOption
- SlotOption newOther = other as SlotOption;
-
- // If the SlotOption information matches
- return (Name == newOther.Name
- && DeviceName == newOther.DeviceName
- && Default == newOther.Default);
+ // Compare the internal models
+ return _slotOption.EqualTo(otherInternal._slotOption);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/SoftwareList.cs b/SabreTools.DatItems/Formats/SoftwareList.cs
index e3bbeb44..e2d18401 100644
--- a/SabreTools.DatItems/Formats/SoftwareList.cs
+++ b/SabreTools.DatItems/Formats/SoftwareList.cs
@@ -1,8 +1,8 @@
using System.Xml.Serialization;
-
-using SabreTools.Core;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
+using SabreTools.Core;
+using SabreTools.Core.Tools;
namespace SabreTools.DatItems.Formats
{
@@ -22,14 +22,22 @@ namespace SabreTools.DatItems.Formats
///
[JsonProperty("tag", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("tag")]
- public string Tag { get; set; }
+ public string? Tag
+ {
+ get => _softwareList.ReadString(Models.Internal.SoftwareList.TagKey);
+ set => _softwareList[Models.Internal.SoftwareList.TagKey] = value;
+ }
///
/// Name of the item
///
[JsonProperty("name")]
[XmlElement("name")]
- public string Name { get; set; }
+ public string? Name
+ {
+ get => _softwareList.ReadString(Models.Internal.SoftwareList.NameKey);
+ set => _softwareList[Models.Internal.SoftwareList.NameKey] = value;
+ }
///
/// Status of the softare list according to the machine
@@ -37,7 +45,11 @@ namespace SabreTools.DatItems.Formats
[JsonProperty("status", DefaultValueHandling = DefaultValueHandling.Ignore)]
[JsonConverter(typeof(StringEnumConverter))]
[XmlElement("status")]
- public SoftwareListStatus Status { get; set; }
+ public SoftwareListStatus Status
+ {
+ get => _softwareList.ReadString(Models.Internal.SoftwareList.StatusKey).AsSoftwareListStatus();
+ set => _softwareList[Models.Internal.SoftwareList.StatusKey] = value.FromSoftwareListStatus();
+ }
[JsonIgnore]
public bool StatusSpecified { get { return Status != SoftwareListStatus.None; } }
@@ -47,17 +59,27 @@ namespace SabreTools.DatItems.Formats
///
[JsonProperty("filter", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("filter")]
- public string Filter { get; set; }
+ public string? Filter
+ {
+ get => _softwareList.ReadString(Models.Internal.SoftwareList.FilterKey);
+ set => _softwareList[Models.Internal.SoftwareList.FilterKey] = value;
+ }
+
+ ///
+ /// Internal SoftwareList model
+ ///
+ [JsonIgnore]
+ private Models.Internal.SoftwareList _softwareList = new();
#endregion
#region Accessors
///
- public override string GetName() => Name;
+ public override string? GetName() => Name;
///
- public override void SetName(string name) => Name = name;
+ public override void SetName(string? name) => Name = name;
#endregion
@@ -83,14 +105,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Tag = this.Tag,
- Name = this.Name,
- Status = this.Status,
- Filter = this.Filter,
+ _softwareList = this._softwareList?.Clone() as Models.Internal.SoftwareList ?? new Models.Internal.SoftwareList(),
};
}
@@ -98,20 +117,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
- // If we don't have a sample, return false
- if (ItemType != other.ItemType)
+ // If we don't have a Adjuster, return false
+ if (ItemType != other?.ItemType || other is not SoftwareList otherInternal)
return false;
- // Otherwise, treat it as a SoftwareList
- SoftwareList newOther = other as SoftwareList;
-
- // If the SoftwareList information matches
- return (Tag == newOther.Tag
- && Name == newOther.Name
- && Status == newOther.Status
- && Filter == newOther.Filter);
+ // Compare the internal models
+ return _softwareList.EqualTo(otherInternal._softwareList);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/Sound.cs b/SabreTools.DatItems/Formats/Sound.cs
index f14a3370..2e23401b 100644
--- a/SabreTools.DatItems/Formats/Sound.cs
+++ b/SabreTools.DatItems/Formats/Sound.cs
@@ -16,11 +16,21 @@ namespace SabreTools.DatItems.Formats
/// Number of speakers or channels
///
[JsonProperty("channels", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("channels")]
- public long? Channels { get; set; }
+ public long? Channels
+ {
+ get => _sound.ReadLong(Models.Internal.Sound.ChannelsKey);
+ set => _sound[Models.Internal.Sound.ChannelsKey] = value;
+ }
[JsonIgnore]
public bool ChannelsSpecified { get { return Channels != null; } }
+ ///
+ /// Internal Sound model
+ ///
+ [JsonIgnore]
+ private Models.Internal.Sound _sound = new();
+
#endregion
#region Constructors
@@ -45,11 +55,11 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
- Channels = this.Channels,
+ _sound = this._sound?.Clone() as Models.Internal.Sound ?? new Models.Internal.Sound(),
};
}
@@ -58,17 +68,14 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
// If we don't have a Sound, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType || other is not Sound otherInternal)
return false;
- // Otherwise, treat it as a Sound
- Sound newOther = other as Sound;
-
- // If the Sound information matches
- return (Channels == newOther.Channels);
+ // Compare the internal models
+ return _sound.EqualTo(otherInternal._sound);
}
#endregion
diff --git a/SabreTools.DatItems/Formats/SourceDetails.cs b/SabreTools.DatItems/Formats/SourceDetails.cs
index c54b3099..ad8fdf52 100644
--- a/SabreTools.DatItems/Formats/SourceDetails.cs
+++ b/SabreTools.DatItems/Formats/SourceDetails.cs
@@ -18,121 +18,121 @@ namespace SabreTools.DatItems.Formats
///
/// TODO: Is this required?
[JsonProperty("id", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("id")]
- public string Id { get; set; }
+ public string? Id { get; set; }
///
/// Section value
///
[JsonProperty("section", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("section")]
- public string Section { get; set; }
+ public string? Section { get; set; }
///
/// Rom info value
///
[JsonProperty("rominfo", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("rominfo")]
- public string RomInfo { get; set; }
+ public string? RomInfo { get; set; }
///
/// Dumping date value
///
[JsonProperty("d_date", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("d_date")]
- public string DDate { get; set; }
+ public string? DDate { get; set; }
///
/// Dumping date info value
///
[JsonProperty("d_date_info", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("d_date_info")]
- public string DDateInfo { get; set; }
+ public string? DDateInfo { get; set; }
///
/// Release date value
///
[JsonProperty("r_date", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("r_date")]
- public string RDate { get; set; }
+ public string? RDate { get; set; }
///
/// Release date info value
///
[JsonProperty("r_date_info", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("r_date_info")]
- public string RDateInfo { get; set; }
+ public string? RDateInfo { get; set; }
///
/// Origin value
///
[JsonProperty("origin", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("origin")]
- public string Origin { get; set; }
+ public string? Origin { get; set; }
///
/// Region value
///
[JsonProperty("region", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("region")]
- public string Region { get; set; }
+ public string? Region { get; set; }
///
/// Media title value
///
[JsonProperty("media_title", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("media_title")]
- public string MediaTitle { get; set; }
+ public string? MediaTitle { get; set; }
///
/// Dumper value
///
[JsonProperty("dumper", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("dumper")]
- public string Dumper { get; set; }
+ public string? Dumper { get; set; }
///
/// Project value
///
[JsonProperty("project", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("project")]
- public string Project { get; set; }
+ public string? Project { get; set; }
///
/// Original format value
///
[JsonProperty("originalformat", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("originalformat")]
- public string OriginalFormat { get; set; }
+ public string? OriginalFormat { get; set; }
///
/// Nodump value
///
[JsonProperty("nodump", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("nodump")]
- public string Nodump { get; set; }
+ public string? Nodump { get; set; }
///
/// Tool value
///
[JsonProperty("tool", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("tool")]
- public string Tool { get; set; }
+ public string? Tool { get; set; }
///
/// Comment 1 value
///
[JsonProperty("comment1", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("comment1")]
- public string Comment1 { get; set; }
+ public string? Comment1 { get; set; }
///
/// Link 2 value
///
[JsonProperty("comment2", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("comment2")]
- public string Comment2 { get; set; }
+ public string? Comment2 { get; set; }
///
/// Link 1 value
///
[JsonProperty("link1", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("link1")]
- public string Link1 { get; set; }
+ public string? Link1 { get; set; }
///
/// Link 2 value
///
[JsonProperty("link2", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("link2")]
- public string Link2 { get; set; }
+ public string? Link2 { get; set; }
///
/// Link 3 value
///
[JsonProperty("link3", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("link3")]
- public string Link3 { get; set; }
+ public string? Link3 { get; set; }
#endregion
@@ -158,8 +158,8 @@ namespace SabreTools.DatItems.Formats
ItemType = this.ItemType,
DupeType = this.DupeType,
- Machine = this.Machine.Clone() as Machine,
- Source = this.Source.Clone() as Source,
+ Machine = this.Machine?.Clone() as Machine,
+ Source = this.Source?.Clone() as Source,
Remove = this.Remove,
Id = this.Id,
@@ -190,17 +190,17 @@ namespace SabreTools.DatItems.Formats
#region Comparision Methods
///
- public override bool Equals(DatItem other)
+ public override bool Equals(DatItem? other)
{
// If we don't have a SourceDetails, return false
- if (ItemType != other.ItemType)
+ if (ItemType != other?.ItemType)
return false;
// Otherwise, treat it as a SourceDetails
- SourceDetails newOther = other as SourceDetails;
+ SourceDetails? newOther = other as SourceDetails;
// If the Details information matches
- return (Id == newOther.Id
+ return (Id == newOther!.Id
&& Section == newOther.Section
&& RomInfo == newOther.RomInfo
&& DDate == newOther.DDate
diff --git a/SabreTools.DatItems/Machine.cs b/SabreTools.DatItems/Machine.cs
index 456a7ece..8f7affb9 100644
--- a/SabreTools.DatItems/Machine.cs
+++ b/SabreTools.DatItems/Machine.cs
@@ -22,7 +22,7 @@ namespace SabreTools.DatItems
///
[JsonProperty("name", DefaultValueHandling = DefaultValueHandling.Include)]
[XmlElement("name")]
- public string Name { get; set; } = null;
+ public string? Name { get; set; } = null;
///
/// Additional notes
@@ -30,63 +30,63 @@ namespace SabreTools.DatItems
/// Known as "Extra" in AttractMode
[JsonProperty("comment", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("comment")]
- public string Comment { get; set; } = null;
+ public string? Comment { get; set; } = null;
///
/// Extended description
///
[JsonProperty("description", DefaultValueHandling = DefaultValueHandling.Include)]
[XmlElement("description")]
- public string Description { get; set; } = null;
+ public string? Description { get; set; } = null;
///
/// Year(s) of release/manufacture
///
[JsonProperty("year", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("year")]
- public string Year { get; set; } = null;
+ public string? Year { get; set; } = null;
///
/// Manufacturer, if available
///
[JsonProperty("manufacturer", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("manufacturer")]
- public string Manufacturer { get; set; } = null;
+ public string? Manufacturer { get; set; } = null;
///
/// Publisher, if available
///
[JsonProperty("publisher", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("publisher")]
- public string Publisher { get; set; } = null;
+ public string? Publisher { get; set; } = null;
///
/// Category, if available
///
[JsonProperty("category", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("category")]
- public string Category { get; set; } = null;
+ public string? Category { get; set; } = null;
///
/// fomof parent
///
[JsonProperty("romof", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("romof")]
- public string RomOf { get; set; } = null;
+ public string? RomOf { get; set; } = null;
///
/// cloneof parent
///
[JsonProperty("cloneof", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("cloneof")]
- public string CloneOf { get; set; } = null;
+ public string? CloneOf { get; set; } = null;
///
/// sampleof parent
///
[JsonProperty("sampleof", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("sampleof")]
- public string SampleOf { get; set; } = null;
+ public string? SampleOf { get; set; } = null;
///
/// Type of the machine
@@ -109,49 +109,49 @@ namespace SabreTools.DatItems
/// Also in Logiqx EmuArc
[JsonProperty("players", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("players")]
- public string Players { get; set; } = null;
+ public string? Players { get; set; } = null;
///
/// Screen rotation
///
[JsonProperty("rotation", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("rotation")]
- public string Rotation { get; set; } = null;
+ public string? Rotation { get; set; } = null;
///
/// Control method
///
[JsonProperty("control", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("control")]
- public string Control { get; set; } = null;
+ public string? Control { get; set; } = null;
///
/// Support status
///
[JsonProperty("status", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("status")]
- public string Status { get; set; } = null;
+ public string? Status { get; set; } = null;
///
/// Display count
///
[JsonProperty("displaycount", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("displaycount")]
- public string DisplayCount { get; set; } = null;
+ public string? DisplayCount { get; set; } = null;
///
/// Display type
///
[JsonProperty("displaytype", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("displaytype")]
- public string DisplayType { get; set; } = null;
+ public string? DisplayType { get; set; } = null;
///
/// Number of input buttons
///
[JsonProperty("buttons", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("buttons")]
- public string Buttons { get; set; } = null;
+ public string? Buttons { get; set; } = null;
#endregion
@@ -162,7 +162,7 @@ namespace SabreTools.DatItems
///
[JsonProperty("history", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("history")]
- public string History { get; set; } = null;
+ public string? History { get; set; } = null;
///
/// Emulator source file related to the machine
@@ -170,7 +170,7 @@ namespace SabreTools.DatItems
/// Also in Logiqx
[JsonProperty("sourcefile", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("sourcefile")]
- public string SourceFile { get; set; } = null;
+ public string? SourceFile { get; set; } = null;
///
/// Machine runnable status
@@ -192,28 +192,28 @@ namespace SabreTools.DatItems
///
[JsonProperty("board", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("board")]
- public string Board { get; set; } = null;
+ public string? Board { get; set; } = null;
///
/// Rebuild location if different than machine name
///
[JsonProperty("rebuildto", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("rebuildto")]
- public string RebuildTo { get; set; } = null;
+ public string? RebuildTo { get; set; } = null;
///
/// No-Intro ID for the game
///
[JsonProperty("nointroid", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("nointroid")]
- public string NoIntroId { get; set; } = null;
+ public string? NoIntroId { get; set; } = null;
///
/// No-Intro ID for the game
///
[JsonProperty("nointrocloneofid", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("nointrocloneofid")]
- public string NoIntroCloneOfId { get; set; } = null;
+ public string? NoIntroCloneOfId { get; set; } = null;
#endregion
@@ -225,49 +225,49 @@ namespace SabreTools.DatItems
///
[JsonProperty("titleid", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("titleid")]
- public string TitleID { get; set; } = null;
+ public string? TitleID { get; set; } = null;
///
/// Machine developer
///
[JsonProperty("developer", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("developer")]
- public string Developer { get; set; } = null;
+ public string? Developer { get; set; } = null;
///
/// Game genre
///
[JsonProperty("genre", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("genre")]
- public string Genre { get; set; } = null;
+ public string? Genre { get; set; } = null;
///
/// Game subgenre
///
[JsonProperty("subgenre", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("subgenre")]
- public string Subgenre { get; set; } = null;
+ public string? Subgenre { get; set; } = null;
///
/// Game ratings
///
[JsonProperty("ratings", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("ratings")]
- public string Ratings { get; set; } = null;
+ public string? Ratings { get; set; } = null;
///
/// Game score
///
[JsonProperty("score", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("score")]
- public string Score { get; set; } = null;
+ public string? Score { get; set; } = null;
///
/// Is the machine enabled
///
[JsonProperty("enabled", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("enabled")]
- public string Enabled { get; set; } = null; // bool?
+ public string? Enabled { get; set; } = null; // bool?
///
/// Does the game have a CRC check
@@ -284,7 +284,7 @@ namespace SabreTools.DatItems
///
[JsonProperty("relatedto", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("relatedto")]
- public string RelatedTo { get; set; } = null;
+ public string? RelatedTo { get; set; } = null;
#endregion
@@ -295,21 +295,21 @@ namespace SabreTools.DatItems
///
[JsonProperty("genmsxid", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("genmsxid")]
- public string GenMSXID { get; set; } = null;
+ public string? GenMSXID { get; set; } = null;
///
/// MSX System
///
[JsonProperty("system", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("system")]
- public string System { get; set; } = null;
+ public string? System { get; set; } = null;
///
/// Machine country of origin
///
[JsonProperty("country", DefaultValueHandling = DefaultValueHandling.Ignore)]
[XmlElement("country")]
- public string Country { get; set; } = null;
+ public string? Country { get; set; } = null;
#endregion
diff --git a/SabreTools.DatItems/SabreTools.DatItems.csproj b/SabreTools.DatItems/SabreTools.DatItems.csproj
index 0d71852a..1884a695 100644
--- a/SabreTools.DatItems/SabreTools.DatItems.csproj
+++ b/SabreTools.DatItems/SabreTools.DatItems.csproj
@@ -2,12 +2,14 @@
net6.0;net7.0
+ enable
+
diff --git a/SabreTools.DatItems/Source.cs b/SabreTools.DatItems/Source.cs
index a63718eb..b8a107c0 100644
--- a/SabreTools.DatItems/Source.cs
+++ b/SabreTools.DatItems/Source.cs
@@ -15,14 +15,14 @@ namespace SabreTools.DatItems
///
/// Source name
///
- public string Name { get; set; }
+ public string? Name { get; set; }
///
/// Constructor
///
/// Source ID, default 0
/// Source name, default null
- public Source(int id = 0, string source = null)
+ public Source(int id = 0, string? source = null)
{
Index = id;
Name = source;
diff --git a/SabreTools.Filter/FieldManipulator.cs b/SabreTools.Filter/FieldManipulator.cs
index f6fdc40a..4e9b00a0 100644
--- a/SabreTools.Filter/FieldManipulator.cs
+++ b/SabreTools.Filter/FieldManipulator.cs
@@ -70,7 +70,7 @@ namespace SabreTools.Filter
// Retrieve the list of valid fields for the item and validate
var constants = TypeHelper.GetConstants(dictionaryBase.GetType());
- if (constants == null || !constants.Any(c => string.Equals(c, fieldName, StringComparison.InvariantCultureIgnoreCase)))
+ if (constants == null || !constants.Any(c => string.Equals(c, fieldName, StringComparison.OrdinalIgnoreCase)))
return false;
// Set the field with the new value
diff --git a/SabreTools.Filtering/DatItemFilter.cs b/SabreTools.Filtering/DatItemFilter.cs
index c5bf4a63..57c0c6dd 100644
--- a/SabreTools.Filtering/DatItemFilter.cs
+++ b/SabreTools.Filtering/DatItemFilter.cs
@@ -785,10 +785,14 @@ namespace SabreTools.Filtering
Chip chip => PassesFilters(chip),
Condition condition => PassesFilters(condition),
Configuration configuration => PassesFilters(configuration),
+ ConfLocation confLocation => PassesFilters(confLocation),
+ ConfSetting confSetting => PassesFilters(confSetting),
Control control => PassesFilters(control),
DataArea dataArea => PassesFilters(dataArea),
Device device => PassesFilters(device),
+ DipLocation dipLocation => PassesFilters(dipLocation),
DipSwitch dipSwitch => PassesFilters(dipSwitch),
+ DipValue dipValue => PassesFilters(dipValue),
Disk disk => PassesFilters(disk),
DiskArea diskArea => PassesFilters(diskArea),
Display display => PassesFilters(display),
@@ -798,7 +802,6 @@ namespace SabreTools.Filtering
Info info => PassesFilters(info),
Input input => PassesFilters(input),
Instance instance => PassesFilters(instance),
- Location location => PassesFilters(location),
Media media => PassesFilters(media),
Part part => PassesFilters(part),
PartFeature partFeature => PassesFilters(partFeature),
@@ -806,7 +809,6 @@ namespace SabreTools.Filtering
RamOption ramOption => PassesFilters(ramOption),
Release release => PassesFilters(release),
Rom rom => PassesFilters(rom),
- Setting setting => PassesFilters(setting),
SharedFeature sharedFeature => PassesFilters(sharedFeature),
Slot slot => PassesFilters(slot),
SlotOption slotOption => PassesFilters(slotOption),
@@ -1024,7 +1026,7 @@ namespace SabreTools.Filtering
// Filter on individual locations
if (configuration.LocationsSpecified)
{
- foreach (Location subLocation in configuration.Locations)
+ foreach (ConfLocation subLocation in configuration.Locations)
{
if (!PassesFilters(subLocation))
return false;
@@ -1034,7 +1036,7 @@ namespace SabreTools.Filtering
// Filter on individual settings
if (configuration.SettingsSpecified)
{
- foreach (Setting subSetting in configuration.Settings)
+ foreach (ConfSetting subSetting in configuration.Settings)
{
if (!PassesFilters(subSetting))
return false;
@@ -1044,6 +1046,60 @@ namespace SabreTools.Filtering
return true;
}
+ ///
+ /// Check to see if a ConfLocation passes the filters
+ ///
+ /// ConfLocation to check
+ /// True if the item passed the filter, false otherwise
+ private bool PassesFilters(ConfLocation confLocation)
+ {
+ // DatItem_Location_Inverted
+ if (!PassBoolFilter(Location_Inverted, confLocation.Inverted))
+ return false;
+
+ // DatItem_Location_Name
+ if (!PassStringFilter(Location_Name, confLocation.Name))
+ return false;
+
+ // DatItem_Location_Number
+ if (!PassLongFilter(Location_Number, confLocation.Number))
+ return false;
+
+ return true;
+ }
+
+ ///
+ /// Check to see if a ConfSetting passes the filters
+ ///
+ /// ConfSetting to check
+ /// True if the item passed the filter, false otherwise
+ private bool PassesFilters(ConfSetting confSetting)
+ {
+ // DatItem_Setting_Default
+ if (!PassBoolFilter(Setting_Default, confSetting.Default))
+ return false;
+
+ // DatItem_Setting_Name
+ if (!PassStringFilter(Setting_Name, confSetting.Name))
+ return false;
+
+ // DatItem_Setting_Value
+ if (!PassStringFilter(Setting_Value, confSetting.Value))
+ return false;
+
+ // Filter on individual conditions
+ if (confSetting.ConditionsSpecified)
+ {
+ foreach (Condition subCondition in confSetting.Conditions)
+ {
+ if (!PassesFilters(subCondition, true))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
///
/// Check to see if a Control passes the filters
///
@@ -1184,6 +1240,28 @@ namespace SabreTools.Filtering
return true;
}
+ ///
+ /// Check to see if a DipLocation passes the filters
+ ///
+ /// DipLocation to check
+ /// True if the item passed the filter, false otherwise
+ private bool PassesFilters(DipLocation dipLocation)
+ {
+ // DatItem_Location_Inverted
+ if (!PassBoolFilter(Location_Inverted, dipLocation.Inverted))
+ return false;
+
+ // DatItem_Location_Name
+ if (!PassStringFilter(Location_Name, dipLocation.Name))
+ return false;
+
+ // DatItem_Location_Number
+ if (!PassLongFilter(Location_Number, dipLocation.Number))
+ return false;
+
+ return true;
+ }
+
///
/// Check to see if a DipSwitch passes the filters
///
@@ -1212,7 +1290,7 @@ namespace SabreTools.Filtering
// Filter on individual locations
if (dipSwitch.LocationsSpecified)
{
- foreach (Location subLocation in dipSwitch.Locations)
+ foreach (DipLocation subLocation in dipSwitch.Locations)
{
if (!PassesFilters(subLocation))
return false;
@@ -1222,7 +1300,7 @@ namespace SabreTools.Filtering
// Filter on individual values
if (dipSwitch.ValuesSpecified)
{
- foreach (Setting subValue in dipSwitch.Values)
+ foreach (DipValue subValue in dipSwitch.Values)
{
if (!PassesFilters(subValue))
return false;
@@ -1239,6 +1317,38 @@ namespace SabreTools.Filtering
return true;
}
+ ///
+ /// Check to see if a DipValue passes the filters
+ ///
+ /// DipValue to check
+ /// True if the item passed the filter, false otherwise
+ private bool PassesFilters(DipValue dipValue)
+ {
+ // DatItem_Setting_Default
+ if (!PassBoolFilter(Setting_Default, dipValue.Default))
+ return false;
+
+ // DatItem_Setting_Name
+ if (!PassStringFilter(Setting_Name, dipValue.Name))
+ return false;
+
+ // DatItem_Setting_Value
+ if (!PassStringFilter(Setting_Value, dipValue.Value))
+ return false;
+
+ // Filter on individual conditions
+ if (dipValue.ConditionsSpecified)
+ {
+ foreach (Condition subCondition in dipValue.Conditions)
+ {
+ if (!PassesFilters(subCondition, true))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
///
/// Check to see if a Disk passes the filters
///
@@ -1539,28 +1649,6 @@ namespace SabreTools.Filtering
return true;
}
- ///
- /// Check to see if a Location passes the filters
- ///
- /// Location to check
- /// True if the item passed the filter, false otherwise
- private bool PassesFilters(Location location)
- {
- // DatItem_Location_Inverted
- if (!PassBoolFilter(Location_Inverted, location.Inverted))
- return false;
-
- // DatItem_Location_Name
- if (!PassStringFilter(Location_Name, location.Name))
- return false;
-
- // DatItem_Location_Number
- if (!PassLongFilter(Location_Number, location.Number))
- return false;
-
- return true;
- }
-
///
/// Check to see if a Media passes the filters
///
@@ -1855,38 +1943,6 @@ namespace SabreTools.Filtering
return true;
}
- ///
- /// Check to see if a Setting passes the filters
- ///
- /// Setting to check
- /// True if the item passed the filter, false otherwise
- private bool PassesFilters(Setting setting)
- {
- // DatItem_Setting_Default
- if (!PassBoolFilter(Setting_Default, setting.Default))
- return false;
-
- // DatItem_Setting_Name
- if (!PassStringFilter(Setting_Name, setting.Name))
- return false;
-
- // DatItem_Setting_Value
- if (!PassStringFilter(Setting_Value, setting.Value))
- return false;
-
- // Filter on individual conditions
- if (setting.ConditionsSpecified)
- {
- foreach (Condition subCondition in setting.Conditions)
- {
- if (!PassesFilters(subCondition, true))
- return false;
- }
- }
-
- return true;
- }
-
///
/// Check to see if a SharedFeature passes the filters
///
diff --git a/SabreTools.Filtering/DatItemRemover.cs b/SabreTools.Filtering/DatItemRemover.cs
index 8fc58e1b..98c128b2 100644
--- a/SabreTools.Filtering/DatItemRemover.cs
+++ b/SabreTools.Filtering/DatItemRemover.cs
@@ -92,10 +92,14 @@ namespace SabreTools.Filtering
else if (datItem is Chip) RemoveFields(datItem as Chip);
else if (datItem is Condition) RemoveFields(datItem as Condition);
else if (datItem is Configuration) RemoveFields(datItem as Configuration);
+ else if (datItem is ConfLocation) RemoveFields(datItem as ConfLocation);
+ else if (datItem is ConfSetting) RemoveFields(datItem as ConfSetting);
else if (datItem is Control) RemoveFields(datItem as Control);
else if (datItem is DataArea) RemoveFields(datItem as DataArea);
else if (datItem is Device) RemoveFields(datItem as Device);
+ else if (datItem is DipLocation) RemoveFields(datItem as DipLocation);
else if (datItem is DipSwitch) RemoveFields(datItem as DipSwitch);
+ else if (datItem is DipValue) RemoveFields(datItem as DipValue);
else if (datItem is Disk) RemoveFields(datItem as Disk);
else if (datItem is DiskArea) RemoveFields(datItem as DiskArea);
else if (datItem is Display) RemoveFields(datItem as Display);
@@ -105,7 +109,6 @@ namespace SabreTools.Filtering
else if (datItem is Info) RemoveFields(datItem as Info);
else if (datItem is Input) RemoveFields(datItem as Input);
else if (datItem is Instance) RemoveFields(datItem as Instance);
- else if (datItem is Location) RemoveFields(datItem as Location);
else if (datItem is Media) RemoveFields(datItem as Media);
else if (datItem is Part) RemoveFields(datItem as Part);
else if (datItem is PartFeature) RemoveFields(datItem as PartFeature);
@@ -113,7 +116,6 @@ namespace SabreTools.Filtering
else if (datItem is RamOption) RemoveFields(datItem as RamOption);
else if (datItem is Release) RemoveFields(datItem as Release);
else if (datItem is Rom) RemoveFields(datItem as Rom);
- else if (datItem is Setting) RemoveFields(datItem as Setting);
else if (datItem is SharedFeature) RemoveFields(datItem as SharedFeature);
else if (datItem is Slot) RemoveFields(datItem as Slot);
else if (datItem is SlotOption) RemoveFields(datItem as SlotOption);
@@ -394,7 +396,7 @@ namespace SabreTools.Filtering
if (configuration.LocationsSpecified)
{
- foreach (Location subLocation in configuration.Locations)
+ foreach (ConfLocation subLocation in configuration.Locations)
{
RemoveFields(subLocation);
}
@@ -402,13 +404,53 @@ namespace SabreTools.Filtering
if (configuration.SettingsSpecified)
{
- foreach (Setting subSetting in configuration.Settings)
+ foreach (ConfSetting subSetting in configuration.Settings)
{
RemoveFields(subSetting);
}
}
}
+ ///
+ /// Remove fields with given values
+ ///
+ /// ConfLocation to remove fields from
+ private void RemoveFields(ConfLocation confLocation)
+ {
+ if (DatItemFields.Contains(DatItemField.Location_Inverted))
+ confLocation.Inverted = null;
+
+ if (DatItemFields.Contains(DatItemField.Location_Name))
+ confLocation.Name = null;
+
+ if (DatItemFields.Contains(DatItemField.Location_Number))
+ confLocation.Number = null;
+ }
+
+ ///
+ /// Remove fields with given values
+ ///
+ /// ConfSetting to remove fields from
+ private void RemoveFields(ConfSetting confsetting)
+ {
+ if (DatItemFields.Contains(DatItemField.Setting_Default))
+ confsetting.Default = null;
+
+ if (DatItemFields.Contains(DatItemField.Setting_Name))
+ confsetting.Name = null;
+
+ if (DatItemFields.Contains(DatItemField.Setting_Value))
+ confsetting.Value = null;
+
+ if (confsetting.ConditionsSpecified)
+ {
+ foreach (Condition subCondition in confsetting.Conditions)
+ {
+ RemoveFields(subCondition, true);
+ }
+ }
+ }
+
///
/// Remove fields with given values
///
@@ -509,6 +551,22 @@ namespace SabreTools.Filtering
}
}
+ ///
+ /// Remove fields with given values
+ ///
+ /// DipLocation to remove fields from
+ private void RemoveFields(DipLocation dipLocation)
+ {
+ if (DatItemFields.Contains(DatItemField.Location_Inverted))
+ dipLocation.Inverted = null;
+
+ if (DatItemFields.Contains(DatItemField.Location_Name))
+ dipLocation.Name = null;
+
+ if (DatItemFields.Contains(DatItemField.Location_Number))
+ dipLocation.Number = null;
+ }
+
///
/// Remove fields with given values
///
@@ -531,7 +589,7 @@ namespace SabreTools.Filtering
if (dipSwitch.LocationsSpecified)
{
- foreach (Location subLocation in dipSwitch.Locations)
+ foreach (DipLocation subLocation in dipSwitch.Locations)
{
RemoveFields(subLocation);
}
@@ -539,7 +597,7 @@ namespace SabreTools.Filtering
if (dipSwitch.ValuesSpecified)
{
- foreach (Setting subValue in dipSwitch.Values)
+ foreach (DipValue subValue in dipSwitch.Values)
{
RemoveFields(subValue);
}
@@ -549,6 +607,30 @@ namespace SabreTools.Filtering
RemoveFields(dipSwitch.Part);
}
+ ///
+ /// Remove fields with given values
+ ///
+ /// DipValue to remove fields from
+ private void RemoveFields(DipValue dipValue)
+ {
+ if (DatItemFields.Contains(DatItemField.Setting_Default))
+ dipValue.Default = null;
+
+ if (DatItemFields.Contains(DatItemField.Setting_Name))
+ dipValue.Name = null;
+
+ if (DatItemFields.Contains(DatItemField.Setting_Value))
+ dipValue.Value = null;
+
+ if (dipValue.ConditionsSpecified)
+ {
+ foreach (Condition subCondition in dipValue.Conditions)
+ {
+ RemoveFields(subCondition, true);
+ }
+ }
+ }
+
///
/// Remove fields with given values
///
@@ -752,22 +834,6 @@ namespace SabreTools.Filtering
instance.Name = null;
}
- ///
- /// Remove fields with given values
- ///
- /// Location to remove fields from
- private void RemoveFields(Location location)
- {
- if (DatItemFields.Contains(DatItemField.Location_Inverted))
- location.Inverted = null;
-
- if (DatItemFields.Contains(DatItemField.Location_Name))
- location.Name = null;
-
- if (DatItemFields.Contains(DatItemField.Location_Number))
- location.Number = null;
- }
-
///
/// Remove fields with given values
///
@@ -977,30 +1043,6 @@ namespace SabreTools.Filtering
RemoveFields(rom.Part);
}
- ///
- /// Remove fields with given values
- ///
- /// Setting to remove fields from
- private void RemoveFields(Setting setting)
- {
- if (DatItemFields.Contains(DatItemField.Setting_Default))
- setting.Default = null;
-
- if (DatItemFields.Contains(DatItemField.Setting_Name))
- setting.Name = null;
-
- if (DatItemFields.Contains(DatItemField.Setting_Value))
- setting.Value = null;
-
- if (setting.ConditionsSpecified)
- {
- foreach (Condition subCondition in setting.Conditions)
- {
- RemoveFields(subCondition, true);
- }
- }
- }
-
///
/// Remove fields with given values
///
diff --git a/SabreTools.Filtering/Replacer.cs b/SabreTools.Filtering/Replacer.cs
index 6e6ea810..a5a0fa60 100644
--- a/SabreTools.Filtering/Replacer.cs
+++ b/SabreTools.Filtering/Replacer.cs
@@ -40,10 +40,14 @@ namespace SabreTools.Filtering
else if (datItem is Chip) ReplaceFields(datItem as Chip, repDatItem as Chip, datItemFields);
else if (datItem is Condition) ReplaceFields(datItem as Condition, repDatItem as Condition, datItemFields);
else if (datItem is Configuration) ReplaceFields(datItem as Configuration, repDatItem as Configuration, datItemFields);
+ else if (datItem is ConfLocation) ReplaceFields(datItem as ConfLocation, repDatItem as ConfLocation, datItemFields);
+ else if (datItem is ConfSetting) ReplaceFields(datItem as ConfSetting, repDatItem as ConfSetting, datItemFields);
else if (datItem is Control) ReplaceFields(datItem as Control, repDatItem as Control, datItemFields);
else if (datItem is DataArea) ReplaceFields(datItem as DataArea, repDatItem as DataArea, datItemFields);
else if (datItem is Device) ReplaceFields(datItem as Device, repDatItem as Device, datItemFields);
+ else if (datItem is DipLocation) ReplaceFields(datItem as DipLocation, repDatItem as DipLocation, datItemFields);
else if (datItem is DipSwitch) ReplaceFields(datItem as DipSwitch, repDatItem as DipSwitch, datItemFields);
+ else if (datItem is DipValue) ReplaceFields(datItem as DipValue, repDatItem as DipValue, datItemFields);
else if (datItem is Disk) ReplaceFields(datItem as Disk, repDatItem as Disk, datItemFields);
else if (datItem is DiskArea) ReplaceFields(datItem as DiskArea, repDatItem as DiskArea, datItemFields);
else if (datItem is Display) ReplaceFields(datItem as Display, repDatItem as Display, datItemFields);
@@ -53,7 +57,6 @@ namespace SabreTools.Filtering
else if (datItem is Info) ReplaceFields(datItem as Info, repDatItem as Info, datItemFields);
else if (datItem is Input) ReplaceFields(datItem as Input, repDatItem as Input, datItemFields);
else if (datItem is Instance) ReplaceFields(datItem as Instance, repDatItem as Instance, datItemFields);
- else if (datItem is Location) ReplaceFields(datItem as Location, repDatItem as Location, datItemFields);
else if (datItem is Media) ReplaceFields(datItem as Media, repDatItem as Media, datItemFields);
else if (datItem is Part) ReplaceFields(datItem as Part, repDatItem as Part, datItemFields);
else if (datItem is PartFeature) ReplaceFields(datItem as PartFeature, repDatItem as PartFeature, datItemFields);
@@ -61,7 +64,6 @@ namespace SabreTools.Filtering
else if (datItem is RamOption) ReplaceFields(datItem as RamOption, repDatItem as RamOption, datItemFields);
else if (datItem is Release) ReplaceFields(datItem as Release, repDatItem as Release, datItemFields);
else if (datItem is Rom) ReplaceFields(datItem as Rom, repDatItem as Rom, datItemFields);
- else if (datItem is Setting) ReplaceFields(datItem as Setting, repDatItem as Setting, datItemFields);
else if (datItem is SharedFeature) ReplaceFields(datItem as SharedFeature, repDatItem as SharedFeature, datItemFields);
else if (datItem is Slot) ReplaceFields(datItem as Slot, repDatItem as Slot, datItemFields);
else if (datItem is SlotOption) ReplaceFields(datItem as SlotOption, repDatItem as SlotOption, datItemFields);
@@ -351,6 +353,46 @@ namespace SabreTools.Filtering
// can replace every setting under this item
}
+ ///
+ /// Replace fields with given values
+ ///
+ /// ConfLocation to remove replace fields in
+ /// ConfLocation to pull new information from
+ /// List of fields representing what should be updated
+ private static void ReplaceFields(ConfLocation location, ConfLocation newItem, List datItemFields)
+ {
+ if (datItemFields.Contains(DatItemField.Location_Inverted))
+ location.Inverted = newItem.Inverted;
+
+ if (datItemFields.Contains(DatItemField.Location_Name))
+ location.Name = newItem.Name;
+
+ if (datItemFields.Contains(DatItemField.Location_Number))
+ location.Number = newItem.Number;
+ }
+
+ ///
+ /// Replace fields with given values
+ ///
+ /// ConfSetting to remove replace fields in
+ /// ConfSetting to pull new information from
+ /// List of fields representing what should be updated
+ private static void ReplaceFields(ConfSetting confSetting, ConfSetting newItem, List datItemFields)
+ {
+ if (datItemFields.Contains(DatItemField.Setting_Default))
+ confSetting.Default = newItem.Default;
+
+ if (datItemFields.Contains(DatItemField.Setting_Name))
+ confSetting.Name = newItem.Name;
+
+ if (datItemFields.Contains(DatItemField.Setting_Value))
+ confSetting.Value = newItem.Value;
+
+ // Condition_* doesn't make sense here
+ // since not every condition under the other item
+ // can replace every condition under this item
+ }
+
///
/// Replace fields with given values
///
@@ -449,6 +491,24 @@ namespace SabreTools.Filtering
// can replace every extension under this item
}
+ ///
+ /// Replace fields with given values
+ ///
+ /// DipLocation to remove replace fields in
+ /// DipLocation to pull new information from
+ /// List of fields representing what should be updated
+ private static void ReplaceFields(DipLocation location, DipLocation newItem, List datItemFields)
+ {
+ if (datItemFields.Contains(DatItemField.Location_Inverted))
+ location.Inverted = newItem.Inverted;
+
+ if (datItemFields.Contains(DatItemField.Location_Name))
+ location.Name = newItem.Name;
+
+ if (datItemFields.Contains(DatItemField.Location_Number))
+ location.Number = newItem.Number;
+ }
+
///
/// Replace fields with given values
///
@@ -479,6 +539,28 @@ namespace SabreTools.Filtering
ReplaceFields(dipSwitch.Part, newItem.Part, datItemFields);
}
+ ///
+ /// Replace fields with given values
+ ///
+ /// DipValue to remove replace fields in
+ /// DipValue to pull new information from
+ /// List of fields representing what should be updated
+ private static void ReplaceFields(DipValue dipValue, DipValue newItem, List datItemFields)
+ {
+ if (datItemFields.Contains(DatItemField.Setting_Default))
+ dipValue.Default = newItem.Default;
+
+ if (datItemFields.Contains(DatItemField.Setting_Name))
+ dipValue.Name = newItem.Name;
+
+ if (datItemFields.Contains(DatItemField.Setting_Value))
+ dipValue.Value = newItem.Value;
+
+ // Condition_* doesn't make sense here
+ // since not every condition under the other item
+ // can replace every condition under this item
+ }
+
///
/// Replace fields with given values
///
@@ -702,24 +784,6 @@ namespace SabreTools.Filtering
instance.Name = newItem.Name;
}
- ///
- /// Replace fields with given values
- ///
- /// Location to remove replace fields in
- /// Location to pull new information from
- /// List of fields representing what should be updated
- private static void ReplaceFields(Location location, Location newItem, List datItemFields)
- {
- if (datItemFields.Contains(DatItemField.Location_Inverted))
- location.Inverted = newItem.Inverted;
-
- if (datItemFields.Contains(DatItemField.Location_Name))
- location.Name = newItem.Name;
-
- if (datItemFields.Contains(DatItemField.Location_Number))
- location.Number = newItem.Number;
- }
-
///
/// Replace fields with given values
///
@@ -968,28 +1032,6 @@ namespace SabreTools.Filtering
ReplaceFields(rom.Part, newItem.Part, datItemFields);
}
- ///
- /// Replace fields with given values
- ///
- /// Setting to remove replace fields in
- /// Setting to pull new information from
- /// List of fields representing what should be updated
- private static void ReplaceFields(Setting setting, Setting newItem, List datItemFields)
- {
- if (datItemFields.Contains(DatItemField.Setting_Default))
- setting.Default = newItem.Default;
-
- if (datItemFields.Contains(DatItemField.Setting_Name))
- setting.Name = newItem.Name;
-
- if (datItemFields.Contains(DatItemField.Setting_Value))
- setting.Value = newItem.Value;
-
- // Condition_* doesn't make sense here
- // since not every condition under the other item
- // can replace every condition under this item
- }
-
///
/// Replace fields with given values
///
diff --git a/SabreTools.Models/Internal/DictionaryBase.cs b/SabreTools.Models/Internal/DictionaryBase.cs
index 9424042e..1a0077fd 100644
--- a/SabreTools.Models/Internal/DictionaryBase.cs
+++ b/SabreTools.Models/Internal/DictionaryBase.cs
@@ -93,6 +93,9 @@ namespace SabreTools.Models.Internal
if (asArray != null)
return string.Join(',', asArray);
+ // TODO: Add byte array conversion here
+ // TODO: Add byte array read helper
+
return this[key]!.ToString();
}
diff --git a/SabreTools.Models/Internal/RamOption.cs b/SabreTools.Models/Internal/RamOption.cs
index 79c91b3f..de59581c 100644
--- a/SabreTools.Models/Internal/RamOption.cs
+++ b/SabreTools.Models/Internal/RamOption.cs
@@ -8,6 +8,9 @@ namespace SabreTools.Models.Internal
{
#region Keys
+ /// string
+ public const string ContentKey = "content";
+
/// (yes|no) "no"
public const string DefaultKey = "default";
diff --git a/SabreTools.Models/Listxml/RamOption.cs b/SabreTools.Models/Listxml/RamOption.cs
index f3e42f7c..a6a7603f 100644
--- a/SabreTools.Models/Listxml/RamOption.cs
+++ b/SabreTools.Models/Listxml/RamOption.cs
@@ -13,6 +13,9 @@ namespace SabreTools.Models.Listxml
[XmlAttribute("default")]
public string? Default { get; set; }
+ [XmlText]
+ public string? Content { get; set; }
+
#region DO NOT USE IN PRODUCTION
/// Should be empty
diff --git a/SabreTools.Serialization/Listxml.Deserializer.cs b/SabreTools.Serialization/Listxml.Deserializer.cs
index 3adf41f4..ecb6d513 100644
--- a/SabreTools.Serialization/Listxml.Deserializer.cs
+++ b/SabreTools.Serialization/Listxml.Deserializer.cs
@@ -717,6 +717,7 @@ namespace SabreTools.Serialization
{
Name = item.ReadString(Models.Internal.RamOption.NameKey),
Default = item.ReadString(Models.Internal.RamOption.DefaultKey),
+ Content = item.ReadString(Models.Internal.RamOption.ContentKey),
};
return ramOption;
}
diff --git a/SabreTools.Serialization/Listxml.Serializer.cs b/SabreTools.Serialization/Listxml.Serializer.cs
index 18c14b09..51cbc1b6 100644
--- a/SabreTools.Serialization/Listxml.Serializer.cs
+++ b/SabreTools.Serialization/Listxml.Serializer.cs
@@ -685,6 +685,7 @@ namespace SabreTools.Serialization
{
[Models.Internal.RamOption.NameKey] = item.Name,
[Models.Internal.RamOption.DefaultKey] = item.Default,
+ [Models.Internal.RamOption.ContentKey] = item.Content,
};
return ramOption;
}
diff --git a/SabreTools.Test/Core/ConvertersTests.cs b/SabreTools.Test/Core/ConvertersTests.cs
index e1786bf8..9c23f74c 100644
--- a/SabreTools.Test/Core/ConvertersTests.cs
+++ b/SabreTools.Test/Core/ConvertersTests.cs
@@ -194,12 +194,16 @@ namespace SabreTools.Test.Core
[InlineData("chip", ItemType.Chip)]
[InlineData("condition", ItemType.Condition)]
[InlineData("configuration", ItemType.Configuration)]
+ [InlineData("conflocation", ItemType.ConfLocation)]
+ [InlineData("confsetting", ItemType.ConfSetting)]
[InlineData("control", ItemType.Control)]
[InlineData("dataarea", ItemType.DataArea)]
[InlineData("device", ItemType.Device)]
[InlineData("deviceref", ItemType.DeviceReference)]
[InlineData("device_ref", ItemType.DeviceReference)]
+ [InlineData("diplocation", ItemType.DipLocation)]
[InlineData("dipswitch", ItemType.DipSwitch)]
+ [InlineData("dipvalue", ItemType.DipValue)]
[InlineData("disk", ItemType.Disk)]
[InlineData("diskarea", ItemType.DiskArea)]
[InlineData("display", ItemType.Display)]
@@ -210,7 +214,6 @@ namespace SabreTools.Test.Core
[InlineData("info", ItemType.Info)]
[InlineData("input", ItemType.Input)]
[InlineData("instance", ItemType.Instance)]
- [InlineData("location", ItemType.Location)]
[InlineData("media", ItemType.Media)]
[InlineData("part", ItemType.Part)]
[InlineData("partfeature", ItemType.PartFeature)]
@@ -224,7 +227,6 @@ namespace SabreTools.Test.Core
[InlineData("rom", ItemType.Rom)]
[InlineData("sample", ItemType.Sample)]
[InlineData("serials", ItemType.Serials)]
- [InlineData("setting", ItemType.Setting)]
[InlineData("sharedfeat", ItemType.SharedFeature)]
[InlineData("shared_feat", ItemType.SharedFeature)]
[InlineData("sharedfeature", ItemType.SharedFeature)]
@@ -657,11 +659,15 @@ namespace SabreTools.Test.Core
[InlineData(ItemType.Chip, "chip")]
[InlineData(ItemType.Condition, "condition")]
[InlineData(ItemType.Configuration, "configuration")]
+ [InlineData(ItemType.ConfLocation, "conflocation")]
+ [InlineData(ItemType.ConfSetting, "confsetting")]
[InlineData(ItemType.Control, "control")]
[InlineData(ItemType.DataArea, "dataarea")]
[InlineData(ItemType.Device, "device")]
[InlineData(ItemType.DeviceReference, "device_ref")]
+ [InlineData(ItemType.DipLocation, "diplocation")]
[InlineData(ItemType.DipSwitch, "dipswitch")]
+ [InlineData(ItemType.DipValue, "dipvalue")]
[InlineData(ItemType.Disk, "disk")]
[InlineData(ItemType.DiskArea, "diskarea")]
[InlineData(ItemType.Display, "display")]
@@ -672,7 +678,6 @@ namespace SabreTools.Test.Core
[InlineData(ItemType.Info, "info")]
[InlineData(ItemType.Input, "input")]
[InlineData(ItemType.Instance, "instance")]
- [InlineData(ItemType.Location, "location")]
[InlineData(ItemType.Media, "media")]
[InlineData(ItemType.Part, "part")]
[InlineData(ItemType.PartFeature, "part_feature")]
@@ -683,7 +688,6 @@ namespace SabreTools.Test.Core
[InlineData(ItemType.Rom, "rom")]
[InlineData(ItemType.Sample, "sample")]
[InlineData(ItemType.Serials, "serials")]
- [InlineData(ItemType.Setting, "setting")]
[InlineData(ItemType.SharedFeature, "sharedfeat")]
[InlineData(ItemType.Slot, "slot")]
[InlineData(ItemType.SlotOption, "slotoption")]