diff --git a/SabreTools.Library/DatFiles/Enums.cs b/SabreTools.Library/DatFiles/Enums.cs index aa98ca9f..517e0ea6 100644 --- a/SabreTools.Library/DatFiles/Enums.cs +++ b/SabreTools.Library/DatFiles/Enums.cs @@ -5,6 +5,7 @@ namespace SabreTools.Library.DatFiles /// /// Determines how the current dictionary is bucketed by /// + /// TODO: Can we use "Field" instead of this? How much more stupidly complex would that make things? public enum BucketedBy { Default = 0, diff --git a/SabreTools.Library/DatItems/Archive.cs b/SabreTools.Library/DatItems/Archive.cs index aee0343e..ea6deca2 100644 --- a/SabreTools.Library/DatItems/Archive.cs +++ b/SabreTools.Library/DatItems/Archive.cs @@ -1,6 +1,4 @@ -using SabreTools.Library.Data; - -namespace SabreTools.Library.DatItems +namespace SabreTools.Library.DatItems { /// /// Represents generic archive files to be included in a set diff --git a/SabreTools.Library/DatItems/BiosSet.cs b/SabreTools.Library/DatItems/BiosSet.cs index 1f745bab..b5f4d547 100644 --- a/SabreTools.Library/DatItems/BiosSet.cs +++ b/SabreTools.Library/DatItems/BiosSet.cs @@ -1,4 +1,5 @@ -using SabreTools.Library.Data; +using System.Collections.Generic; +using System.Security.Permissions; using Newtonsoft.Json; namespace SabreTools.Library.DatItems @@ -24,6 +25,42 @@ namespace SabreTools.Library.DatItems #endregion + #region Accessors + + /// + /// Get the value of that field as a string, if possible + /// + public override string GetField(Field field, List excludeFields) + { + // If the field is to be excluded, return empty string + if (excludeFields.Contains(field)) + return string.Empty; + + // Handle BiosSet-specific fields + string fieldValue; + switch (field) + { + case Field.Default: + fieldValue = Default?.ToString(); + break; + case Field.BiosDescription: + fieldValue = Description; + break; + + // For everything else, use the base method + default: + return base.GetField(field, excludeFields); + } + + // Make sure we don't return null + if (string.IsNullOrEmpty(fieldValue)) + fieldValue = string.Empty; + + return fieldValue; + } + + #endregion + #region Constructors /// diff --git a/SabreTools.Library/DatItems/DatItem.cs b/SabreTools.Library/DatItems/DatItem.cs index ec77e282..6c482ba5 100644 --- a/SabreTools.Library/DatItems/DatItem.cs +++ b/SabreTools.Library/DatItems/DatItem.cs @@ -615,7 +615,7 @@ namespace SabreTools.Library.DatItems /// /// Get the value of that field as a string, if possible /// - public string GetField(Field field, List excludeFields) + public virtual string GetField(Field field, List excludeFields) { // If the field is to be excluded, return empty string if (excludeFields.Contains(field)) @@ -625,196 +625,80 @@ namespace SabreTools.Library.DatItems switch (field) { case Field.Name: - fieldValue = this.Name; + fieldValue = Name; break; case Field.PartName: - fieldValue = this.PartName; + fieldValue = PartName; break; case Field.PartInterface: - fieldValue = this.PartInterface; + fieldValue = PartInterface; break; case Field.Features: - fieldValue = string.Join(";", (this.Features ?? new List>()).Select(f => $"{f.Key}={f.Value}")); + fieldValue = string.Join(";", (Features ?? new List>()).Select(f => $"{f.Key}={f.Value}")); break; case Field.AreaName: - fieldValue = this.AreaName; + fieldValue = AreaName; break; case Field.AreaSize: - fieldValue = this.AreaSize?.ToString(); + fieldValue = AreaSize?.ToString(); break; case Field.MachineName: - fieldValue = this.MachineName; + fieldValue = MachineName; break; case Field.Comment: - fieldValue = this.Comment; + fieldValue = Comment; break; case Field.Description: - fieldValue = this.MachineDescription; + fieldValue = MachineDescription; break; case Field.Year: - fieldValue = this.Year; + fieldValue = Year; break; case Field.Manufacturer: - fieldValue = this.Manufacturer; + fieldValue = Manufacturer; break; case Field.Publisher: - fieldValue = this.Publisher; + fieldValue = Publisher; break; case Field.Category: - fieldValue = this.Category; + fieldValue = Category; break; case Field.RomOf: - fieldValue = this.RomOf; + fieldValue = RomOf; break; case Field.CloneOf: - fieldValue = this.CloneOf; + fieldValue = CloneOf; break; case Field.SampleOf: - fieldValue = this.SampleOf; + fieldValue = SampleOf; break; case Field.Supported: - fieldValue = this.Supported?.ToString(); + fieldValue = Supported?.ToString(); break; case Field.SourceFile: - fieldValue = this.SourceFile; + fieldValue = SourceFile; break; case Field.Runnable: - fieldValue = this.Runnable?.ToString(); + fieldValue = Runnable?.ToString(); break; case Field.Board: - fieldValue = this.Board; + fieldValue = Board; break; case Field.RebuildTo: - fieldValue = this.RebuildTo; + fieldValue = RebuildTo; break; case Field.Devices: - fieldValue = string.Join(";", this.Devices ?? new List()); + fieldValue = string.Join(";", Devices ?? new List()); break; case Field.SlotOptions: - fieldValue = string.Join(";", this.SlotOptions ?? new List()); + fieldValue = string.Join(";", SlotOptions ?? new List()); break; case Field.Infos: - fieldValue = string.Join(";", (this.Infos ?? new List>()).Select(i => $"{i.Key}={i.Value}")); + fieldValue = string.Join(";", (Infos ?? new List>()).Select(i => $"{i.Key}={i.Value}")); break; case Field.MachineType: - fieldValue = this.MachineType.ToString(); - break; - - case Field.Default: - if (ItemType == ItemType.BiosSet) - fieldValue = (this as BiosSet).Default?.ToString(); - else if (ItemType == ItemType.Release) - fieldValue = (this as Release).Default?.ToString(); - break; - case Field.BiosDescription: - if (ItemType == ItemType.BiosSet) - fieldValue = (this as BiosSet).Description; - break; - - case Field.MD5: - if (ItemType == ItemType.Disk) - fieldValue = (this as Disk).MD5; - else if (ItemType == ItemType.Rom) - fieldValue = (this as Rom).MD5; - break; -#if NET_FRAMEWORK - case Field.RIPEMD160: - if (ItemType == ItemType.Disk) - fieldValue = (this as Disk).RIPEMD160; - else if (ItemType == ItemType.Rom) - fieldValue = (this as Rom).RIPEMD160; - break; -#endif - case Field.SHA1: - if (ItemType == ItemType.Disk) - fieldValue = (this as Disk).SHA1; - else if (ItemType == ItemType.Rom) - fieldValue = (this as Rom).SHA1; - break; - case Field.SHA256: - if (ItemType == ItemType.Disk) - fieldValue = (this as Disk).SHA256; - else if (ItemType == ItemType.Rom) - fieldValue = (this as Rom).SHA256; - break; - case Field.SHA384: - if (ItemType == ItemType.Disk) - fieldValue = (this as Disk).SHA384; - else if (ItemType == ItemType.Rom) - fieldValue = (this as Rom).SHA384; - break; - case Field.SHA512: - if (ItemType == ItemType.Disk) - fieldValue = (this as Disk).SHA512; - else if (ItemType == ItemType.Rom) - fieldValue = (this as Rom).SHA512; - break; - case Field.Merge: - if (ItemType == ItemType.Disk) - fieldValue = (this as Disk).MergeTag; - else if (ItemType == ItemType.Rom) - fieldValue = (this as Rom).MergeTag; - break; - case Field.Region: - if (ItemType == ItemType.Disk) - fieldValue = (this as Disk).Region; - else if (ItemType == ItemType.Release) - fieldValue = (this as Release).Region; - else if (ItemType == ItemType.Rom) - fieldValue = (this as Rom).Region; - break; - case Field.Index: - if (ItemType == ItemType.Disk) - fieldValue = (this as Disk).Index; - break; - case Field.Writable: - if (ItemType == ItemType.Disk) - fieldValue = (this as Disk).Writable?.ToString(); - break; - case Field.Optional: - if (ItemType == ItemType.Disk) - fieldValue = (this as Disk).Optional?.ToString(); - else if (ItemType == ItemType.Rom) - fieldValue = (this as Rom).Optional?.ToString(); - break; - case Field.Status: - if (ItemType == ItemType.Disk) - fieldValue = (this as Disk).ItemStatus.ToString(); - else if (ItemType == ItemType.Rom) - fieldValue = (this as Rom).ItemStatus.ToString(); - break; - - case Field.Language: - if (ItemType == ItemType.Release) - fieldValue = (this as Release).Language; - break; - case Field.Date: - if (ItemType == ItemType.Release) - fieldValue = (this as Release).Date; - else if (ItemType == ItemType.Rom) - fieldValue = (this as Rom).Date; - break; - - case Field.Bios: - if (ItemType == ItemType.Rom) - fieldValue = (this as Rom).Bios; - break; - case Field.Size: - if (ItemType == ItemType.Rom) - fieldValue = (this as Rom).Size.ToString(); - break; - case Field.CRC: - if (ItemType == ItemType.Rom) - fieldValue = (this as Rom).CRC; - break; - case Field.Offset: - if (ItemType == ItemType.Rom) - fieldValue = (this as Rom).Offset; - break; - case Field.Inverted: - if (ItemType == ItemType.Rom) - fieldValue = (this as Rom).Inverted?.ToString(); + fieldValue = MachineType.ToString(); break; case Field.NULL: @@ -949,10 +833,10 @@ namespace SabreTools.Library.DatItems { try { - if (this.Name == other.Name) - return this.Equals(other) ? 0 : 1; + if (Name == other.Name) + return Equals(other) ? 0 : 1; - return String.Compare(this.Name, other.Name); + return string.Compare(Name, other.Name); } catch { @@ -977,13 +861,13 @@ namespace SabreTools.Library.DatItems DupeType output = 0x00; // If we don't have a duplicate at all, return none - if (!this.Equals(lastItem)) + if (!Equals(lastItem)) return output; // If the duplicate is external already or should be, set it - if (lastItem.DupeType.HasFlag(DupeType.External) || lastItem.IndexId != this.IndexId) + if (lastItem.DupeType.HasFlag(DupeType.External) || lastItem.IndexId != IndexId) { - if (lastItem.MachineName == this.MachineName && lastItem.Name == this.Name) + if (lastItem.MachineName == MachineName && lastItem.Name == Name) output = DupeType.External | DupeType.All; else output = DupeType.External | DupeType.Hash; @@ -992,7 +876,7 @@ namespace SabreTools.Library.DatItems // Otherwise, it's considered an internal dupe else { - if (lastItem.MachineName == this.MachineName && lastItem.Name == this.Name) + if (lastItem.MachineName == MachineName && lastItem.Name == Name) output = DupeType.Internal | DupeType.All; else output = DupeType.Internal | DupeType.Hash; @@ -1012,7 +896,7 @@ namespace SabreTools.Library.DatItems /// True if the key should be lowercased (default), false otherwise /// True if games should only be compared on game and file name, false if system and source are counted /// String representing the key to be used for the DatItem - public string GetKey(BucketedBy bucketedBy, bool lower = true, bool norename = true) + public virtual string GetKey(BucketedBy bucketedBy, bool lower = true, bool norename = true) { // Set the output key as the default blank string string key = string.Empty; @@ -1021,16 +905,16 @@ namespace SabreTools.Library.DatItems switch (bucketedBy) { case BucketedBy.CRC: - key = (this.ItemType == ItemType.Rom ? ((Rom)this).CRC : Constants.CRCZero); + key = Constants.CRCZero; break; case BucketedBy.Game: key = (norename ? string.Empty - : this.IndexId.ToString().PadLeft(10, '0') + : IndexId.ToString().PadLeft(10, '0') + "-") - + (string.IsNullOrWhiteSpace(this.MachineName) + + (string.IsNullOrWhiteSpace(MachineName) ? "Default" - : this.MachineName); + : MachineName); if (lower) key = key.ToLowerInvariant(); @@ -1041,53 +925,29 @@ namespace SabreTools.Library.DatItems break; case BucketedBy.MD5: - key = (this.ItemType == ItemType.Rom - ? ((Rom)this).MD5 - : (this.ItemType == ItemType.Disk - ? ((Disk)this).MD5 - : Constants.MD5Zero)); + key = Constants.MD5Zero; break; #if NET_FRAMEWORK case BucketedBy.RIPEMD160: - key = (this.ItemType == ItemType.Rom - ? ((Rom)this).RIPEMD160 - : (this.ItemType == ItemType.Disk - ? ((Disk)this).RIPEMD160 - : Constants.RIPEMD160Zero)); + key = Constants.RIPEMD160Zero; break; #endif case BucketedBy.SHA1: - key = (this.ItemType == ItemType.Rom - ? ((Rom)this).SHA1 - : (this.ItemType == ItemType.Disk - ? ((Disk)this).SHA1 - : Constants.SHA1Zero)); + key = Constants.SHA1Zero; break; case BucketedBy.SHA256: - key = (this.ItemType == ItemType.Rom - ? ((Rom)this).SHA256 - : (this.ItemType == ItemType.Disk - ? ((Disk)this).SHA256 - : Constants.SHA256Zero)); + key = Constants.SHA256Zero; break; case BucketedBy.SHA384: - key = (this.ItemType == ItemType.Rom - ? ((Rom)this).SHA384 - : (this.ItemType == ItemType.Disk - ? ((Disk)this).SHA384 - : Constants.SHA384Zero)); + key = Constants.SHA384Zero; break; case BucketedBy.SHA512: - key = (this.ItemType == ItemType.Rom - ? ((Rom)this).SHA512 - : (this.ItemType == ItemType.Disk - ? ((Disk)this).SHA512 - : Constants.SHA512Zero)); + key = Constants.SHA512Zero; break; } @@ -1151,13 +1011,13 @@ namespace SabreTools.Library.DatItems continue; // If it's a nodump, add and skip - if (file.ItemType == ItemType.Rom && ((Rom)file).ItemStatus == ItemStatus.Nodump) + if (file.ItemType == ItemType.Rom && (file as Rom).ItemStatus == ItemStatus.Nodump) { outfiles.Add(file); nodumpCount++; continue; } - else if (file.ItemType == ItemType.Disk && ((Disk)file).ItemStatus == ItemStatus.Nodump) + else if (file.ItemType == ItemType.Disk && (file as Disk).ItemStatus == ItemStatus.Nodump) { outfiles.Add(file); nodumpCount++; @@ -1172,7 +1032,7 @@ namespace SabreTools.Library.DatItems // Check if the rom is a duplicate DupeType dupetype = 0x00; - DatItem saveditem = new Rom(); + DatItem saveditem = new Blank(); int pos = -1; for (int i = 0; i < outfiles.Count; i++) { @@ -1187,59 +1047,11 @@ namespace SabreTools.Library.DatItems saveditem = lastrom; pos = i; - // Roms have more infomration to save - if (file.ItemType == ItemType.Rom) - { - ((Rom)saveditem).Size = (((Rom)saveditem).Size == -1 && ((Rom)file).Size != -1 - ? ((Rom)file).Size - : ((Rom)saveditem).Size); - ((Rom)saveditem).CRC = (string.IsNullOrWhiteSpace(((Rom)saveditem).CRC) && !string.IsNullOrWhiteSpace(((Rom)file).CRC) - ? ((Rom)file).CRC - : ((Rom)saveditem).CRC); - ((Rom)saveditem).MD5 = (string.IsNullOrWhiteSpace(((Rom)saveditem).MD5) && !string.IsNullOrWhiteSpace(((Rom)file).MD5) - ? ((Rom)file).MD5 - : ((Rom)saveditem).MD5); -#if NET_FRAMEWORK - ((Rom)saveditem).RIPEMD160 = (string.IsNullOrWhiteSpace(((Rom)saveditem).RIPEMD160) && !string.IsNullOrWhiteSpace(((Rom)file).RIPEMD160) - ? ((Rom)file).RIPEMD160 - : ((Rom)saveditem).RIPEMD160); -#endif - ((Rom)saveditem).SHA1 = (string.IsNullOrWhiteSpace(((Rom)saveditem).SHA1) && !string.IsNullOrWhiteSpace(((Rom)file).SHA1) - ? ((Rom)file).SHA1 - : ((Rom)saveditem).SHA1); - ((Rom)saveditem).SHA256 = (string.IsNullOrWhiteSpace(((Rom)saveditem).SHA256) && !string.IsNullOrWhiteSpace(((Rom)file).SHA256) - ? ((Rom)file).SHA256 - : ((Rom)saveditem).SHA256); - ((Rom)saveditem).SHA384 = (string.IsNullOrWhiteSpace(((Rom)saveditem).SHA384) && !string.IsNullOrWhiteSpace(((Rom)file).SHA384) - ? ((Rom)file).SHA384 - : ((Rom)saveditem).SHA384); - ((Rom)saveditem).SHA512 = (string.IsNullOrWhiteSpace(((Rom)saveditem).SHA512) && !string.IsNullOrWhiteSpace(((Rom)file).SHA512) - ? ((Rom)file).SHA512 - : ((Rom)saveditem).SHA512); - } - else if (file.ItemType == ItemType.Disk) - { - ((Disk)saveditem).MD5 = (string.IsNullOrWhiteSpace(((Disk)saveditem).MD5) && !string.IsNullOrWhiteSpace(((Disk)file).MD5) - ? ((Disk)file).MD5 - : ((Disk)saveditem).MD5); -#if NET_FRAMEWORK - ((Disk)saveditem).RIPEMD160 = (string.IsNullOrWhiteSpace(((Disk)saveditem).RIPEMD160) && !string.IsNullOrWhiteSpace(((Disk)file).RIPEMD160) - ? ((Disk)file).RIPEMD160 - : ((Disk)saveditem).RIPEMD160); -#endif - ((Disk)saveditem).SHA1 = (string.IsNullOrWhiteSpace(((Disk)saveditem).SHA1) && !string.IsNullOrWhiteSpace(((Disk)file).SHA1) - ? ((Disk)file).SHA1 - : ((Disk)saveditem).SHA1); - ((Disk)saveditem).SHA256 = (string.IsNullOrWhiteSpace(((Disk)saveditem).SHA256) && !string.IsNullOrWhiteSpace(((Disk)file).SHA256) - ? ((Disk)file).SHA256 - : ((Disk)saveditem).SHA256); - ((Disk)saveditem).SHA384 = (string.IsNullOrWhiteSpace(((Disk)saveditem).SHA384) && !string.IsNullOrWhiteSpace(((Disk)file).SHA384) - ? ((Disk)file).SHA384 - : ((Disk)saveditem).SHA384); - ((Disk)saveditem).SHA512 = (string.IsNullOrWhiteSpace(((Disk)saveditem).SHA512) && !string.IsNullOrWhiteSpace(((Disk)file).SHA512) - ? ((Disk)file).SHA512 - : ((Disk)saveditem).SHA512); - } + // Disks and Roms have more information to fill + if (file.ItemType == ItemType.Disk) + (saveditem as Disk).FillMissingInformation(file as Disk); + else if (file.ItemType == ItemType.Rom) + (saveditem as Rom).FillMissingInformation(file as Rom); saveditem.DupeType = dupetype; @@ -1370,29 +1182,9 @@ namespace SabreTools.Library.DatItems private static string GetDuplicateSuffix(DatItem datItem) { if (datItem.ItemType == ItemType.Disk) - { - Disk disk = datItem as Disk; - - if (string.IsNullOrWhiteSpace(disk.MD5)) - return $"_{disk.MD5}"; - else if (string.IsNullOrWhiteSpace(disk.SHA1)) - return $"_{disk.SHA1}"; - else - return "_1"; - } + return (datItem as Disk).GetDuplicateSuffix(); else if (datItem.ItemType == ItemType.Rom) - { - Rom rom = datItem as Rom; - - if (string.IsNullOrWhiteSpace(rom.CRC)) - return $"_{rom.CRC}"; - else if (string.IsNullOrWhiteSpace(rom.MD5)) - return $"_{rom.MD5}"; - else if (string.IsNullOrWhiteSpace(rom.SHA1)) - return $"_{rom.SHA1}"; - else - return "_1"; - } + return (datItem as Rom).GetDuplicateSuffix(); return "_1"; } @@ -1414,31 +1206,22 @@ namespace SabreTools.Library.DatItems { if (x.MachineName == y.MachineName) { - if ((x.ItemType == ItemType.Rom || x.ItemType == ItemType.Disk) && (y.ItemType == ItemType.Rom || y.ItemType == ItemType.Disk)) + // Special case for comparing a Disk or Rom to another item type + if ((x.ItemType == ItemType.Disk || x.ItemType == ItemType.Rom) ^ (y.ItemType == ItemType.Disk || y.ItemType == ItemType.Rom)) { - if (Path.GetDirectoryName(Sanitizer.RemovePathUnsafeCharacters(x.Name)) == Path.GetDirectoryName(Sanitizer.RemovePathUnsafeCharacters(y.Name))) - { - return nc.Compare(Path.GetFileName(Sanitizer.RemovePathUnsafeCharacters(x.Name)), Path.GetFileName(Sanitizer.RemovePathUnsafeCharacters(y.Name))); - } + if (x.ItemType == ItemType.Disk || x.ItemType == ItemType.Rom) + return -1; + else + return 1; + } - return nc.Compare(Path.GetDirectoryName(Sanitizer.RemovePathUnsafeCharacters(x.Name)), Path.GetDirectoryName(Sanitizer.RemovePathUnsafeCharacters(y.Name))); - } - else if ((x.ItemType == ItemType.Rom || x.ItemType == ItemType.Disk) && (y.ItemType != ItemType.Rom && y.ItemType != ItemType.Disk)) - { - return -1; - } - else if ((x.ItemType != ItemType.Rom && x.ItemType != ItemType.Disk) && (y.ItemType == ItemType.Rom || y.ItemType == ItemType.Disk)) - { - return 1; - } + // Otherwise, we compare names naturally else { - if (Path.GetDirectoryName(x.Name) == Path.GetDirectoryName(y.Name)) - { - return nc.Compare(Path.GetFileName(x.Name), Path.GetFileName(y.Name)); - } + if (Path.GetDirectoryName(Sanitizer.RemovePathUnsafeCharacters(x.Name)) == Path.GetDirectoryName(Sanitizer.RemovePathUnsafeCharacters(y.Name))) + return nc.Compare(Path.GetFileName(Sanitizer.RemovePathUnsafeCharacters(x.Name)), Path.GetFileName(Sanitizer.RemovePathUnsafeCharacters(y.Name))); - return nc.Compare(Path.GetDirectoryName(x.Name), Path.GetDirectoryName(y.Name)); + return nc.Compare(Path.GetDirectoryName(Sanitizer.RemovePathUnsafeCharacters(x.Name)), Path.GetDirectoryName(Sanitizer.RemovePathUnsafeCharacters(y.Name))); } } diff --git a/SabreTools.Library/DatItems/Disk.cs b/SabreTools.Library/DatItems/Disk.cs index 45134063..2633b905 100644 --- a/SabreTools.Library/DatItems/Disk.cs +++ b/SabreTools.Library/DatItems/Disk.cs @@ -1,5 +1,5 @@ -using System.Linq; - +using System.Collections.Generic; +using SabreTools.Library.DatFiles; using SabreTools.Library.FileTypes; using SabreTools.Library.Tools; using Newtonsoft.Json; @@ -126,6 +126,74 @@ namespace SabreTools.Library.DatItems #endregion + #region Accessors + + /// + /// Get the value of that field as a string, if possible + /// + public override string GetField(Field field, List excludeFields) + { + // If the field is to be excluded, return empty string + if (excludeFields.Contains(field)) + return string.Empty; + + // Handle Disk-specific fields + string fieldValue; + switch (field) + { + case Field.MD5: + fieldValue = MD5; + break; +#if NET_FRAMEWORK + case Field.RIPEMD160: + fieldValue = RIPEMD160; + break; +#endif + case Field.SHA1: + fieldValue = SHA1; + break; + case Field.SHA256: + fieldValue = SHA256; + break; + case Field.SHA384: + fieldValue = SHA384; + break; + case Field.SHA512: + fieldValue = SHA512; + break; + case Field.Merge: + fieldValue = MergeTag; + break; + case Field.Region: + fieldValue = Region; + break; + case Field.Index: + fieldValue = Index; + break; + case Field.Writable: + fieldValue = Writable?.ToString(); + break; + case Field.Optional: + fieldValue = Optional?.ToString(); + break; + case Field.Status: + fieldValue = ItemStatus.ToString(); + break; + + // For everything else, use the base method + default: + return base.GetField(field, excludeFields); + } + + // Make sure we don't return null + if (string.IsNullOrEmpty(fieldValue)) + fieldValue = string.Empty; + + return fieldValue; + } + + #endregion + #region Constructors /// @@ -305,6 +373,53 @@ namespace SabreTools.Library.DatItems return dupefound; } + /// + /// Fill any missing size and hash information from another Disk + /// + /// Disk to fill information from + public void FillMissingInformation(Disk other) + { + if (_md5.IsNullOrEmpty() && !other._md5.IsNullOrEmpty()) + _md5 = other._md5; + +#if NET_FRAMEWORK + if (_ripemd160.IsNullOrEmpty() && !other._ripemd160.IsNullOrEmpty()) + _ripemd160 = other._ripemd160; +#endif + + if (_sha1.IsNullOrEmpty() && !other._sha1.IsNullOrEmpty()) + _sha1 = other._sha1; + + if (_sha256.IsNullOrEmpty() && !other._sha256.IsNullOrEmpty()) + _sha256 = other._sha256; + + if (_sha384.IsNullOrEmpty() && !other._sha384.IsNullOrEmpty()) + _sha384 = other._sha384; + + if (_sha512.IsNullOrEmpty() && !other._sha512.IsNullOrEmpty()) + _sha512 = other._sha512; + } + + /// + /// Get unique duplicate suffix on name collision + /// + /// String representing the suffix + public string GetDuplicateSuffix() + { + if (!_md5.IsNullOrEmpty()) + return $"_{MD5}"; + else if (!_sha1.IsNullOrEmpty()) + return $"_{SHA1}"; + else if (!_sha256.IsNullOrEmpty()) + return $"_{SHA256}"; + else if (!_sha384.IsNullOrEmpty()) + return $"_{SHA384}"; + else if (!_sha512.IsNullOrEmpty()) + return $"_{SHA512}"; + else + return "_1"; + } + /// /// Returns if there are no, non-empty hashes in common with another Disk /// @@ -365,5 +480,62 @@ namespace SabreTools.Library.DatItems } #endregion + + #region Sorting and Merging + + /// + /// Get the dictionary key that should be used for a given item and bucketing type + /// + /// BucketedBy enum representing what key to get + /// True if the key should be lowercased (default), false otherwise + /// True if games should only be compared on game and file name, false if system and source are counted + /// String representing the key to be used for the DatItem + public override string GetKey(BucketedBy bucketedBy, bool lower = true, bool norename = true) + { + // Set the output key as the default blank string + string key = string.Empty; + + // Now determine what the key should be based on the bucketedBy value + switch (bucketedBy) + { + case BucketedBy.MD5: + key = MD5; + break; + +#if NET_FRAMEWORK + case BucketedBy.RIPEMD160: + key = RIPEMD160; + break; +#endif + + case BucketedBy.SHA1: + key = SHA1; + break; + + case BucketedBy.SHA256: + key = SHA256; + break; + + case BucketedBy.SHA384: + key = SHA384; + break; + + case BucketedBy.SHA512: + key = SHA512; + break; + + // Let the base handle generic stuff + default: + return base.GetKey(bucketedBy, lower, norename); + } + + // Double and triple check the key for corner cases + if (key == null) + key = string.Empty; + + return key; + } + + #endregion } } diff --git a/SabreTools.Library/DatItems/Release.cs b/SabreTools.Library/DatItems/Release.cs index fb848720..98650736 100644 --- a/SabreTools.Library/DatItems/Release.cs +++ b/SabreTools.Library/DatItems/Release.cs @@ -1,4 +1,4 @@ -using SabreTools.Library.Data; +using System.Collections.Generic; using Newtonsoft.Json; namespace SabreTools.Library.DatItems @@ -36,6 +36,48 @@ namespace SabreTools.Library.DatItems #endregion + #region Accessors + + /// + /// Get the value of that field as a string, if possible + /// + public override string GetField(Field field, List excludeFields) + { + // If the field is to be excluded, return empty string + if (excludeFields.Contains(field)) + return string.Empty; + + // Handle Release-specific fields + string fieldValue; + switch (field) + { + case Field.Region: + fieldValue = Region; + break; + case Field.Language: + fieldValue = Language; + break; + case Field.Date: + fieldValue = Date; + break; + case Field.Default: + fieldValue = Default?.ToString(); + break; + + // For everything else, use the base method + default: + return base.GetField(field, excludeFields); + } + + // Make sure we don't return null + if (string.IsNullOrEmpty(fieldValue)) + fieldValue = string.Empty; + + return fieldValue; + } + + #endregion + #region Constructors /// diff --git a/SabreTools.Library/DatItems/Rom.cs b/SabreTools.Library/DatItems/Rom.cs index a055ba12..bf345906 100644 --- a/SabreTools.Library/DatItems/Rom.cs +++ b/SabreTools.Library/DatItems/Rom.cs @@ -1,6 +1,6 @@ -using System.Linq; - +using System.Collections.Generic; using SabreTools.Library.Data; +using SabreTools.Library.DatFiles; using SabreTools.Library.FileTypes; using SabreTools.Library.Tools; using Newtonsoft.Json; @@ -156,6 +156,86 @@ namespace SabreTools.Library.DatItems #endregion + #region Accessors + + /// + /// Get the value of that field as a string, if possible + /// + public override string GetField(Field field, List excludeFields) + { + // If the field is to be excluded, return empty string + if (excludeFields.Contains(field)) + return string.Empty; + + // Handle Rom-specific fields + string fieldValue; + switch (field) + { + case Field.Bios: + fieldValue = Bios; + break; + case Field.Size: + fieldValue = Size.ToString(); + break; + case Field.CRC: + fieldValue = CRC; + break; + case Field.MD5: + fieldValue = MD5; + break; +#if NET_FRAMEWORK + case Field.RIPEMD160: + fieldValue = RIPEMD160; + break; +#endif + case Field.SHA1: + fieldValue = SHA1; + break; + case Field.SHA256: + fieldValue = SHA256; + break; + case Field.SHA384: + fieldValue = SHA384; + break; + case Field.SHA512: + fieldValue = SHA512; + break; + case Field.Merge: + fieldValue = MergeTag; + break; + case Field.Region: + fieldValue = Region; + break; + case Field.Offset: + fieldValue = Offset; + break; + case Field.Date: + fieldValue = Date; + break; + case Field.Status: + fieldValue = ItemStatus.ToString(); + break; + case Field.Optional: + fieldValue = Optional?.ToString(); + break; + case Field.Inverted: + fieldValue = Inverted?.ToString(); + break; + + // For everything else, use the base method + default: + return base.GetField(field, excludeFields); + } + + // Make sure we don't return null + if (string.IsNullOrEmpty(fieldValue)) + fieldValue = string.Empty; + + return fieldValue; + } + + #endregion + #region Constructors /// @@ -307,6 +387,61 @@ namespace SabreTools.Library.DatItems return dupefound; } + /// + /// Fill any missing size and hash information from another Rom + /// + /// Rom to fill information from + public void FillMissingInformation(Rom other) + { + if (Size == -1 && other.Size != -1) + Size = other.Size; + + if (_crc.IsNullOrEmpty() && !other._crc.IsNullOrEmpty()) + _crc = other._crc; + + if (_md5.IsNullOrEmpty() && !other._md5.IsNullOrEmpty()) + _md5 = other._md5; + +#if NET_FRAMEWORK + if (_ripemd160.IsNullOrEmpty() && !other._ripemd160.IsNullOrEmpty()) + _ripemd160 = other._ripemd160; +#endif + + if (_sha1.IsNullOrEmpty() && !other._sha1.IsNullOrEmpty()) + _sha1 = other._sha1; + + if (_sha256.IsNullOrEmpty() && !other._sha256.IsNullOrEmpty()) + _sha256 = other._sha256; + + if (_sha384.IsNullOrEmpty() && !other._sha384.IsNullOrEmpty()) + _sha384 = other._sha384; + + if (_sha512.IsNullOrEmpty() && !other._sha512.IsNullOrEmpty()) + _sha512 = other._sha512; + } + + /// + /// Get unique duplicate suffix on name collision + /// + /// String representing the suffix + public string GetDuplicateSuffix() + { + if (!_crc.IsNullOrEmpty()) + return $"_{CRC}"; + else if (!_md5.IsNullOrEmpty()) + return $"_{MD5}"; + else if (!_sha1.IsNullOrEmpty()) + return $"_{SHA1}"; + else if (!_sha256.IsNullOrEmpty()) + return $"_{SHA256}"; + else if (!_sha384.IsNullOrEmpty()) + return $"_{SHA384}"; + else if (!_sha512.IsNullOrEmpty()) + return $"_{SHA512}"; + else + return "_1"; + } + /// /// Returns if there are no, non-empty hashes in common with another Rom /// @@ -370,5 +505,66 @@ namespace SabreTools.Library.DatItems } #endregion + + #region Sorting and Merging + + /// + /// Get the dictionary key that should be used for a given item and bucketing type + /// + /// BucketedBy enum representing what key to get + /// True if the key should be lowercased (default), false otherwise + /// True if games should only be compared on game and file name, false if system and source are counted + /// String representing the key to be used for the DatItem + public override string GetKey(BucketedBy bucketedBy, bool lower = true, bool norename = true) + { + // Set the output key as the default blank string + string key = string.Empty; + + // Now determine what the key should be based on the bucketedBy value + switch (bucketedBy) + { + case BucketedBy.CRC: + key = CRC; + break; + + case BucketedBy.MD5: + key = MD5; + break; + +#if NET_FRAMEWORK + case BucketedBy.RIPEMD160: + key = RIPEMD160; + break; +#endif + + case BucketedBy.SHA1: + key = SHA1; + break; + + case BucketedBy.SHA256: + key = SHA256; + break; + + case BucketedBy.SHA384: + key = SHA384; + break; + + case BucketedBy.SHA512: + key = SHA512; + break; + + // Let the base handle generic stuff + default: + return base.GetKey(bucketedBy, lower, norename); + } + + // Double and triple check the key for corner cases + if (key == null) + key = string.Empty; + + return key; + } + + #endregion } } diff --git a/SabreTools.Library/DatItems/Sample.cs b/SabreTools.Library/DatItems/Sample.cs index ad036ad7..e15d3d73 100644 --- a/SabreTools.Library/DatItems/Sample.cs +++ b/SabreTools.Library/DatItems/Sample.cs @@ -1,6 +1,4 @@ -using SabreTools.Library.Data; - -namespace SabreTools.Library.DatItems +namespace SabreTools.Library.DatItems { /// /// Represents a (usually WAV-formatted) sample to be included for use in the set