diff --git a/SabreTools.Helper/Data/Constants.cs b/SabreTools.Helper/Data/Constants.cs index 179695e4..bad9b588 100644 --- a/SabreTools.Helper/Data/Constants.cs +++ b/SabreTools.Helper/Data/Constants.cs @@ -19,6 +19,9 @@ namespace SabreTools.Helper.Data public const string CRCZero = "00000000"; public const string MD5Zero = "d41d8cd98f00b204e9800998ecf8427e"; public const string SHA1Zero = "da39a3ee5e6b4b0d3255bfef95601890afd80709"; + public const string SHA256Zero = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"; + public const string SHA384Zero = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"; + public const string SHA512Zero = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; #endregion @@ -61,6 +64,9 @@ namespace SabreTools.Helper.Data public const int CRCLength = 8; public const int MD5Length = 32; public const int SHA1Length = 40; + public const int SHA256Length = 64; + public const int SHA384Length = 96; + public const int SHA512Length = 128; #endregion diff --git a/SabreTools.Helper/Data/Enums.cs b/SabreTools.Helper/Data/Enums.cs index 9e203426..d54b1fc2 100644 --- a/SabreTools.Helper/Data/Enums.cs +++ b/SabreTools.Helper/Data/Enums.cs @@ -253,6 +253,7 @@ CRC, MD5, SHA1, + SHA256, Game, } diff --git a/SabreTools.Helper/Data/Flags.cs b/SabreTools.Helper/Data/Flags.cs index f607a8d8..0a803e33 100644 --- a/SabreTools.Helper/Data/Flags.cs +++ b/SabreTools.Helper/Data/Flags.cs @@ -223,6 +223,7 @@ namespace SabreTools.Helper.Data TSV = 0x0800, CSV = 0x1000, AttractMode = 0x2000, + RedumpSHA256 = 0x4000, ALL = 0xFFFF, } diff --git a/SabreTools.Helper/Dats/DatFile.cs b/SabreTools.Helper/Dats/DatFile.cs index 41a583c3..d6962cf2 100644 --- a/SabreTools.Helper/Dats/DatFile.cs +++ b/SabreTools.Helper/Dats/DatFile.cs @@ -51,6 +51,7 @@ namespace SabreTools.Helper.Dats private long _crcCount; private long _md5Count; private long _sha1Count; + private long _sha256Count; private long _baddumpCount; private long _nodumpCount; @@ -243,6 +244,11 @@ namespace SabreTools.Helper.Dats get { return _sha1Count; } set { _sha1Count = value; } } + public long _sha256Count + { + get { return _sha256Count; } + set { _sha256Count = value; } + } public long BaddumpCount { get { return _baddumpCount; } diff --git a/SabreTools.Helper/Dats/Disk.cs b/SabreTools.Helper/Dats/Disk.cs index 4343c8e4..5f8b8309 100644 --- a/SabreTools.Helper/Dats/Disk.cs +++ b/SabreTools.Helper/Dats/Disk.cs @@ -11,6 +11,7 @@ namespace SabreTools.Helper.Dats // Disk information protected string _md5; protected string _sha1; + protected string _sha256; protected ItemStatus _itemStatus; #endregion @@ -28,6 +29,11 @@ namespace SabreTools.Helper.Dats get { return _sha1; } set { _sha1 = value; } } + public string SHA256 + { + get { return _sha256; } + set { _sha256 = value; } + } public ItemStatus ItemStatus { get { return _itemStatus; } @@ -79,6 +85,7 @@ namespace SabreTools.Helper.Dats MD5 = this.MD5, SHA1 = this.SHA1, + SHA256 = this.SHA256, ItemStatus = this.ItemStatus, }; } @@ -106,8 +113,9 @@ namespace SabreTools.Helper.Dats return dupefound; } - if (((String.IsNullOrEmpty(_md5) || String.IsNullOrEmpty(newOther.MD5)) || this.MD5 == newOther.MD5) && - ((String.IsNullOrEmpty(this.SHA1) || String.IsNullOrEmpty(newOther.SHA1)) || this.SHA1 == newOther.SHA1)) + if (((String.IsNullOrEmpty(_md5) || String.IsNullOrEmpty(newOther.MD5)) || this.MD5 == newOther.MD5) + && ((String.IsNullOrEmpty(this.SHA1) || String.IsNullOrEmpty(newOther.SHA1)) || this.SHA1 == newOther.SHA1) + && ((String.IsNullOrEmpty(this.SHA256) || String.IsNullOrEmpty(newOther.SHA256)) || this.SHA256 == newOther.SHA256)) { dupefound = true; } diff --git a/SabreTools.Helper/Dats/Filter.cs b/SabreTools.Helper/Dats/Filter.cs index 385e5cfb..84f11a76 100644 --- a/SabreTools.Helper/Dats/Filter.cs +++ b/SabreTools.Helper/Dats/Filter.cs @@ -18,6 +18,7 @@ namespace SabreTools.Helper.Dats private List _crcs; private List _md5s; private List _sha1s; + private List _sha256s; private ItemStatus _itemStatuses; private MachineType _machineTypes; @@ -31,6 +32,7 @@ namespace SabreTools.Helper.Dats private List _notCrcs; private List _notMd5s; private List _notSha1s; + private List _notSha256s private ItemStatus _itemNotStatuses; private MachineType _machineNotTypes; @@ -82,6 +84,11 @@ namespace SabreTools.Helper.Dats get { return _sha1s; } set { _sha1s = value; } } + public List SHA256s + { + get { return _sha256s; } + set { _sha256s = value; } + } public ItemStatus ItemStatuses { get { return _itemStatuses; } @@ -127,6 +134,11 @@ namespace SabreTools.Helper.Dats get { return _notSha1s; } set { _notSha1s = value; } } + public List NotSHA256s + { + get { return _notSha256s; } + set { _notSha256s = value; } + } public ItemStatus NotItemStatuses { get { return _itemNotStatuses; } @@ -186,6 +198,7 @@ namespace SabreTools.Helper.Dats _crcs = new List(); _md5s = new List(); _sha1s = new List(); + _sha256s = new List(); _itemStatuses = ItemStatus.NULL; _machineTypes = MachineType.NULL; @@ -196,6 +209,7 @@ namespace SabreTools.Helper.Dats _notCrcs = new List(); _notMd5s = new List(); _notSha1s = new List(); + _notSha256s = new List(); _itemNotStatuses = ItemStatus.NULL; _machineNotTypes = MachineType.NULL; @@ -332,6 +346,24 @@ namespace SabreTools.Helper.Dats return false; } } + + // Filter on SHA256 + if (_sha256s.Count > 0) + { + // If the SHA-1 isn't in the list, return false + if (!FindValueInList(_sha256s, rom.SHA256)) + { + return false; + } + } + if (_notSha256s.Count > 0) + { + // If the SHA-1 is in the list, return false + if (FindValueInList(_notSha256s, rom.SHA256)) + { + return false; + } + } } else if (item.Type == ItemType.Disk) { @@ -382,6 +414,24 @@ namespace SabreTools.Helper.Dats return false; } } + + // Filter on SHA256 + if (_sha256s.Count > 0) + { + // If the SHA-1 isn't in the list, return false + if (!FindValueInList(_sha256s, rom.SHA256)) + { + return false; + } + } + if (_notSha256s.Count > 0) + { + // If the SHA-1 is in the list, return false + if (FindValueInList(_notSha256s, rom.SHA256)) + { + return false; + } + } } // Filter on game name diff --git a/SabreTools.Helper/Dats/Partials/DatFile.Bucketing.cs b/SabreTools.Helper/Dats/Partials/DatFile.Bucketing.cs index acf0e517..d9be01f4 100644 --- a/SabreTools.Helper/Dats/Partials/DatFile.Bucketing.cs +++ b/SabreTools.Helper/Dats/Partials/DatFile.Bucketing.cs @@ -275,7 +275,78 @@ namespace SabreTools.Helper.Dats ? ((Rom)rom).SHA1 : (rom.Type == ItemType.Disk ? ((Disk)rom).SHA1 - : Constants.MD5Zero)); + : Constants.SHA1Zero)); + + if (!sortable.ContainsKey(newkey)) + { + sortable.Add(newkey, new List()); + } + sortable[newkey].Add(rom); + } + } + + // Now go through and sort all of the lists + keys = sortable.Keys.ToList(); + foreach (string key in keys) + { + List sortedlist = sortable[key]; + DatItem.Sort(ref sortedlist, false); + sortable[key] = sortedlist; + } + + // Output the count if told to + if (output) + { + logger.User("A total of " + count + " file hashes will be written out to file"); + } + + // Now assign the dictionary back + _files = sortable; + } + + /// + /// Take the arbitrarily sorted Files Dictionary and convert to one sorted by SHA256 + /// + /// True if roms should be deduped, false otherwise + /// Logger object for file and console output + /// True if the number of hashes counted is to be output (default), false otherwise + public void BucketBySHA256(bool mergeroms, Logger logger, bool output = true) + { + // If we already have the right sorting, trust it + if (_sortedBy == SortedBy.SHA256) + { + return; + } + + // Set the sorted type + _sortedBy = SortedBy.SHA256; + + SortedDictionary> sortable = new SortedDictionary>(); + long count = 0; + + logger.User("Organizing " + (mergeroms ? "and merging " : "") + "roms by SHA-256"); + + // Process each all of the roms + List keys = Keys.ToList(); + foreach (string key in keys) + { + List roms = this[key]; + + // If we're merging the roms, do so + if (mergeroms) + { + roms = DatItem.Merge(roms, logger); + } + + // Now add each of the roms to their respective games + foreach (DatItem rom in roms) + { + count++; + string newkey = (rom.Type == ItemType.Rom + ? ((Rom)rom).SHA256 + : (rom.Type == ItemType.Disk + ? ((Disk)rom).SHA256 + : Constants.SHA256Zero)); if (!sortable.ContainsKey(newkey)) { diff --git a/SabreTools.Helper/Dats/Partials/DatFile.DFD.cs b/SabreTools.Helper/Dats/Partials/DatFile.DFD.cs index 6082b698..3c7f65d5 100644 --- a/SabreTools.Helper/Dats/Partials/DatFile.DFD.cs +++ b/SabreTools.Helper/Dats/Partials/DatFile.DFD.cs @@ -28,6 +28,7 @@ namespace SabreTools.Helper.Dats /// Base folder to be used in creating the DAT /// True if MD5 hashes should be skipped over, false otherwise /// True if SHA-1 hashes should be skipped over, false otherwise + /// True if SHA-256 hashes should be skipped over, false otherwise /// True if the date should be omitted from the DAT, false otherwise /// True if archives should be treated as files, false otherwise /// True if GZIP archives should be treated as files, false otherwise @@ -39,7 +40,7 @@ namespace SabreTools.Helper.Dats /// Populated string representing the name of the skipper to use, a blank string to use the first available checker, null otherwise /// Integer representing the maximum amount of parallelization to be used /// Logger object for console and file output - public bool PopulateFromDir(string basePath, bool noMD5, bool noSHA1, bool bare, bool archivesAsFiles, + public bool PopulateFromDir(string basePath, bool noMD5, bool noSHA1, bool noSHA256, bool bare, bool archivesAsFiles, bool enableGzip, bool addBlanks, bool addDate, string tempDir, bool copyFiles, string headerToCheckAgainst, int maxDegreeOfParallelism, Logger logger) { @@ -73,7 +74,7 @@ namespace SabreTools.Helper.Dats new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism }, item => { - PopulateFromDirCheckFile(item, basePath, noMD5, noSHA1, bare, archivesAsFiles, enableGzip, addBlanks, addDate, + PopulateFromDirCheckFile(item, basePath, noMD5, noSHA1, noSHA256, bare, archivesAsFiles, enableGzip, addBlanks, addDate, tempDir, copyFiles, headerToCheckAgainst, maxDegreeOfParallelism, logger); }); @@ -88,7 +89,7 @@ namespace SabreTools.Helper.Dats new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism }, subitem => { - PopulateFromDirCheckFile(subitem, basePath, noMD5, noSHA1, bare, archivesAsFiles, enableGzip, addBlanks, addDate, + PopulateFromDirCheckFile(subitem, basePath, noMD5, noSHA1, noSHA256, bare, archivesAsFiles, enableGzip, addBlanks, addDate, tempDir, copyFiles, headerToCheckAgainst, maxDegreeOfParallelism, logger); }); }); @@ -150,7 +151,7 @@ namespace SabreTools.Helper.Dats } else if (File.Exists(basePath)) { - PopulateFromDirCheckFile(basePath, Path.GetDirectoryName(Path.GetDirectoryName(basePath)), noMD5, noSHA1, bare, archivesAsFiles, enableGzip, addBlanks, addDate, + PopulateFromDirCheckFile(basePath, Path.GetDirectoryName(Path.GetDirectoryName(basePath)), noMD5, noSHA1, noSHA256, bare, archivesAsFiles, enableGzip, addBlanks, addDate, tempDir, copyFiles, headerToCheckAgainst, maxDegreeOfParallelism, logger); } @@ -178,6 +179,7 @@ namespace SabreTools.Helper.Dats /// Base folder to be used in creating the DAT /// True if MD5 hashes should be skipped over, false otherwise /// True if SHA-1 hashes should be skipped over, false otherwise + /// True if SHA-256 hashes should be skipped over, false otherwise /// True if the date should be omitted from the DAT, false otherwise /// True if archives should be treated as files, false otherwise /// True if GZIP archives should be treated as files, false otherwise @@ -188,7 +190,7 @@ namespace SabreTools.Helper.Dats /// Populated string representing the name of the skipper to use, a blank string to use the first available checker, null otherwise /// Integer representing the maximum amount of parallelization to be used /// Logger object for console and file output - private void PopulateFromDirCheckFile(string item, string basePath, bool noMD5, bool noSHA1, bool bare, bool archivesAsFiles, + private void PopulateFromDirCheckFile(string item, string basePath, bool noMD5, bool noSHA1, bool noSHA256, bool bare, bool archivesAsFiles, bool enableGzip, bool addBlanks, bool addDate, string tempDir, bool copyFiles, string headerToCheckAgainst, int maxDegreeOfParallelism, Logger logger) { @@ -227,8 +229,8 @@ namespace SabreTools.Helper.Dats File.Copy(item, newItem, true); } - // If both deep hash skip flags are set, do a quickscan - if (noMD5 && noSHA1) + // If all deep hash skip flags are set, do a quickscan + if (noMD5 && noSHA1 && noSHA256) { ArchiveType? type = ArchiveTools.GetCurrentArchiveType(newItem, logger); @@ -249,7 +251,7 @@ namespace SabreTools.Helper.Dats // Otherwise, just get the info on the file itself else if (File.Exists(newItem)) { - PopulateFromDirProcessFile(newItem, "", newBasePath, noMD5, noSHA1, addDate, headerToCheckAgainst, logger); + PopulateFromDirProcessFile(newItem, "", newBasePath, noMD5, noSHA1, noSHA256, addDate, headerToCheckAgainst, logger); } } // Otherwise, attempt to extract the files to the temporary directory @@ -279,6 +281,7 @@ namespace SabreTools.Helper.Dats tempSubDir, noMD5, noSHA1, + noSHA256, addDate, headerToCheckAgainst, logger); @@ -287,7 +290,7 @@ namespace SabreTools.Helper.Dats // Otherwise, just get the info on the file itself else if (File.Exists(newItem)) { - PopulateFromDirProcessFile(newItem, "", newBasePath, noMD5, noSHA1, addDate, headerToCheckAgainst, logger); + PopulateFromDirProcessFile(newItem, "", newBasePath, noMD5, noSHA1, noSHA256, addDate, headerToCheckAgainst, logger); } } @@ -316,13 +319,15 @@ namespace SabreTools.Helper.Dats /// Path the represents the parent directory /// True if MD5 hashes should be skipped over, false otherwise /// True if SHA-1 hashes should be skipped over, false otherwise + /// True if SHA-256 hashes should be skipped over, false otherwise /// True if dates should be archived for all files, false otherwise /// Populated string representing the name of the skipper to use, a blank string to use the first available checker, null otherwise /// Logger object for console and file output - private void PopulateFromDirProcessFile(string item, string parent, string basePath, bool noMD5, bool noSHA1, bool addDate, string headerToCheckAgainst, Logger logger) + private void PopulateFromDirProcessFile(string item, string parent, string basePath, bool noMD5, bool noSHA1, + bool noSHA256, bool addDate, string headerToCheckAgainst, Logger logger) { logger.Verbose(Path.GetFileName(item) + " treated like a file"); - Rom rom = FileTools.GetFileInfo(item, logger, noMD5: noMD5, noSHA1: noSHA1, date: addDate, header: headerToCheckAgainst); + Rom rom = FileTools.GetFileInfo(item, logger, noMD5: noMD5, noSHA1: noSHA1, noSHA256: noSHA256, date: addDate, header: headerToCheckAgainst); PopulateFromDirProcessFileHelper(item, rom, basePath, parent, logger); } diff --git a/SabreTools.Helper/Dats/Partials/DatFile.Parsers.cs b/SabreTools.Helper/Dats/Partials/DatFile.Parsers.cs index c97597d5..0dcd9e36 100644 --- a/SabreTools.Helper/Dats/Partials/DatFile.Parsers.cs +++ b/SabreTools.Helper/Dats/Partials/DatFile.Parsers.cs @@ -88,7 +88,7 @@ namespace SabreTools.Helper.Dats { ext = ext.Substring(1); } - if (ext != "dat" && ext != "md5" && ext != "sfv" && ext != "sha1" && ext != "txt" && ext != "xml") + if (ext != "dat" && ext != "md5" && ext != "sfv" && ext != "sha1" && ext != "sha256" && ext != "txt" && ext != "xml") { return; } @@ -124,6 +124,9 @@ namespace SabreTools.Helper.Dats case DatFormat.RedumpSHA1: ParseRedumpSHA1(filename, sysid, srcid, filter, trim, single, root, logger, clean); break; + case DatFormat.RedumpSHA256: + ParseRedumpSHA256(filename, sysid, srcid, filter, trim, single, root, logger, clean); + break; case DatFormat.RomCenter: ParseRC(filename, sysid, srcid, filter, trim, single, root, logger, clean); break; @@ -459,6 +462,27 @@ namespace SabreTools.Helper.Dats i++; ((Rom)item).CRC = gc[i].Replace("\"", "").ToLowerInvariant(); } + + // Get the MD5 from the next part + else if (gc[i] == "md5") + { + i++; + ((Rom)item).MD5 = gc[i].Replace("\"", "").ToLowerInvariant(); + } + + // Get the SHA1 from the next part + else if (gc[i] == "sha1") + { + i++; + ((Rom)item).SHA1 = gc[i].Replace("\"", "").ToLowerInvariant(); + } + + // Get the SHA256 from the next part + else if (gc[i] == "sha256") + { + i++; + ((Rom)item).SHA256 = gc[i].Replace("\"", "").ToLowerInvariant(); + } } // Now process and add the rom @@ -575,6 +599,20 @@ namespace SabreTools.Helper.Dats ((Disk)item).SHA1 = quoteless.ToLowerInvariant(); } break; + case "sha256": + if (item.Type == ItemType.Rom) + { + i++; + quoteless = gc[i].Replace("\"", ""); + ((Rom)item).SHA256 = quoteless.ToLowerInvariant(); + } + else if (item.Type == ItemType.Disk) + { + i++; + quoteless = gc[i].Replace("\"", ""); + ((Disk)item).SHA256 = quoteless.ToLowerInvariant(); + } + break; case "status": case "flags": i++; @@ -1712,6 +1750,7 @@ namespace SabreTools.Helper.Dats Name = subreader.GetAttribute("name"), MD5 = subreader.GetAttribute("md5")?.ToLowerInvariant(), SHA1 = subreader.GetAttribute("sha1")?.ToLowerInvariant(), + SHA256 = subreader.GetAttribute("sha256")?.ToLowerInvariant(), MergeTag = merge, ItemStatus = its, @@ -1740,6 +1779,7 @@ namespace SabreTools.Helper.Dats CRC = subreader.GetAttribute("crc"), MD5 = subreader.GetAttribute("md5")?.ToLowerInvariant(), SHA1 = subreader.GetAttribute("sha1")?.ToLowerInvariant(), + SHA256 = subreader.GetAttribute("sha256")?.ToLowerInvariant(), ItemStatus = its, MergeTag = merge, Date = date, @@ -1905,6 +1945,7 @@ namespace SabreTools.Helper.Dats Name = xtr.GetAttribute("name"), MD5 = xtr.GetAttribute("md5")?.ToLowerInvariant(), SHA1 = xtr.GetAttribute("sha1")?.ToLowerInvariant(), + SHA256 = xtr.GetAttribute("sha256")?.ToLowerInvariant(), ItemStatus = its, Machine = dir, @@ -1923,6 +1964,7 @@ namespace SabreTools.Helper.Dats CRC = xtr.GetAttribute("crc")?.ToLowerInvariant(), MD5 = xtr.GetAttribute("md5")?.ToLowerInvariant(), SHA1 = xtr.GetAttribute("sha1")?.ToLowerInvariant(), + SHA256 = xtr.GetAttribute("sha256")?.ToLowerInvariant(), ItemStatus = its, Date = date, @@ -2143,6 +2185,68 @@ namespace SabreTools.Helper.Dats sr.Dispose(); } + /// + /// Parse a Redump SHA-256 and return all found games and roms within + /// + /// Name of the file to be parsed + /// System ID for the DAT + /// Source ID for the DAT + /// Filter object for passing to the DatItem level + /// True if we are supposed to trim names to NTFS length, false otherwise + /// True if all games should be replaced by '!', false otherwise + /// String representing root directory to compare against for length calculation + /// Logger object for console and/or file output + /// True if game names are sanitized, false otherwise (default) + private void ParseRedumpSHA256( + // Standard Dat parsing + string filename, + int sysid, + int srcid, + + // Rom filtering + Filter filter, + + // Rom renaming + bool trim, + bool single, + string root, + + // Miscellaneous + Logger logger, + bool clean) + { + // Open a file reader + Encoding enc = Style.GetEncoding(filename); + StreamReader sr = new StreamReader(File.OpenRead(filename), enc); + + while (!sr.EndOfStream) + { + string line = sr.ReadLine(); + + Rom rom = new Rom + { + Name = line.Split(' ')[1].Replace("*", String.Empty), + Size = -1, + SHA256 = line.Split(' ')[0], + ItemStatus = ItemStatus.None, + + Machine = new Machine + { + Name = Path.GetFileNameWithoutExtension(filename), + }, + + SystemID = sysid, + SourceID = srcid, + }; + + // Now process and add the rom + string key = ""; + ParseAddHelper(rom, filter, trim, single, root, clean, logger, out key); + } + + sr.Dispose(); + } + /// /// Parse a RomCenter DAT and return all found games and roms within /// @@ -2353,17 +2457,20 @@ namespace SabreTools.Helper.Dats itemRom.CRC = Style.CleanHashData(itemRom.CRC, Constants.CRCLength); itemRom.MD5 = Style.CleanHashData(itemRom.MD5, Constants.MD5Length); itemRom.SHA1 = Style.CleanHashData(itemRom.SHA1, Constants.SHA1Length); + itemRom.SHA256 = Style.CleanHashData(itemRom.SHA256, Constants.SHA256Length); // If we have a rom and it's missing size AND the hashes match a 0-byte file, fill in the rest of the info if ((itemRom.Size == 0 || itemRom.Size == -1) && ((itemRom.CRC == Constants.CRCZero || String.IsNullOrEmpty(itemRom.CRC)) || itemRom.MD5 == Constants.MD5Zero - || itemRom.SHA1 == Constants.SHA1Zero)) + || itemRom.SHA1 == Constants.SHA1Zero + || itemRom.SHA256 == Constants.SHA256Zero)) { itemRom.Size = Constants.SizeZero; itemRom.CRC = Constants.CRCZero; itemRom.MD5 = Constants.MD5Zero; itemRom.SHA1 = Constants.SHA1Zero; + itemRom.SHA256 = Constants.SHA256Zero; } // If the file has no size and it's not the above case, skip and log else if (itemRom.ItemStatus != ItemStatus.Nodump && (itemRom.Size == 0 || itemRom.Size == -1)) @@ -2376,7 +2483,8 @@ namespace SabreTools.Helper.Dats && itemRom.Size > 0 && String.IsNullOrEmpty(itemRom.CRC) && String.IsNullOrEmpty(itemRom.MD5) - && String.IsNullOrEmpty(itemRom.SHA1)) + && String.IsNullOrEmpty(itemRom.SHA1) + && String.IsNullOrEmpty(itemRom.SHA256)) { logger.Verbose("Incomplete entry for \"" + itemRom.Name + "\" will be output as nodump"); itemRom.ItemStatus = ItemStatus.Nodump; @@ -2391,11 +2499,13 @@ namespace SabreTools.Helper.Dats // Sanitize the hashes from null, hex sizes, and "true blank" strings itemDisk.MD5 = Style.CleanHashData(itemDisk.MD5, Constants.MD5Length); itemDisk.SHA1 = Style.CleanHashData(itemDisk.SHA1, Constants.SHA1Length); + itemDisk.SHA256 = Style.CleanHashData(itemRom.SHA256, Constants.SHA256Length); // If the file has aboslutely no hashes, skip and log if (itemDisk.ItemStatus != ItemStatus.Nodump && String.IsNullOrEmpty(itemDisk.MD5) - && String.IsNullOrEmpty(itemDisk.SHA1)) + && String.IsNullOrEmpty(itemDisk.SHA1) + && String.IsNullOrEmpty(itemDisk.SHA256)) { logger.Verbose("Incomplete entry for \"" + itemDisk.Name + "\" will be output as nodump"); itemDisk.ItemStatus = ItemStatus.Nodump; @@ -2443,6 +2553,7 @@ namespace SabreTools.Helper.Dats TotalSize += 0; MD5Count += (String.IsNullOrEmpty(((Disk)item).MD5) ? 0 : 1); SHA1Count += (String.IsNullOrEmpty(((Disk)item).SHA1) ? 0 : 1); + SHA256Count += (String.IsNullOrEmpty((Disk)item).SHA256) ? 0 : 1); BaddumpCount += (((Disk)item).ItemStatus == ItemStatus.BadDump ? 1 : 0); NodumpCount += (((Disk)item).ItemStatus == ItemStatus.Nodump ? 1 : 0); break; @@ -2455,6 +2566,7 @@ namespace SabreTools.Helper.Dats CRCCount += (String.IsNullOrEmpty(((Rom)item).CRC) ? 0 : 1); MD5Count += (String.IsNullOrEmpty(((Rom)item).MD5) ? 0 : 1); SHA1Count += (String.IsNullOrEmpty(((Rom)item).SHA1) ? 0 : 1); + SHA256Count += (String.IsNullOrEmpty((Rom)item).SHA256) ? 0 : 1); BaddumpCount += (((Rom)item).ItemStatus == ItemStatus.BadDump ? 1 : 0); NodumpCount += (((Rom)item).ItemStatus == ItemStatus.Nodump ? 1 : 0); break; diff --git a/SabreTools.Helper/Dats/Partials/DatFile.Statistics.cs b/SabreTools.Helper/Dats/Partials/DatFile.Statistics.cs index e78ae747..79a1a736 100644 --- a/SabreTools.Helper/Dats/Partials/DatFile.Statistics.cs +++ b/SabreTools.Helper/Dats/Partials/DatFile.Statistics.cs @@ -37,6 +37,7 @@ namespace SabreTools.Helper.Dats CRCCount = 0; MD5Count = 0; SHA1Count = 0; + SHA256Count = 0; BaddumpCount = 0; NodumpCount = 0; @@ -63,6 +64,7 @@ namespace SabreTools.Helper.Dats DiskCount += 1; MD5Count += (String.IsNullOrEmpty(disk.MD5) ? 0 : 1); SHA1Count += (String.IsNullOrEmpty(disk.SHA1) ? 0 : 1); + SHA256Count += (String.IsNullOrEmpty(disk.SHA256) ? 0 : 1); BaddumpCount += (disk.ItemStatus == ItemStatus.BadDump ? 1 : 0); NodumpCount += (disk.ItemStatus == ItemStatus.Nodump ? 1 : 0); break; @@ -75,6 +77,7 @@ namespace SabreTools.Helper.Dats CRCCount += (String.IsNullOrEmpty(rom.CRC) ? 0 : 1); MD5Count += (String.IsNullOrEmpty(rom.MD5) ? 0 : 1); SHA1Count += (String.IsNullOrEmpty(rom.SHA1) ? 0 : 1); + SHA256Count += (String.IsNullOrEmpty(rom.SHA256) ? 0 : 1); BaddumpCount += (rom.ItemStatus == ItemStatus.BadDump ? 1 : 0); NodumpCount += (rom.ItemStatus == ItemStatus.Nodump ? 1 : 0); break; @@ -118,8 +121,9 @@ namespace SabreTools.Helper.Dats Roms found: " + RomCount + @" Disks found: " + DiskCount + @" Roms with CRC: " + CRCCount + @" - Roms with MD5 " + MD5Count + @" - Roms with SHA-1: " + SHA1Count + "\n"; + Roms with MD5: " + MD5Count + @" + Roms with SHA-1: " + SHA1Count + @" + Roms with SHA-256: " + SHA256Count + "\n"; if (baddumpCol) { @@ -143,8 +147,8 @@ namespace SabreTools.Helper.Dats Roms found: " + RomCount + @" Disks found: " + DiskCount + @" Roms with CRC: " + CRCCount + @" - Roms with MD5: " + MD5Count + @" - Roms with SHA-1: " + SHA1Count + "\n"; + Roms with SHA-1: " + SHA1Count + @" + Roms with SHA-256: " + SHA256Count + "\n"; if (baddumpCol) { @@ -165,7 +169,8 @@ namespace SabreTools.Helper.Dats + "\"" + DiskCount + "\"," + "\"" + CRCCount + "\"," + "\"" + MD5Count + "\"," - + "\"" + SHA1Count + "\""; + + "\"" + SHA1Count + "\"," + + "\"" + SHA256Count + "\""; if (baddumpCol) { @@ -190,7 +195,8 @@ namespace SabreTools.Helper.Dats + "" + DiskCount + "" + "" + CRCCount + "" + "" + MD5Count + "" - + "" + SHA1Count + ""; + + "" + SHA1Count + "" + + "" + SHA256Count + ""; if (baddumpCol) { @@ -213,7 +219,8 @@ namespace SabreTools.Helper.Dats + "\"" + DiskCount + "\"\t" + "\"" + CRCCount + "\"\t" + "\"" + MD5Count + "\"\t" - + "\"" + SHA1Count + "\""; + + "\"" + SHA1Count + "\"\t" + + "\"" + SHA256Count + "\""; if (baddumpCol) { @@ -302,6 +309,7 @@ namespace SabreTools.Helper.Dats long totalCRC = 0; long totalMD5 = 0; long totalSHA1 = 0; + long totalSHA256 = 0; long totalBaddump = 0; long totalNodump = 0; @@ -315,6 +323,7 @@ namespace SabreTools.Helper.Dats long dirCRC = 0; long dirMD5 = 0; long dirSHA1 = 0; + long dirSHA256 = 0; long dirBaddump = 0; long dirNodump = 0; @@ -340,6 +349,7 @@ namespace SabreTools.Helper.Dats CRCCount = dirCRC, MD5Count = dirMD5, SHA1Count = dirSHA1, + SHA256Count = dirSHA256, BaddumpCount = dirBaddump, NodumpCount = dirNodump, }; @@ -359,6 +369,7 @@ namespace SabreTools.Helper.Dats dirCRC = 0; dirMD5 = 0; dirSHA1 = 0; + dirSHA256 = 0; dirBaddump = 0; dirNodump = 0; } @@ -384,6 +395,7 @@ namespace SabreTools.Helper.Dats dirCRC += datdata.CRCCount; dirMD5 += datdata.MD5Count; dirSHA1 += datdata.SHA1Count; + dirSHA256 += datdata.SHA256Count; dirBaddump += datdata.BaddumpCount; dirNodump += datdata.NodumpCount; @@ -395,6 +407,7 @@ namespace SabreTools.Helper.Dats totalCRC += datdata.CRCCount; totalMD5 += datdata.MD5Count; totalSHA1 += datdata.SHA1Count; + totalSHA256 += datdata.SHA256Count; totalBaddump += datdata.BaddumpCount; totalNodump += datdata.NodumpCount; @@ -416,6 +429,7 @@ namespace SabreTools.Helper.Dats CRCCount = dirCRC, MD5Count = dirMD5, SHA1Count = dirSHA1, + SHA256Count = dirSHA256, BaddumpCount = dirBaddump, NodumpCount = dirNodump, }; @@ -436,6 +450,7 @@ namespace SabreTools.Helper.Dats dirCRC = 0; dirMD5 = 0; dirSHA1 = 0; + dirSHA256 = 0; dirNodump = 0; // Output total DAT stats @@ -448,6 +463,7 @@ namespace SabreTools.Helper.Dats CRCCount = totalCRC, MD5Count = totalMD5, SHA1Count = totalSHA1, + SHA256Count = totalSHA256, BaddumpCount = totalBaddump, NodumpCount = totalNodump, }; @@ -530,7 +546,7 @@ Please check the log folder if the stats scrolled offscreen", false); } if (outputs.ContainsKey(StatDatFormat.CSV)) { - outputs[StatDatFormat.CSV].Write("\"File Name\",\"Total Size\",\"Games\",\"Roms\",\"Disks\",\"# with CRC\",\"# with MD5\",\"# with SHA-1\"" + outputs[StatDatFormat.CSV].Write("\"File Name\",\"Total Size\",\"Games\",\"Roms\",\"Disks\",\"# with CRC\",\"# with MD5\",\"# with SHA-1\",\"# with SHA-256\"" + (baddumpCol ? ",\"BadDumps\"" : "") + (nodumpCol ? ",\"Nodumps\"" : "") + "\n"); } if (outputs.ContainsKey(StatDatFormat.HTML)) @@ -558,7 +574,7 @@ Please check the log folder if the stats scrolled offscreen", false); } if (outputs.ContainsKey(StatDatFormat.TSV)) { - outputs[StatDatFormat.TSV].Write("\"File Name\"\t\"Total Size\"\t\"Games\"\t\"Roms\"\t\"Disks\"\t\"# with CRC\"\t\"# with MD5\"\t\"# with SHA-1\"" + outputs[StatDatFormat.TSV].Write("\"File Name\"\t\"Total Size\"\t\"Games\"\t\"Roms\"\t\"Disks\"\t\"# with CRC\"\t\"# with MD5\"\t\"# with SHA-1\"\t\"# with SHA-256\"" + (baddumpCol ? "\t\"BadDumps\"" : "") + (nodumpCol ? "\t\"Nodumps\"" : "") + "\n"); } @@ -586,7 +602,7 @@ Please check the log folder if the stats scrolled offscreen", false); if (outputs.ContainsKey(StatDatFormat.HTML)) { outputs[StatDatFormat.HTML].Write(@" File NameTotal SizeGamesRoms" -+ @"Disks# with CRC# with MD5# with SHA-1" ++ @"Disks# with CRC# with MD5# with SHA-1# with SHA-256" + (baddumpCol ? "Baddumps" : "") + (nodumpCol ? "Nodumps" : "") + "\n"); } if (outputs.ContainsKey(StatDatFormat.TSV)) @@ -616,10 +632,10 @@ Please check the log folder if the stats scrolled offscreen", false); { outputs[StatDatFormat.HTML].Write("\n"); } @@ -650,10 +666,10 @@ Please check the log folder if the stats scrolled offscreen", false); { outputs[StatDatFormat.HTML].Write("\n"); } diff --git a/SabreTools.Helper/Dats/Partials/DatFile.Writers.cs b/SabreTools.Helper/Dats/Partials/DatFile.Writers.cs index bedf0ca7..21d8e0d2 100644 --- a/SabreTools.Helper/Dats/Partials/DatFile.Writers.cs +++ b/SabreTools.Helper/Dats/Partials/DatFile.Writers.cs @@ -173,7 +173,8 @@ namespace SabreTools.Helper.Dats && ((Rom)rom).Size == -1 && ((Rom)rom).CRC == "null" && ((Rom)rom).MD5 == "null" - && ((Rom)rom).SHA1 == "null") + && ((Rom)rom).SHA1 == "null" + && ((Rom)rom).SHA256 == "null") { logger.Verbose("Empty folder found: " + rom.Machine.Name); @@ -188,6 +189,7 @@ namespace SabreTools.Helper.Dats ((Rom)rom).CRC = Constants.CRCZero; ((Rom)rom).MD5 = Constants.MD5Zero; ((Rom)rom).SHA1 = Constants.SHA1Zero; + ((Rom)rom).SHA256 = Constants.SHA256Zero; } // Otherwise, set the new path and such, write out, and continue @@ -264,7 +266,7 @@ namespace SabreTools.Helper.Dats break; case DatFormat.CSV: header = "\"File Name\",\"Internal Name\",\"Description\",\"Game Name\",\"Game Description\",\"Type\",\"" + - "Rom Name\",\"Disk Name\",\"Size\",\"CRC\",\"MD5\",\"SHA1\",\"Nodump\"\n"; + "Rom Name\",\"Disk Name\",\"Size\",\"CRC\",\"MD5\",\"SHA1\"\"SHA256\",\"Nodump\"\n"; break; case DatFormat.DOSCenter: header = "DOSCenter (\n" + @@ -311,7 +313,7 @@ namespace SabreTools.Helper.Dats break; case DatFormat.TSV: header = "\"File Name\"\t\"Internal Name\"\t\"Description\"\t\"Game Name\"\t\"Game Description\"\t\"Type\"\t\"" + - "Rom Name\"\t\"Disk Name\"\t\"Size\"\t\"CRC\"\t\"MD5\"\t\"SHA1\"\t\"Nodump\"\n"; + "Rom Name\"\t\"Disk Name\"\t\"Size\"\t\"CRC\"\t\"MD5\"\t\"SHA1\"\t\"SHA256\"\t\"Nodump\"\n"; break; case DatFormat.OfflineList: header = "\n" @@ -687,6 +689,7 @@ namespace SabreTools.Helper.Dats state += "\tdisk ( name \"" + rom.Name + "\"" + (!String.IsNullOrEmpty(((Disk)rom).MD5) ? " md5 " + ((Disk)rom).MD5.ToLowerInvariant() : "") + (!String.IsNullOrEmpty(((Disk)rom).SHA1) ? " sha1 " + ((Disk)rom).SHA1.ToLowerInvariant() : "") + + (!String.IsNullOrEmpty(((Disk)rom).SHA256) ? " sha256 " + ((Disk)rom).SHA256.ToLowerInvariant() : "") + (((Disk)rom).ItemStatus != ItemStatus.None ? " flags " + ((Disk)rom).ItemStatus.ToString().ToLowerInvariant() : "") + " )\n"; break; @@ -706,6 +709,7 @@ namespace SabreTools.Helper.Dats + (!String.IsNullOrEmpty(((Rom)rom).CRC) ? " crc " + ((Rom)rom).CRC.ToLowerInvariant() : "") + (!String.IsNullOrEmpty(((Rom)rom).MD5) ? " md5 " + ((Rom)rom).MD5.ToLowerInvariant() : "") + (!String.IsNullOrEmpty(((Rom)rom).SHA1) ? " sha1 " + ((Rom)rom).SHA1.ToLowerInvariant() : "") + + (!String.IsNullOrEmpty(((Rom)rom).SHA256) ? " sha256 " + ((Rom)rom).SHA256.ToLowerInvariant() : "") + (!String.IsNullOrEmpty(((Rom)rom).Date) ? " date \"" + ((Rom)rom).Date + "\"" : "") + (((Rom)rom).ItemStatus != ItemStatus.None ? " flags " + ((Rom)rom).ItemStatus.ToString().ToLowerInvariant() : "") + " )\n"; @@ -736,6 +740,7 @@ namespace SabreTools.Helper.Dats .Replace("%crc%", ((Rom)rom).CRC) .Replace("%md5%", ((Rom)rom).MD5) .Replace("%sha1%", ((Rom)rom).SHA1) + .Replace("%sha256%", ((Rom)rom).SHA256) .Replace("%size%", ((Rom)rom).Size.ToString()); post = post .Replace("%game%", rom.Machine.Name) @@ -743,6 +748,7 @@ namespace SabreTools.Helper.Dats .Replace("%crc%", ((Rom)rom).CRC) .Replace("%md5%", ((Rom)rom).MD5) .Replace("%sha1%", ((Rom)rom).SHA1) + .Replace("%sha256%", ((Rom)rom).SHA256) .Replace("%size%", ((Rom)rom).Size.ToString()); } else if (rom.Type == ItemType.Disk) @@ -751,13 +757,37 @@ namespace SabreTools.Helper.Dats pre = pre .Replace("%game%", rom.Machine.Name) .Replace("%name%", rom.Name) + .Replace("%crc%", string.Empty) .Replace("%md5%", ((Disk)rom).MD5) - .Replace("%sha1%", ((Disk)rom).SHA1); + .Replace("%sha1%", ((Disk)rom).SHA1) + .Replace("%sha256%", ((Disk)rom).SHA256) + .Replace("%size%", string.Empty);; post = post .Replace("%game%", rom.Machine.Name) .Replace("%name%", rom.Name) + .Replace("%crc%", string.Empty) .Replace("%md5%", ((Disk)rom).MD5) - .Replace("%sha1%", ((Disk)rom).SHA1); + .Replace("%sha1%", ((Disk)rom).SHA1) + .Replace("%sha256%", ((Disk)rom).SHA256) + .Replace("%size%", string.Empty);; + } + else + { + // Check for special strings in prefix and postfix + pre = pre + .Replace("%game%", rom.Machine.Name) + .Replace("%name%", rom.Name) + .Replace("%crc%", string.Empty) + .Replace("%md5%", string.Empty) + .Replace("%sha1%", string.Empty) + .Replace("%size%", string.Empty); + post = post + .Replace("%game%", rom.Machine.Name) + .Replace("%name%", rom.Name) + .Replace("%crc%", string.Empty) + .Replace("%md5%", string.Empty) + .Replace("%sha1%", string.Empty) + .Replace("%size%", string.Empty); } if (rom.Type == ItemType.Rom) @@ -774,6 +804,7 @@ namespace SabreTools.Helper.Dats + ",\"" + ((Rom)rom).CRC + "\"" + ",\"" + ((Rom)rom).MD5 + "\"" + ",\"" + ((Rom)rom).SHA1 + "\"" + + ",\"" + ((Rom)rom).SHA256 + "\"" + "," + (((Rom)rom).ItemStatus != ItemStatus.None ? "\"" + ((Rom)rom).ItemStatus.ToString() + "\"" : "\"\""); state += pre + inline + post + "\n"; } @@ -791,6 +822,7 @@ namespace SabreTools.Helper.Dats + "," + "\"\"" + ",\"" + ((Disk)rom).MD5 + "\"" + ",\"" + ((Disk)rom).SHA1 + "\"" + + ",\"" + ((Disk)rom).SHA256 + "\"" + "," + (((Disk)rom).ItemStatus != ItemStatus.None ? "\"" + ((Disk)rom).ItemStatus.ToString() + "\"" : "\"\""); state += pre + inline + post + "\n"; } @@ -833,6 +865,7 @@ namespace SabreTools.Helper.Dats state += "\t\t\n"; break; @@ -852,6 +885,7 @@ namespace SabreTools.Helper.Dats + (!String.IsNullOrEmpty(((Rom)rom).CRC) ? " crc=\"" + ((Rom)rom).CRC.ToLowerInvariant() + "\"" : "") + (!String.IsNullOrEmpty(((Rom)rom).MD5) ? " md5=\"" + ((Rom)rom).MD5.ToLowerInvariant() + "\"" : "") + (!String.IsNullOrEmpty(((Rom)rom).SHA1) ? " sha1=\"" + ((Rom)rom).SHA1.ToLowerInvariant() + "\"" : "") + + (!String.IsNullOrEmpty(((Rom)rom).SHA256) ? " sha256=\"" + ((Rom)rom).SHA256.ToLowerInvariant() + "\"" : "") + (!String.IsNullOrEmpty(((Rom)rom).Date) ? " date=\"" + ((Rom)rom).Date + "\"" : "") + (((Rom)rom).ItemStatus != ItemStatus.None ? " status=\"" + ((Rom)rom).ItemStatus.ToString().ToLowerInvariant() + "\"" : "") + "/>\n"; @@ -875,6 +909,7 @@ namespace SabreTools.Helper.Dats .Replace("%crc%", ((Rom)rom).CRC) .Replace("%md5%", ((Rom)rom).MD5) .Replace("%sha1%", ((Rom)rom).SHA1) + .Replace("%sha256%", ((Rom)rom).SHA256) .Replace("%size%", ((Rom)rom).Size.ToString()); post = post .Replace("%game%", rom.Machine.Name) @@ -882,6 +917,7 @@ namespace SabreTools.Helper.Dats .Replace("%crc%", ((Rom)rom).CRC) .Replace("%md5%", ((Rom)rom).MD5) .Replace("%sha1%", ((Rom)rom).SHA1) + .Replace("%sha256%", ((Rom)rom).SHA256) .Replace("%size%", ((Rom)rom).Size.ToString()); } else if (rom.Type == ItemType.Disk) @@ -893,6 +929,7 @@ namespace SabreTools.Helper.Dats .Replace("%crc%", string.Empty) .Replace("%md5%", ((Disk)rom).MD5) .Replace("%sha1%", ((Disk)rom).SHA1) + .Replace("%sha256%", ((Disk)rom).SHA256) .Replace("%size%", string.Empty); post = post .Replace("%game%", rom.Machine.Name) @@ -900,6 +937,7 @@ namespace SabreTools.Helper.Dats .Replace("%crc%", string.Empty) .Replace("%md5%", ((Disk)rom).MD5) .Replace("%sha1%", ((Disk)rom).SHA1) + .Replace("%sha256%", ((Disk)rom).SHA256) .Replace("%size%", string.Empty); } else @@ -961,6 +999,7 @@ namespace SabreTools.Helper.Dats RepExt = ""; } + // TODO: Find out why this code strips out partial paths string dir = Path.GetDirectoryName(name); dir = (dir.StartsWith(Path.DirectorySeparatorChar.ToString()) ? dir.Remove(0, 1) : dir); name = Path.Combine(dir, Path.GetFileNameWithoutExtension(name) + RepExt); @@ -1058,6 +1097,16 @@ namespace SabreTools.Helper.Dats state += ((Disk)rom).SHA1 + " *" + (GameName ? rom.Machine.Name + Path.DirectorySeparatorChar : "") + rom.Name + "\n"; } break; + case DatFormat.RedumpSHA256: + if (rom.Type == ItemType.Rom) + { + state += ((Rom)rom).SHA256 + " *" + (GameName ? rom.Machine.Name + Path.DirectorySeparatorChar : "") + rom.Name + "\n"; + } + else if (rom.Type == ItemType.Disk) + { + state += ((Disk)rom).SHA256 + " *" + (GameName ? rom.Machine.Name + Path.DirectorySeparatorChar : "") + rom.Name + "\n"; + } + break; case DatFormat.RomCenter: if (rom.Type == ItemType.Rom) { @@ -1106,6 +1155,7 @@ namespace SabreTools.Helper.Dats state += "\n" + prefix + "\t\n" + prefix + "\t\t\n" + prefix + "\t\n" + @@ -1127,6 +1177,7 @@ namespace SabreTools.Helper.Dats + (!String.IsNullOrEmpty(((Rom)rom).CRC) ? " crc=\"" + ((Rom)rom).CRC.ToLowerInvariant() + "\"" : "") + (!String.IsNullOrEmpty(((Rom)rom).MD5) ? " md5=\"" + ((Rom)rom).MD5.ToLowerInvariant() + "\"" : "") + (!String.IsNullOrEmpty(((Rom)rom).SHA1) ? " sha1=\"" + ((Rom)rom).SHA1.ToLowerInvariant() + "\"" : "") + + (!String.IsNullOrEmpty(((Rom)rom).SHA256) ? " sha256=\"" + ((Rom)rom).SHA256.ToLowerInvariant() + "\"" : "") + (!String.IsNullOrEmpty(((Rom)rom).Date) ? " date=\"" + ((Rom)rom).Date + "\"" : "") + (((Rom)rom).ItemStatus != ItemStatus.None ? prefix + "/>\n" + prefix + "\t\n" + prefix + "\t\t\n" + @@ -1173,6 +1224,7 @@ namespace SabreTools.Helper.Dats + "\t\t\t\t\n" + "\t\t\t\n"; @@ -1198,6 +1250,7 @@ namespace SabreTools.Helper.Dats + (!String.IsNullOrEmpty(((Rom)rom).CRC) ? " crc=\"" + ((Rom)rom).CRC.ToLowerInvariant() + "\"" : "") + (!String.IsNullOrEmpty(((Rom)rom).MD5) ? " md5=\"" + ((Rom)rom).MD5.ToLowerInvariant() + "\"" : "") + (!String.IsNullOrEmpty(((Rom)rom).SHA1) ? " sha1=\"" + ((Rom)rom).SHA1.ToLowerInvariant() + "\"" : "") + + (!String.IsNullOrEmpty(((Rom)rom).SHA256) ? " sha256=\"" + ((Rom)rom).SHA256.ToLowerInvariant() + "\"" : "") + (!String.IsNullOrEmpty(((Rom)rom).Date) ? " date=\"" + ((Rom)rom).Date + "\"" : "") + (((Rom)rom).ItemStatus != ItemStatus.None ? " status=\"" + ((Rom)rom).ItemStatus.ToString().ToLowerInvariant() + "\"" : "") + "/>\n" @@ -1233,6 +1286,7 @@ namespace SabreTools.Helper.Dats .Replace("%crc%", ((Rom)rom).CRC) .Replace("%md5%", ((Rom)rom).MD5) .Replace("%sha1%", ((Rom)rom).SHA1) + .Replace("%sha256%", ((Rom)rom).SHA256) .Replace("%size%", ((Rom)rom).Size.ToString()); post = post .Replace("%game%", rom.Machine.Name) @@ -1240,6 +1294,7 @@ namespace SabreTools.Helper.Dats .Replace("%crc%", ((Rom)rom).CRC) .Replace("%md5%", ((Rom)rom).MD5) .Replace("%sha1%", ((Rom)rom).SHA1) + .Replace("%sha256%", ((Rom)rom).SHA256) .Replace("%size%", ((Rom)rom).Size.ToString()); } else if (rom.Type == ItemType.Disk) @@ -1248,14 +1303,41 @@ namespace SabreTools.Helper.Dats pre = pre .Replace("%game%", rom.Machine.Name) .Replace("%name%", rom.Name) + .Replace("%crc%", string.Empty) .Replace("%md5%", ((Disk)rom).MD5) - .Replace("%sha1%", ((Disk)rom).SHA1); + .Replace("%sha1%", ((Disk)rom).SHA1) + .Replace("%sha256%", ((Disk)rom).SHA256) + .Replace("%size%", string.Empty); post = post .Replace("%game%", rom.Machine.Name) .Replace("%name%", rom.Name) + .Replace("%crc%", string.Empty) .Replace("%md5%", ((Disk)rom).MD5) - .Replace("%sha1%", ((Disk)rom).SHA1); + .Replace("%sha1%", ((Disk)rom).SHA1) + .Replace("%sha256%", ((Disk)rom).SHA256) + .Replace("%size%", string.Empty);; } + else + { + // Check for special strings in prefix and postfix + pre = pre + .Replace("%game%", rom.Machine.Name) + .Replace("%name%", rom.Name) + .Replace("%crc%", string.Empty) + .Replace("%md5%", string.Empty) + .Replace("%sha1%", string.Empty) + .Replace("%sha256%", string.Empty) + .Replace("%size%", string.Empty); + post = post + .Replace("%game%", rom.Machine.Name) + .Replace("%name%", rom.Name) + .Replace("%crc%", string.Empty) + .Replace("%md5%", string.Empty) + .Replace("%sha1%", string.Empty) + .Replace("%sha256%", string.Empty) + .Replace("%size%", string.Empty);; + } + if (rom.Type == ItemType.Rom) { @@ -1271,6 +1353,7 @@ namespace SabreTools.Helper.Dats + "\t\"" + ((Rom)rom).CRC + "\"" + "\t\"" + ((Rom)rom).MD5 + "\"" + "\t\"" + ((Rom)rom).SHA1 + "\"" + + "\t\"" + ((Rom)rom).SHA256 + "\"" + "\t" + (((Rom)rom).ItemStatus != ItemStatus.None ? "\"" + ((Rom)rom).ItemStatus.ToString() + "\"" : "\"\""); state += pre + inline + post + "\n"; } @@ -1288,6 +1371,7 @@ namespace SabreTools.Helper.Dats + "\t" + "\"\"" + "\t\"" + ((Disk)rom).MD5 + "\"" + "\t\"" + ((Disk)rom).SHA1 + "\"" + + "\t\"" + ((Disk)rom).SHA256 + "\"" + "\t" + (((Disk)rom).ItemStatus != ItemStatus.None ? "\"" + ((Disk)rom).ItemStatus.ToString() + "\"" : "\"\""); state += pre + inline + post + "\n"; } diff --git a/SabreTools.Helper/Dats/Rom.cs b/SabreTools.Helper/Dats/Rom.cs index aace1b4e..ec91a054 100644 --- a/SabreTools.Helper/Dats/Rom.cs +++ b/SabreTools.Helper/Dats/Rom.cs @@ -63,6 +63,7 @@ namespace SabreTools.Helper.Dats _crc = "null"; _md5 = "null"; _sha1 = "null"; + _sha256 = "null"; _itemStatus = ItemStatus.None; _machine = new Machine @@ -102,6 +103,7 @@ namespace SabreTools.Helper.Dats MD5 = this.MD5, SHA1 = this.SHA1, + SHA256 = this.SHA256, ItemStatus = this.ItemStatus, Size = this.Size, CRC = this.CRC, @@ -132,10 +134,11 @@ namespace SabreTools.Helper.Dats return dupefound; } - if ((this.Size == newOther.Size) && - ((String.IsNullOrEmpty(this.CRC) || String.IsNullOrEmpty(newOther.CRC)) || this.CRC == newOther.CRC) && - ((String.IsNullOrEmpty(this.MD5) || String.IsNullOrEmpty(newOther.MD5)) || this.MD5 == newOther.MD5) && - ((String.IsNullOrEmpty(this.SHA1) || String.IsNullOrEmpty(newOther.SHA1)) || this.SHA1 == newOther.SHA1)) + if ((this.Size == newOther.Size) + && ((String.IsNullOrEmpty(this.CRC) || String.IsNullOrEmpty(newOther.CRC)) || this.CRC == newOther.CRC) + && ((String.IsNullOrEmpty(this.MD5) || String.IsNullOrEmpty(newOther.MD5)) || this.MD5 == newOther.MD5) && + && ((String.IsNullOrEmpty(this.SHA1) || String.IsNullOrEmpty(newOther.SHA1)) || this.SHA1 == newOther.SHA1) + && ((String.IsNullOrEmpty(this.SHA256) || String.IsNullOrEmpty(newOther.SHA256)) || this.SHA256 == newOther.SHA256)) { dupefound = true; } diff --git a/SabreTools.Helper/Tools/FileTools.cs b/SabreTools.Helper/Tools/FileTools.cs index 25be7119..892e0c37 100644 --- a/SabreTools.Helper/Tools/FileTools.cs +++ b/SabreTools.Helper/Tools/FileTools.cs @@ -178,11 +178,13 @@ namespace SabreTools.Helper.Tools /// Logger object for console and file output /// True if MD5 hashes should not be calculated, false otherwise (default) /// True if SHA-1 hashes should not be calcluated, false otherwise (default) + /// True if SHA-256 hashes should not be calcluated, false otherwise (default) /// Set a >0 number for getting hash for part of the file, 0 otherwise (default) /// True if the file Date should be included, false otherwise (default) /// Populated string representing the name of the skipper to use, a blank string to use the first available checker, null otherwise /// Populated RomData object if success, empty one on error - public static Rom GetFileInfo(string input, Logger logger, bool noMD5 = false, bool noSHA1 = false, long offset = 0, bool date = false, string header = null) + public static Rom GetFileInfo(string input, Logger logger, bool noMD5 = false, bool noSHA1 = false, + bool noSHA256 = false, long offset = 0, bool date = false, string header = null) { // Add safeguard if file doesn't exist if (!File.Exists(input)) @@ -214,12 +216,12 @@ namespace SabreTools.Helper.Tools // Otherwise, just get the info else { - rom = GetStreamInfo(File.OpenRead(input), new FileInfo(input).Length, noMD5, noSHA1, offset, false); + rom = GetStreamInfo(File.OpenRead(input), new FileInfo(input).Length, noMD5, noSHA1, noSHA256, offset, false); } } else { - rom = GetStreamInfo(File.OpenRead(input), new FileInfo(input).Length, noMD5, noSHA1, offset, false); + rom = GetStreamInfo(File.OpenRead(input), new FileInfo(input).Length, noMD5, noSHA1, noSHA256, offset, false); } // Add unique data from the file @@ -497,10 +499,12 @@ namespace SabreTools.Helper.Tools /// Size of the input stream /// True if MD5 hashes should not be calculated, false otherwise (default) /// True if SHA-1 hashes should not be calcluated, false otherwise (default) + /// True if SHA-256 hashes should not be calcluated, false otherwise (default) /// Set a >0 number for getting hash for part of the file, 0 otherwise (default) /// True if the underlying read stream should be kept open, false otherwise /// Populated RomData object if success, empty one on error - public static Rom GetStreamInfo(Stream input, long size, bool noMD5 = false, bool noSHA1 = false, long offset = 0, bool keepReadOpen = false) + public static Rom GetStreamInfo(Stream input, long size, bool noMD5 = false, bool noSHA1 = false, + bool noSHA256 = false, long offset = 0, bool keepReadOpen = false) { Rom rom = new Rom { @@ -509,6 +513,7 @@ namespace SabreTools.Helper.Tools CRC = string.Empty, MD5 = string.Empty, SHA1 = string.Empty, + SHA256 = string.Empty, }; try @@ -517,6 +522,7 @@ namespace SabreTools.Helper.Tools OptimizedCRC crc = new OptimizedCRC(); MD5 md5 = MD5.Create(); SHA1 sha1 = SHA1.Create(); + SHA256 sha256 = SHA256.Create(); // Seek to the starting position, if one is set if (offset < 0) @@ -541,6 +547,10 @@ namespace SabreTools.Helper.Tools { sha1.TransformBlock(buffer, 0, read, buffer, 0); } + if (!noSHA256) + { + sha256.TransformBlock(buffer, 0, read, buffer, 0); + } } crc.Update(buffer, 0, 0); @@ -556,11 +566,17 @@ namespace SabreTools.Helper.Tools sha1.TransformFinalBlock(buffer, 0, 0); rom.SHA1 = BitConverter.ToString(sha1.Hash).Replace("-", "").ToLowerInvariant(); } + if (!noSHA256) + { + sha256.TransformFinalBlock(buffer, 0, 0); + rom.SHA256 = BitConverter.ToString(sha256.Hash).Replace("-", "").ToLowerInvariant(); + } // Dispose of the hashers crc.Dispose(); md5.Dispose(); sha1.Dispose(); + sha256.Dispose(); } catch (IOException) { diff --git a/SabreTools.Helper/Tools/Style.cs b/SabreTools.Helper/Tools/Style.cs index b7e21800..b011d24a 100644 --- a/SabreTools.Helper/Tools/Style.cs +++ b/SabreTools.Helper/Tools/Style.cs @@ -186,6 +186,12 @@ namespace SabreTools.Helper.Tools outfileNames.Add(DatFormat.RedumpSHA1, CreateOutfileNamesHelper(outDir, ".sha1", datdata, overwrite)); }; + // Redump SHA-256 + if ((datdata.DatFormat & DatFormat.RedumpSHA256) != 0) + { + outfileNames.Add(DatFormat.RedumpSHA256, CreateOutfileNamesHelper(outDir, ".sha256", datdata, overwrite)); + }; + // RomCenter if ((datdata.DatFormat & DatFormat.RomCenter) != 0 && (datdata.DatFormat & DatFormat.ClrMamePro) == 0) diff --git a/SabreTools/Partials/SabreTools.Help.cs b/SabreTools/Partials/SabreTools.Help.cs index 55faaf09..005d37a3 100644 --- a/SabreTools/Partials/SabreTools.Help.cs +++ b/SabreTools/Partials/SabreTools.Help.cs @@ -49,6 +49,11 @@ namespace SabreTools "Don't include SHA1 in output", FeatureType.Flag, null)); + datFromDir.AddFeature("noSHA256", new Feature( + new List() { "-ns256", "--noSHA256" }, + "Don't include SHA256 in output", + FeatureType.Flag, + null)); datFromDir.AddFeature("bare", new Feature( new List() { "-b", "--bare" }, "Don't include date in file name", @@ -99,7 +104,7 @@ namespace SabreTools FeatureType.Flag, null)); datFromDir.AddFeature("output-md5", new Feature( - new List() { "-oa", "--output-md5" }, + new List() { "-omd5", "--output-md5" }, "Output in MD5 format", FeatureType.Flag, null)); @@ -124,10 +129,15 @@ namespace SabreTools FeatureType.Flag, null)); datFromDir.AddFeature("output-sha1", new Feature( - new List() { "-osfv", "--output-sha1" }, + new List() { "-osha1", "--output-sha1" }, "Output in SHA-1 format", FeatureType.Flag, null)); + datFromDir.AddFeature("output-sha256", new Feature( + new List() { "-osha256", "--output-sha256" }, + "Output in SHA-256 format", + FeatureType.Flag, + null)); datFromDir.AddFeature("output-sl", new Feature( new List() { "-osl", "--output-sl" }, "Output in Softwarelist format", @@ -701,7 +711,14 @@ namespace SabreTools new List() { "-om", "--output-miss" }, "Output in Missfile format", FeatureType.Flag, - null)); + new List() + { + "", + "Prefix and postfix can include certain fields from the", + "items by including %blah% in the input.", + "A list of features that can be used are:", + " game, name, crc, md5, sha1, sha256, size", + })); update["output-miss"].AddFeature("roms", new Feature( new List() { "-r", "--roms" }, "Output roms to miss instead of sets", @@ -758,7 +775,7 @@ namespace SabreTools FeatureType.Flag, null)); update.AddFeature("output-md5", new Feature( - new List() { "-oa", "--output-md5" }, + new List() { "-omd5", "--output-md5" }, "Output in MD5 format", FeatureType.Flag, null)); @@ -793,7 +810,7 @@ namespace SabreTools FeatureType.Flag, null)); update.AddFeature("output-sha1", new Feature( - new List() { "-osfv", "--output-sha1" }, + new List() { "-osha1", "--output-sha1" }, "Output in SHA-1 format", FeatureType.Flag, null)); @@ -802,6 +819,16 @@ namespace SabreTools "Add game name as a prefix", FeatureType.Flag, null)); + update.AddFeature("output-sha256", new Feature( + new List() { "-osha256", "--output-sha256" }, + "Output in SHA-256 format", + FeatureType.Flag, + null)); + update["output-sha256"].AddFeature("game-prefix", new Feature( + new List() { "-gp", "--game-prefix" }, + "Add game name as a prefix", + FeatureType.Flag, + null)); update.AddFeature("output-sl", new Feature( new List() { "-osl", "--output-sl" }, "Output in Softwarelist format", @@ -1144,6 +1171,16 @@ namespace SabreTools "Filter by not SHA-1 hash", FeatureType.List, null)); + update.AddFeature("sha256", new Feature( + new List() { "-sha256", "--sha256" }, + "Filter by SHA-256 hash", + FeatureType.List, + null)); + update.AddFeature("not-sha256", new Feature( + new List() { "-nsha256", "--not-sha256" }, + "Filter by not SHA-256 hash", + FeatureType.List, + null)); update.AddFeature("status", new Feature( new List() { "-is", "--status" }, "Include only items with a given status", diff --git a/SabreTools/Partials/SabreTools.Inits.cs b/SabreTools/Partials/SabreTools.Inits.cs index 5b4efb75..730e64ce 100644 --- a/SabreTools/Partials/SabreTools.Inits.cs +++ b/SabreTools/Partials/SabreTools.Inits.cs @@ -37,6 +37,7 @@ namespace SabreTools /// True to enable SuperDAT-style reading, false otherwise /// True to disable getting MD5 hash, false otherwise /// True to disable getting SHA-1 hash, false otherwise + /// True to disable getting SHA-256 hash, false otherwise /// True if the date should be omitted from the DAT, false otherwise /// True if archives should be treated as files, false otherwise /// True if GZIP archives should be treated as files, false otherwise @@ -61,6 +62,7 @@ namespace SabreTools bool superdat, bool noMD5, bool noSHA1, + bool noSHA256, bool removeDateFromAutomaticName, bool parseArchivesAsFiles, bool enableGzip, @@ -116,7 +118,7 @@ namespace SabreTools DatFile datdata = new DatFile(basedat); string basePath = Path.GetFullPath(path); - bool success = datdata.PopulateFromDir(basePath, noMD5, noSHA1, removeDateFromAutomaticName, parseArchivesAsFiles, enableGzip, + bool success = datdata.PopulateFromDir(basePath, noMD5, noSHA1, noSHA256, removeDateFromAutomaticName, parseArchivesAsFiles, enableGzip, addBlankFilesForEmptyFolder, addFileDates, tempDir, copyFiles, headerToCheckAgainst, maxDegreeOfParallelism, _logger); // If it was a success, write the DAT out diff --git a/SabreTools/SabreTools.cs b/SabreTools/SabreTools.cs index 40531cd7..7f894ad4 100644 --- a/SabreTools/SabreTools.cs +++ b/SabreTools/SabreTools.cs @@ -103,6 +103,7 @@ namespace SabreTools merge = false, noMD5 = false, noSHA1 = false, + noSHA256 = true, // TODO: This will eventually need to be inversed parseArchivesAsFiles = false, quickScan = false, quotes = false, @@ -394,6 +395,10 @@ namespace SabreTools case "--noSHA1": noSHA1 = true; break; + case "-ns256": + case "--noSHA256": + noSHA256 = false; + break; case "-oa": case "--output-all": datFormat |= DatFormat.ALL; @@ -446,6 +451,10 @@ namespace SabreTools case "--output-sha1": datFormat |= DatFormat.RedumpSHA1; break; + case "-osha256": + case "--output-sha256": + datFormat |= DatFormat.RedumpSHA256; + break; case "-osl": case "--output-sl": datFormat |= DatFormat.SoftwareList; @@ -697,6 +706,10 @@ namespace SabreTools case "--not-sha1": filter.NotSHA1s.Add(args[++i]); break; + case "-nsha256": + case "--not-sha256": + filter.NotSHA256s.Add(args[++i]); + break; case "-out": case "--out": outDir = args[++i]; @@ -748,6 +761,10 @@ namespace SabreTools case "--sha1": filter.SHA1s.Add(args[++i]); break; + case "-sha256": + case "--sha256": + filter.SHA256s.Add(args[++i]); + break; case "-slt": case "--less": filter.SizeLessThanOrEqual = GetSizeFromString(args[++i]); @@ -930,6 +947,10 @@ namespace SabreTools case "--not-sha1": filter.NotSHA1s.Add(split[1]); break; + case "-nsha256": + case "--not-sha256": + filter.NotSHA256s.Add(split[1]); + break; case "-out": case "--out": outDir = split[1]; @@ -981,6 +1002,10 @@ namespace SabreTools case "--sha1": filter.SHA1s.Add(split[1]); break; + case "-sha256": + case "--sha256": + filter.SHA256s.Add(split[1]); + break; case "-slt": case "--less": filter.SizeLessThanOrEqual = GetSizeFromString(split[1]); @@ -1080,6 +1105,7 @@ namespace SabreTools superdat, noMD5, noSHA1, + noSHA256, removeDateFromAutomaticName, parseArchivesAsFiles, enableGzip,