diff --git a/SabreTools.Library/DatFiles/DatFile.cs b/SabreTools.Library/DatFiles/DatFile.cs index cc7239ce..c97998dd 100644 --- a/SabreTools.Library/DatFiles/DatFile.cs +++ b/SabreTools.Library/DatFiles/DatFile.cs @@ -1581,8 +1581,9 @@ namespace SabreTools.Library.DatFiles /// True to allow SL DATs to have game names used instead of descriptions, false otherwise (default) /// Filter object to be passed to the DatItem level /// Type of the split that should be performed (split, merged, fully merged) + /// True if hashes should be updated along with names, false otherwise [Only for base replacement] public void DetermineUpdateType(List inputPaths, List basePaths, string outDir, UpdateMode updateMode, bool inplace, bool skip, - bool bare, bool clean, bool remUnicode, bool descAsName, Filter filter, SplitType splitType) + bool bare, bool clean, bool remUnicode, bool descAsName, Filter filter, SplitType splitType, bool updateHashes) { // Ensure we only have files in the inputs List inputFileNames = Utilities.GetOnlyFilesFromInputs(inputPaths, appendparent: true); @@ -1636,7 +1637,7 @@ namespace SabreTools.Library.DatFiles else if ((updateMode & UpdateMode.BaseReplace) != 0 || (updateMode & UpdateMode.ReverseBaseReplace) != 0) { - BaseReplace(inputFileNames, baseFileNames, outDir, inplace, clean, remUnicode, descAsName, filter, splitType); + BaseReplace(inputFileNames, baseFileNames, outDir, inplace, clean, remUnicode, descAsName, filter, splitType, updateHashes); } return; @@ -1718,8 +1719,9 @@ namespace SabreTools.Library.DatFiles /// 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 + /// True if hashes should be updated along with names, false otherwise public void BaseReplace(List inputFileNames, List baseFileNames, string outDir, bool inplace, bool clean, bool remUnicode, - bool descAsName, Filter filter, SplitType splitType) + bool descAsName, Filter filter, SplitType splitType, bool updateHashes) { // First we want to parse all of the base DATs into the input InternalStopwatch watch = new InternalStopwatch("Populating base DAT for replacement..."); @@ -1769,6 +1771,67 @@ namespace SabreTools.Library.DatFiles if (dupes.Count > 0) { newDatItem.Name = dupes[0].Name; + + // If we're updating hashes too, only replace if the current item doesn't have them + if (updateHashes) + { + if (newDatItem.Type == ItemType.Rom) + { + Rom newRomItem = (Rom)newDatItem; + if (String.IsNullOrEmpty(newRomItem.CRC) && !String.IsNullOrEmpty(((Rom)dupes[0]).CRC)) + { + newRomItem.CRC = ((Rom)dupes[0]).CRC; + } + if (String.IsNullOrEmpty(newRomItem.MD5) && !String.IsNullOrEmpty(((Rom)dupes[0]).MD5)) + { + newRomItem.MD5 = ((Rom)dupes[0]).MD5; + } + if (String.IsNullOrEmpty(newRomItem.SHA1) && !String.IsNullOrEmpty(((Rom)dupes[0]).SHA1)) + { + newRomItem.SHA1 = ((Rom)dupes[0]).SHA1; + } + if (String.IsNullOrEmpty(newRomItem.SHA256) && !String.IsNullOrEmpty(((Rom)dupes[0]).SHA256)) + { + newRomItem.SHA256 = ((Rom)dupes[0]).SHA256; + } + if (String.IsNullOrEmpty(newRomItem.SHA384) && !String.IsNullOrEmpty(((Rom)dupes[0]).SHA384)) + { + newRomItem.SHA384 = ((Rom)dupes[0]).SHA384; + } + if (String.IsNullOrEmpty(newRomItem.SHA512) && !String.IsNullOrEmpty(((Rom)dupes[0]).SHA512)) + { + newRomItem.SHA512 = ((Rom)dupes[0]).SHA512; + } + + newDatItem = (Rom)newRomItem.Clone(); + } + else if (newDatItem.Type == ItemType.Disk) + { + Disk newDiskItem = (Disk)newDatItem; + if (String.IsNullOrEmpty(newDiskItem.MD5) && !String.IsNullOrEmpty(((Rom)dupes[0]).MD5)) + { + newDiskItem.MD5 = ((Rom)dupes[0]).MD5; + } + if (String.IsNullOrEmpty(newDiskItem.SHA1) && !String.IsNullOrEmpty(((Rom)dupes[0]).SHA1)) + { + newDiskItem.SHA1 = ((Rom)dupes[0]).SHA1; + } + if (String.IsNullOrEmpty(newDiskItem.SHA256) && !String.IsNullOrEmpty(((Rom)dupes[0]).SHA256)) + { + newDiskItem.SHA256 = ((Rom)dupes[0]).SHA256; + } + if (String.IsNullOrEmpty(newDiskItem.SHA384) && !String.IsNullOrEmpty(((Rom)dupes[0]).SHA384)) + { + newDiskItem.SHA384 = ((Rom)dupes[0]).SHA384; + } + if (String.IsNullOrEmpty(newDiskItem.SHA512) && !String.IsNullOrEmpty(((Rom)dupes[0]).SHA512)) + { + newDiskItem.SHA512 = ((Rom)dupes[0]).SHA512; + } + + newDatItem = (Disk)newDiskItem.Clone(); + } + } } newDatItems.Add(newDatItem); diff --git a/SabreTools.Library/README.1ST b/SabreTools.Library/README.1ST index 424ae8d2..7eb58ce2 100644 --- a/SabreTools.Library/README.1ST +++ b/SabreTools.Library/README.1ST @@ -1154,6 +1154,10 @@ Options: -bd=, --base-dat= Add a base DAT for replacing Add a DAT or folder of DATs to the base set to be used in item name replacement + + -uh, --update-hashes Update hashes along with the names + By default, only names are updated during the replacement. This + flag also allows updating of missing hashes at the same time. -gn=, --not-game= Filter by game name -ngn=, --game-name= Exclude by game name diff --git a/SabreTools/SabreTools.Help.cs b/SabreTools/SabreTools.Help.cs index d0d10e63..8fa26fde 100644 --- a/SabreTools/SabreTools.Help.cs +++ b/SabreTools/SabreTools.Help.cs @@ -1270,6 +1270,11 @@ namespace SabreTools "Add a base DAT for replacing", FeatureType.List, null)); + update["base-name"].AddFeature("update-hashes", new Feature( + new List() { "-uh", "--update-hashes" }, + "Update hashes along with the names", + FeatureType.Flag, + null)); update.AddFeature("reverse-base-name", new Feature( new List() { "-rbn", "--reverse-base-name" }, "Replace item names from base DATs in reverse", @@ -1280,6 +1285,11 @@ namespace SabreTools "Add a base DAT for replacing", FeatureType.List, null)); + update["reverse-base-name"].AddFeature("update-hashes", new Feature( + new List() { "-uh", "--update-hashes" }, + "Update hashes along with the names", + FeatureType.Flag, + null)); update.AddFeature("game-name", new Feature( new List() { "-gn", "--game-name" }, "Filter by game name", diff --git a/SabreTools/SabreTools.Inits.cs b/SabreTools/SabreTools.Inits.cs index 0cbbf83f..545d067b 100644 --- a/SabreTools/SabreTools.Inits.cs +++ b/SabreTools/SabreTools.Inits.cs @@ -233,6 +233,7 @@ namespace SabreTools /// True to clean the game names to WoD standard, false otherwise (default) /// True if we should remove non-ASCII characters from output, false otherwise (default) /// True if descriptions should be used as names, false otherwise (default) + /// True if hashes should be updated along with names, false otherwise [Only for base replacement] private static void InitUpdate( List inputPaths, List basePaths, @@ -254,7 +255,8 @@ namespace SabreTools string outDir, bool clean, bool remUnicode, - bool descAsName) + bool descAsName, + bool updateHashes) { // Normalize the extensions datHeader.AddExtension = (datHeader.AddExtension == "" || datHeader.AddExtension.StartsWith(".") @@ -302,7 +304,7 @@ namespace SabreTools DatFile userInputDat = new DatFile(datHeader); userInputDat.DetermineUpdateType(inputPaths, basePaths, outDir, updateMode, inplace, skip, bare, clean, - remUnicode, descAsName, filter, splitType); + remUnicode, descAsName, filter, splitType, updateHashes); } /// diff --git a/SabreTools/SabreTools.cs b/SabreTools/SabreTools.cs index 9d914d3b..60cd7595 100644 --- a/SabreTools/SabreTools.cs +++ b/SabreTools/SabreTools.cs @@ -93,7 +93,8 @@ namespace SabreTools showNodumpColumn = false, shortname = false, skip = false, - updateDat = false; + updateDat = false, + updateHashes = false; Hash omitFromScan = Hash.DeepHashes; // TODO: All instances of Hash.DeepHashes should be made into 0x0 eventually OutputFormat outputFormat = OutputFormat.Folder; SkipFileType skipFileType = SkipFileType.None; @@ -487,6 +488,9 @@ namespace SabreTools case "update-dat": updateDat = true; break; + case "update-hashes": + updateHashes = true; + break; case "exclude-of": datHeader.ExcludeOf = true; break; @@ -716,7 +720,7 @@ namespace SabreTools case "Update": VerifyInputs(inputs, feature); InitUpdate(inputs, basePaths, datHeader, updateMode, inplace, skip, removeDateFromAutomaticName, filter, - splitType, outDir, cleanGameNames, removeUnicode, descAsName); + splitType, outDir, cleanGameNames, removeUnicode, descAsName, updateHashes); break; // If we're using the verifier case "Verify":