diff --git a/RombaSharp/Partials/RombaSharp_Inits.cs b/RombaSharp/Partials/RombaSharp_Inits.cs index 2d74bcbf..fd367bff 100644 --- a/RombaSharp/Partials/RombaSharp_Inits.cs +++ b/RombaSharp/Partials/RombaSharp_Inits.cs @@ -174,7 +174,7 @@ namespace SabreTools // Create the sorting object to use and rebuild the needed files ArchiveScanLevel asl = ArchiveTools.GetArchiveScanLevelFromNumbers((onlyNeeded ? 0 : 1), (onlyNeeded ? 0 : 1), (onlyNeeded ? 0 : 1), (onlyNeeded ? 0 : 1)); - need.RebuildToOutput(onlyDirs, _depots.Keys.ToList()[0], _tmpdir, false /*quickScan*/, false /*date*/, + need.RebuildFromInputs(onlyDirs, _depots.Keys.ToList()[0], _tmpdir, false /*quickScan*/, false /*date*/, false /*delete*/, false /*inverse*/, OutputFormat.TorrentGzip, true /*romba*/, asl, false /*updateDat*/, null /*headerToCheckAgainst*/, 4 /*maxDegreeOfParallelism*/, _logger); } @@ -214,8 +214,8 @@ namespace SabreTools // Now scan all of those depots and rebuild ArchiveScanLevel asl = ArchiveTools.GetArchiveScanLevelFromNumbers(1, 1, 1, 1); - datFile.RebuildToOutput(onlineDepots, outputFolder, _tmpdir, true /*quickscan*/, false /*date*/, - false /*delete*/, false /*inverse*/, (copy ? OutputFormat.TorrentGzip : OutputFormat.TorrentZip), copy, asl, + datFile.RebuildFromDepot(onlineDepots, outputFolder, _tmpdir, false /*date*/, + false /*delete*/, false /*inverse*/, (copy ? OutputFormat.TorrentGzip : OutputFormat.TorrentZip), copy, false /*updateDat*/, null /*headerToCheckAgainst*/, 4 /*maxDegreeOfParallelism*/, _logger); } } diff --git a/SabreTools.Helper/Data/Build.cs b/SabreTools.Helper/Data/Build.cs index f509d780..e1b2908e 100644 --- a/SabreTools.Helper/Data/Build.cs +++ b/SabreTools.Helper/Data/Build.cs @@ -238,6 +238,26 @@ namespace SabreTools.Helper.Data helptext.Add(" -ud, --update-dat Output updated DAT to output directory"); helptext.Add(" -mt={4} Amount of threads to use (-1 unlimted)"); + // Sort Depot + helptext.Add(" -ssd, --sort Sort input files by a set of DATs"); + helptext.Add(" -dat= Input DAT to rebuild against"); + helptext.Add(" -out= Output directory"); + helptext.Add(" -t=, --temp= Set the temporary directory to use"); + helptext.Add(" -del, --delete Delete fully rebuilt input files"); + helptext.Add(" -in, --inverse Rebuild only files not in DAT"); + helptext.Add(" -ad, --add-date Add original dates from DAT, if possible"); + //helptext.Add(" -t7z Enable Torrent7z output"); + helptext.Add(" -tar Enable TAR output"); + helptext.Add(" -tgz Enable TorrentGZ output"); + helptext.Add(" -r, --romba Enable Romba depot dir output"); + //helptext.Add(" -tlrz Enable TorrentLRZ output"); + //helptext.Add(" -trar Enable TorrentRAR output"); + //helptext.Add(" -txz Enable TorrentXZ output"); + helptext.Add(" -tzip Enable TorrentZip output"); + helptext.Add(" -h=, --header= Set a header skipper to use, blank means all"); + helptext.Add(" -ud, --update-dat Output updated DAT to output directory"); + helptext.Add(" -mt={4} Amount of threads to use (-1 unlimted)"); + // Stats helptext.Add(" -st, --stats Get statistics on all input DATs"); helptext.Add(" -bc, --baddump-col Add baddump stats to output"); diff --git a/SabreTools.Helper/Dats/DatItem.cs b/SabreTools.Helper/Dats/DatItem.cs index 18f931ce..d81f81d1 100644 --- a/SabreTools.Helper/Dats/DatItem.cs +++ b/SabreTools.Helper/Dats/DatItem.cs @@ -248,10 +248,15 @@ namespace SabreTools.Helper.Dats // Get the correct dictionary based on what is available string key = ""; - if (_itemType == ItemType.Rom && ((Rom)this).CRC != null) + if (_itemType == ItemType.Rom && ((Rom)this).SHA1 != null) { - key = ((Rom)this).CRC; - datdata.BucketByCRC(false, logger, false); + key = ((Rom)this).SHA1; + datdata.BucketBySHA1(false, logger, false); + } + else if (_itemType == ItemType.Disk && ((Disk)this).SHA1 != null) + { + key = ((Disk)this).SHA1; + datdata.BucketBySHA1(false, logger, false); } else if (_itemType == ItemType.Rom && ((Rom)this).MD5 != null) { @@ -263,15 +268,10 @@ namespace SabreTools.Helper.Dats key = ((Disk)this).MD5; datdata.BucketByMD5(false, logger, false); } - else if (_itemType == ItemType.Rom && ((Rom)this).SHA1 != null) + else if (_itemType == ItemType.Rom && ((Rom)this).CRC != null) { - key = ((Rom)this).SHA1; - datdata.BucketBySHA1(false, logger, false); - } - else if (_itemType == ItemType.Disk && ((Disk)this).SHA1 != null) - { - key = ((Disk)this).SHA1; - datdata.BucketBySHA1(false, logger, false); + key = ((Rom)this).CRC; + datdata.BucketByCRC(false, logger, false); } else if (_itemType == ItemType.Rom) { @@ -323,10 +323,15 @@ namespace SabreTools.Helper.Dats // Get the correct dictionary based on what is available string key = ""; - if (_itemType == ItemType.Rom && ((Rom)this).CRC != null) + if (_itemType == ItemType.Rom && ((Rom)this).SHA1 != null) { - key = ((Rom)this).CRC; - datdata.BucketByCRC(false, logger, false); + key = ((Rom)this).SHA1; + datdata.BucketBySHA1(false, logger, false); + } + else if (_itemType == ItemType.Disk && ((Disk)this).SHA1 != null) + { + key = ((Disk)this).SHA1; + datdata.BucketBySHA1(false, logger, false); } else if (_itemType == ItemType.Rom && ((Rom)this).MD5 != null) { @@ -338,15 +343,10 @@ namespace SabreTools.Helper.Dats key = ((Disk)this).MD5; datdata.BucketByMD5(false, logger, false); } - else if (_itemType == ItemType.Rom && ((Rom)this).SHA1 != null) + else if (_itemType == ItemType.Rom && ((Rom)this).CRC != null) { - key = ((Rom)this).SHA1; - datdata.BucketBySHA1(false, logger, false); - } - else if (_itemType == ItemType.Disk && ((Disk)this).SHA1 != null) - { - key = ((Disk)this).SHA1; - datdata.BucketBySHA1(false, logger, false); + key = ((Rom)this).CRC; + datdata.BucketByCRC(false, logger, false); } else if (_itemType == ItemType.Rom) { diff --git a/SabreTools.Helper/Dats/Partials/DatFile.Rebuild.cs b/SabreTools.Helper/Dats/Partials/DatFile.Rebuild.cs index 7c2ffaf3..6f6fdc8c 100644 --- a/SabreTools.Helper/Dats/Partials/DatFile.Rebuild.cs +++ b/SabreTools.Helper/Dats/Partials/DatFile.Rebuild.cs @@ -20,6 +20,178 @@ namespace SabreTools.Helper.Dats { #region Rebuilding and Verifying [MODULAR DONE, FOR NOW] + /// + /// Process the DAT and find all matches in input files and folders assuming they're a depot + /// + /// List of input files/folders to check + /// Output directory to use to build to + /// Temporary directory for archive extraction + /// True if the date from the DAT should be used if available, false otherwise + /// True if input files should be deleted, false otherwise + /// True if the DAT should be used as a filter instead of a template, false otherwise + /// Output format that files should be written to + /// True if files should be output in Romba depot folders, false otherwise + /// True if the updated DAT should be output, 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 file and console output + /// True if rebuilding was a success, false otherwise + public bool RebuildFromDepot(List inputs, string outDir, string tempDir, bool date, bool delete, + bool inverse, OutputFormat outputFormat, bool romba, bool updateDat, string headerToCheckAgainst, + int maxDegreeOfParallelism, Logger logger) + { + #region Perform setup + + // If the DAT is not populated and inverse is not set, inform the user and quit + if (Count == 0 && !inverse) + { + logger.User("No entries were found to rebuild, exiting..."); + return false; + } + + // Check that the output directory exists + if (!Directory.Exists(outDir)) + { + Directory.CreateDirectory(outDir); + outDir = Path.GetFullPath(outDir); + } + + // Check the temp directory + if (String.IsNullOrEmpty(tempDir)) + { + tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + } + + // Then create or clean the temp directory + if (!Directory.Exists(tempDir)) + { + Directory.CreateDirectory(tempDir); + } + else + { + FileTools.CleanDirectory(tempDir); + } + + // Preload the Skipper list + int listcount = Skipper.List.Count; + + #endregion + + bool success = true; + + #region Rebuild from depots in order + + switch (outputFormat) + { + case OutputFormat.Folder: + logger.User("Rebuilding all files to directory"); + break; + case OutputFormat.TapeArchive: + logger.User("Rebuilding all files to TAR"); + break; + case OutputFormat.Torrent7Zip: + logger.User("Rebuilding all files to Torrent7Z"); + break; + case OutputFormat.TorrentGzip: + logger.User("Rebuilding all files to TorrentGZ"); + break; + case OutputFormat.TorrentLrzip: + logger.User("Rebuilding all files to TorrentLRZ"); + break; + case OutputFormat.TorrentRar: + logger.User("Rebuilding all files to TorrentRAR"); + break; + case OutputFormat.TorrentXZ: + logger.User("Rebuilding all files to TorrentXZ"); + break; + case OutputFormat.TorrentZip: + logger.User("Rebuilding all files to TorrentZip"); + break; + } + DateTime start = DateTime.Now; + + // Now loop through and get only directories from the input paths + List directories = new List(); + foreach (string input in inputs) + { + // Add to the list if the input is a directory + if (Directory.Exists(input)) + { + logger.Verbose("Adding depot: '" + input + "'"); + directories.Add(input); + } + } + + // If we don't have any directories, we want to exit + if (directories.Count == 0) + { + return success; + } + + // Now that we have a list of depots, we want to sort the input DAT by SHA-1 + BucketBySHA1(false, logger, output: false); + + // Then we want to loop through each of the hashes and see if we can rebuild + List hashes = Keys.ToList(); + foreach (string hash in hashes) + { + // Pre-empt any issues that could arise from string length + if (hash.Length != Constants.SHA1Length) + { + continue; + } + + logger.User("Checking hash '" + hash + "'"); + + // Get the extension path for the hash + string subpath = Path.Combine(hash.Substring(0, 2), hash.Substring(2, 2), hash.Substring(4, 2), hash.Substring(6, 2), hash + ".gz"); + + // Find the first depot that includes the hash + string foundpath = null; + foreach (string directory in directories) + { + if (File.Exists(Path.Combine(directory, subpath))) + { + foundpath = Path.Combine(directory, subpath); + break; + } + } + + // If we didn't find a path, then we continue + if (foundpath == null) + { + continue; + } + + // If we have a path, we want to try to get the rom information + Rom fileinfo = ArchiveTools.GetTorrentGZFileInfo(foundpath, logger); + + // If the file information is null, then we continue + if (fileinfo == null) + { + continue; + } + + // Otherwise, we rebuild that file to all locations that we need to + + RebuildIndividualFile(fileinfo, foundpath, outDir, tempDir, date, inverse, outputFormat, romba, updateDat, true /*isZip*/, headerToCheckAgainst, logger); + } + + logger.User("Rebuilding complete in: " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff")); + + #endregion + + // If we're updating the DAT, output to the rebuild directory + if (updateDat) + { + _fileName = "fixDAT_" + _fileName; + _name = "fixDAT_" + _name; + _description = "fixDAT_" + _description; + WriteToFile(outDir, logger); + } + + return success; + } + /// /// Process the DAT and find all matches in input files and folders /// @@ -37,7 +209,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 /// Logger object for file and console output /// True if rebuilding was a success, false otherwise - public bool RebuildToOutput(List inputs, string outDir, string tempDir, bool quickScan, bool date, + public bool RebuildFromInputs(List inputs, string outDir, string tempDir, bool quickScan, bool date, bool delete, bool inverse, OutputFormat outputFormat, bool romba, ArchiveScanLevel archiveScanLevel, bool updateDat, string headerToCheckAgainst, int maxDegreeOfParallelism, Logger logger) { @@ -117,8 +289,8 @@ namespace SabreTools.Helper.Dats // If the input is a file if (File.Exists(input)) { - logger.Verbose("Checking file: '" + input + "'"); - RebuildToOutputHelper(input, outDir, tempDir, quickScan, date, delete, inverse, + logger.User("Checking file: '" + input + "'"); + RebuildFromInputsHelper(input, outDir, tempDir, quickScan, date, delete, inverse, outputFormat, romba, archiveScanLevel, updateDat, headerToCheckAgainst, maxDegreeOfParallelism, logger); } @@ -128,8 +300,8 @@ namespace SabreTools.Helper.Dats logger.Verbose("Checking directory: '" + input + "'"); foreach (string file in Directory.EnumerateFiles(input, "*", SearchOption.AllDirectories)) { - logger.Verbose("Checking file: '" + file + "'"); - RebuildToOutputHelper(file, outDir, tempDir, quickScan, date, delete, inverse, + logger.User("Checking file: '" + file + "'"); + RebuildFromInputsHelper(file, outDir, tempDir, quickScan, date, delete, inverse, outputFormat, romba, archiveScanLevel, updateDat, headerToCheckAgainst, maxDegreeOfParallelism, logger); } } @@ -167,7 +339,7 @@ namespace SabreTools.Helper.Dats /// True if the updated DAT should be output, 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 file and console output - private void RebuildToOutputHelper(string file, string outDir, string tempDir, bool quickScan, bool date, + private void RebuildFromInputsHelper(string file, string outDir, string tempDir, bool quickScan, bool date, bool delete, bool inverse, OutputFormat outputFormat, bool romba, ArchiveScanLevel archiveScanLevel, bool updateDat, string headerToCheckAgainst, int maxDegreeOfParallelism, Logger logger) { @@ -193,7 +365,7 @@ namespace SabreTools.Helper.Dats if (shouldExternalProcess) { Rom rom = FileTools.GetFileInfo(file, logger, noMD5: quickScan, noSHA1: quickScan, header: headerToCheckAgainst); - usedExternally = RebuildToOutputIndividual(rom, file, outDir, tempSubDir, date, inverse, outputFormat, + usedExternally = RebuildIndividualFile(rom, file, outDir, tempSubDir, date, inverse, outputFormat, romba, updateDat, false /* isZip */, headerToCheckAgainst, logger); } @@ -208,7 +380,7 @@ namespace SabreTools.Helper.Dats foreach (Rom rom in extracted) { - usedInternally &= RebuildToOutputIndividual(rom, file, outDir, tempSubDir, date, inverse, outputFormat, + usedInternally &= RebuildIndividualFile(rom, file, outDir, tempSubDir, date, inverse, outputFormat, romba, updateDat, true /* isZip */, headerToCheckAgainst, logger); } } @@ -227,7 +399,7 @@ namespace SabreTools.Helper.Dats foreach (string entry in extracted) { Rom rom = FileTools.GetFileInfo(entry, logger, noMD5: quickScan, noSHA1: quickScan); - usedInternally &= RebuildToOutputIndividual(rom, entry, outDir, tempSubDir, date, inverse, outputFormat, + usedInternally &= RebuildIndividualFile(rom, entry, outDir, tempSubDir, date, inverse, outputFormat, romba, updateDat, false /* isZip */, headerToCheckAgainst, logger); } } @@ -235,7 +407,7 @@ namespace SabreTools.Helper.Dats else if (File.Exists(file)) { Rom rom = FileTools.GetFileInfo(file, logger, noMD5: quickScan, noSHA1: quickScan); - usedExternally = RebuildToOutputIndividual(rom, file, outDir, tempSubDir, date, inverse, outputFormat, + usedExternally = RebuildIndividualFile(rom, file, outDir, tempSubDir, date, inverse, outputFormat, romba, updateDat, false /* isZip */, headerToCheckAgainst, logger); } } @@ -280,7 +452,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 /// Logger object for file and console output /// True if the file was able to be rebuilt, false otherwise - private bool RebuildToOutputIndividual(Rom rom, string file, string outDir, string tempDir, bool date, + private bool RebuildIndividualFile(Rom rom, string file, string outDir, string tempDir, bool date, bool inverse, OutputFormat outputFormat, bool romba, bool updateDat, bool isZip, string headerToCheckAgainst, Logger logger) { // Set the output value diff --git a/SabreTools.Helper/README.1ST b/SabreTools.Helper/README.1ST index 1c2e3525..b0e4a4cb 100644 --- a/SabreTools.Helper/README.1ST +++ b/SabreTools.Helper/README.1ST @@ -487,6 +487,105 @@ Options: -upd, --update-dat Output updated DAT Once the files that were able to rebuilt are taken care of, a DAT of the files that could not be matched will be output to the output directory. + + -ssd, --sort-depot Sort input depots by a set of DATs + This feature allows the user to quickly rebuild based on a supplied DAT file(s). By + default all files will be rebuilt to uncompressed folders in the output directory. + This is different than the generic sort above as it requires that all inputs are + Romba-compatible depots. + + -dat= Name of the DAT to be used for the various options + The user-supplied DAT used to check which files need to be rebuilt. Multiple + occurrences of this flag are allowed. + + -out= Set the name of the output directory + This sets an output folder to be used when the files are created. If a path + is not defined, the application directory is used instead. + + -t=, --temp= Set the name of the temporary directory + Optionally, a temp folder can be supplied in the case the default temp directory + (inside the running folder) is not preferred. This is used for any operations that + require an archive to be extracted. + + -d, --delete Delete fully rebuilt input files + Optionally, the input files, once processed and fully matched, can be deleted. This + can be useful when the original file structure is no longer needed or if there is + limited space on the source drive. + + -in, --inverse Match files not in the DAT + Instead of the normal behavior of rebuilding using a DAT, this flag allows the user + to use the DAT as a filter instead. All files that are found in the DAT will be + skipped and everything else will be output in the selected format. + + -ad, --add-date Write dates for each file parsed, if available + If this flag is set, the the date in the DAT will be used for the output file + instead of the standard date and time for TorrentZip. This will technically + invalidate the output files as proper TorrentZip files because the date will not + match the standard. + + -t7z Enable Torrent 7zip output [NOT IMPLEMENTED] + Instead of ouputting the files to folder, files will be rebuilt to Torrent7Zip (T7Z) + files. This format is based on the LZMA container format 7zip, but with custom header + information. This is currently unused by any major application. + + -tar Enable Tape ARchive output + Instead of outputting the fiels to folder, files will be rebuilt to Tape ARchive (TAR) + files. This format is a standardized storage archive without any compression, usually + used with other compression formats around it. It is widely used in backup applications + and source code archives. + + -tgz Enable Torrent GZ output + Instead of outputting the files to folder, files will be rebuilt to TorrentGZ (TGZ) + files. This format is based on the GZip archive format, but with custom header + information and a file name replaced by the SHA-1 of the file inside. This is + primarily used by external tool Romba (https://github.com/uwedeportivo/romba), but + may be used more widely in the future. + + -r, --romba Enable Romba depot directory output + As an extension of the parent flag, this outputs the TGZ files into directories + based on the structure used by Romba. This uses nested folders using the first + 4 bytes of the SHA-1, 1 byte for each layer of the directory name. It also + includes two auxilary files, .romba_size and .romba_size.backup, that have the + compressed size of the folder inside for use with Romba. + + -tlrz Enable Torrent Long-Range Zip output [NOT IMPLEMENTED] + Instead of ouputting the files to folder, files will be rebuilt to Torrent Long-Range + Zip (TLRZ) files. This format is based on the LRZip file format as defined at + https://github.com/ckolivas/lrzip but with custom header information. This is currently + unused by any major application. + + -trar Enable Torrent RAR output [NOT IMPLEMENTED] + Instead of outputting files to folder, files will be rebuilt to Torrent RAR (TRAR) + files. This format is based on the RAR propietary format but with custom header + information. This is currently unused by any major application; + + -txz Enable Torrent XZ output [NOT IMPLEMENTED] + Instead of outputting files to folder, files will be rebuilt to Torrent XZ (TXZ) files. + This format is based on the LZMA container format XZ, but with custom header + information. This is currently unused by any major application; + + -tzip Enable Torrent Zip output + Instead of ouputting files to folder, files will be rebuilt to TorrentZip (TZ) files. + This format is based on the ZIP archive format, but with custom header information. + This is primarily used by external tool RomVault (http://www.romvault.com/) and is + already widely used. + + -h=, --header= Remove headers from hash calculations + If this is set, then all files that have copier headers that are detected will + have them removed from the hash calculation. This will allow for a headered collection + to be hashed without possibly variant information. If a particular header skipper is + defined, and that skipper exists, then it will be used instead of trying to find one + that matches. + + -mt={4} Amount of threads to use + Optionally, set the number of threads to use for the multithreaded operations. + The default is 4 threads; -1 means unlimited threads created. If the user specifies + that only 1 thread is to be used, it defaults to the original, serial implementation + of the DFD code. + + -upd, --update-dat Output updated DAT + Once the files that were able to rebuilt are taken care of, a DAT of the files + that could not be matched will be output to the output directory. -st, --stats Get statistics on all input DATs This will output by default the combined statistics for all input DAT files. The stats diff --git a/SabreTools/Partials/SabreTools.Inits.cs b/SabreTools/Partials/SabreTools.Inits.cs index 4a5b56e5..e3a55d68 100644 --- a/SabreTools/Partials/SabreTools.Inits.cs +++ b/SabreTools/Partials/SabreTools.Inits.cs @@ -332,7 +332,40 @@ namespace SabreTools } _logger.User("Populating complete in " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff")); - datdata.RebuildToOutput(inputs, outDir, tempDir, quickScan, date, delete, inverse, outputFormat, romba, asl, + datdata.RebuildFromInputs(inputs, outDir, tempDir, quickScan, date, delete, inverse, outputFormat, romba, asl, + updateDat, headerToCheckAgainst, maxDegreeOfParallelism, _logger); + } + + /// + /// Wrap sorting files from a depot using an input DAT + /// + /// Names of the DATs to compare against + /// List of input files/folders to check + /// Output directory to use to build to + /// Temporary directory for archive extraction + /// True if the date from the DAT should be used if available, false otherwise + /// True if input files should be deleted, false otherwise + /// True if the DAT should be used as a filter instead of a template, false otherwise + /// Output format that files should be written to + /// True if files should be output in Romba depot folders, false otherwise + /// True if the updated DAT should be output, false otherwise + /// 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 + private static void InitSortDepot(List datfiles, List inputs, string outDir, string tempDir, bool date, bool delete, + bool inverse, OutputFormat outputFormat, bool romba, bool updateDat, string headerToCheckAgainst, int maxDegreeOfParallelism) + { + DateTime start = DateTime.Now; + _logger.User("Populating internal DAT..."); + + // Add all of the input DATs into one huge internal DAT + DatFile datdata = new DatFile(); + foreach (string datfile in datfiles) + { + datdata.Parse(datfile, 99, 99, _logger, keep: true, softlist: true); + } + _logger.User("Populating complete in " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff")); + + datdata.RebuildFromDepot(inputs, outDir, tempDir, date, delete, inverse, outputFormat, romba, updateDat, headerToCheckAgainst, maxDegreeOfParallelism, _logger); } diff --git a/SabreTools/SabreTools.cs b/SabreTools/SabreTools.cs index 856b020b..7100bc73 100644 --- a/SabreTools/SabreTools.cs +++ b/SabreTools/SabreTools.cs @@ -58,14 +58,15 @@ namespace SabreTools datFromDir = false, extract = false, restore = false, - sort = false, // SimpleSort + sort = false, + sortDepot = false, splitByExt = false, splitByHash = false, splitByLevel = false, splitByType = false, stats = false, update = false, - verify = false; // SimpleSort + verify = false; // User flags bool addBlankFilesForEmptyFolder = false, @@ -75,17 +76,17 @@ namespace SabreTools copyFiles = false, datPrefix = false, dedup = false, - delete = false, // SimpleSort + delete = false, enableGzip = false, excludeOf = false, hashOnly = false, inplace = false, - inverse = false, // SimpleSort + inverse = false, merge = false, noMD5 = false, noSHA1 = false, parseArchivesAsFiles = false, - quickScan = false, // SimpleSort + quickScan = false, quotes = false, remext = false, removeDateFromAutomaticName = false, @@ -98,7 +99,7 @@ namespace SabreTools superdat = false, trim = false, skip = false, - updateDat = false, // SimpleSort + updateDat = false, usegame = true; bool? runnable = null; DatFormat datFormat = 0x0; @@ -108,11 +109,11 @@ namespace SabreTools StatDatFormat statDatFormat = 0x0; // User inputs - int gz = 2, // SimpleSort + int gz = 2, maxParallelism = 4, - rar = 2, // SimpleSort - sevenzip = 1, // SimpleSort - zip = 1; // SimpleSort + rar = 2, + sevenzip = 1, + zip = 1; long sgt = -1, slt = -1, seq = -1; @@ -142,7 +143,7 @@ namespace SabreTools url = null, version = null; List crc = new List(); - List datfiles = new List(); // SimpleSort + List datfiles = new List(); //List exta = new List(); //List extb = new List(); List gamename = new List(); @@ -205,6 +206,10 @@ namespace SabreTools case "--sort": sort = true; break; + case "-ssd": + case "--sort-depot": + sortDepot = true; + break; case "-st": case "--stats": stats = true; @@ -991,7 +996,7 @@ namespace SabreTools } // If none of the feature flags is enabled, show the help screen - if (!(datFromDir | extract | restore | sort | splitByExt | splitByHash | splitByLevel | splitByType | stats | update | verify)) + if (!(datFromDir | extract | restore | sort | sortDepot | splitByExt | splitByHash | splitByLevel | splitByType | stats | update | verify)) { _logger.Error("At least one feature switch must be enabled"); _logger.Close(); @@ -999,7 +1004,7 @@ namespace SabreTools } // If more than one switch is enabled, show the help screen - if (!(datFromDir ^ extract ^ restore ^ sort ^ splitByExt ^ splitByHash ^ splitByLevel ^ splitByType ^ stats ^ update ^ verify)) + if (!(datFromDir ^ extract ^ restore ^ sort ^ sortDepot ^ splitByExt ^ splitByHash ^ splitByLevel ^ splitByType ^ stats ^ update ^ verify)) { _logger.Error("Only one feature switch is allowed at a time"); _logger.Close(); @@ -1065,6 +1070,13 @@ namespace SabreTools outputFormat, romba, sevenzip, gz, rar, zip, updateDat, header, maxParallelism); } + // If we're using the sorter from depot + else if (sortDepot) + { + InitSortDepot(datfiles, inputs, outDir, tempDir, addFileDates, delete, inverse, + outputFormat, romba, updateDat, header, maxParallelism); + } + // Split a DAT by extension else if (splitByExt) {