diff --git a/SabreTools.Helper/Data/Build.cs b/SabreTools.Helper/Data/Build.cs index 5df6ea7e..1a80fb86 100644 --- a/SabreTools.Helper/Data/Build.cs +++ b/SabreTools.Helper/Data/Build.cs @@ -143,6 +143,7 @@ namespace SabreTools.Helper helptext.Add(" -out= Output directory"); helptext.Add(" -hs, --hash-split Split a DAT or folder by best-available hashes"); helptext.Add(" -out= Output directory"); + helptext.Add(" -html, --html Write statistics on all input DATs to HTML"); helptext.Add(" -st, --stats Get statistics on all input DATs"); helptext.Add(" -si, --single Show individual statistics"); helptext.Add(" -ts, --type-split Split a DAT or folder by file types (rom/disk)"); diff --git a/SabreTools.Helper/Objects/Dat/DatFile.cs b/SabreTools.Helper/Objects/Dat/DatFile.cs index a6305b39..92629b6b 100644 --- a/SabreTools.Helper/Objects/Dat/DatFile.cs +++ b/SabreTools.Helper/Objects/Dat/DatFile.cs @@ -4361,6 +4361,38 @@ namespace SabreTools.Helper ", false); } + /// + /// Output the stats for the Dat in a human-readable HTML format + /// + /// StreamWriter representing the output file or stream for the statistics + /// Logger object for file and console writing + /// True if numbers should be recalculated for the DAT, false otherwise (default) + /// Number of games to use, -1 means recalculate games (default) + public void OutputHTMLStats(StreamWriter sw, Logger logger, bool recalculate = false, long game = -1) + { + // If we're supposed to recalculate the statistics, do so + if (recalculate) + { + RecalculateStats(); + } + + BucketByGame(false, true, logger, false); + if (TotalSize < 0) + { + TotalSize = Int64.MaxValue + TotalSize; + } + sw.Write("\t\t\t" + FileName + "" + + "" + Style.GetBytesReadable(TotalSize) + "" + + "" + (game == -1 ? Files.Count : game) + "" + + "" + RomCount + "" + + "" + DiskCount + "" + + "" + CRCCount + "" + + "" + MD5Count + "" + + "" + SHA1Count + "" + + "" + NodumpCount + "" + + "\n"); + } + #endregion #endregion // Instance Methods @@ -5106,6 +5138,104 @@ namespace SabreTools.Helper Please check the log folder if the stats scrolled offscreen", false); } + /// + /// Output the stats for a list of input dats as files in a human-readable HTML format + /// + /// List of input files and folders + /// True if single DAT stats are output, false otherwise + /// Logger object for file and console output + /// Logger object for file and console output (statistics) + public static void OutputHTMLStats(List inputs, Logger logger) + { + StreamWriter sw = new StreamWriter(File.OpenWrite("report.html")); + + // Make sure we have all files + List newinputs = new List(); + foreach (string input in inputs) + { + if (File.Exists(input)) + { + newinputs.Add(input); + } + if (Directory.Exists(input)) + { + foreach (string file in Directory.GetFiles(input, "*", SearchOption.AllDirectories)) + { + newinputs.Add(file); + } + } + } + + // Write the HTML header + sw.Write(@" + +
+ DAT Statistics Report +
+ + + " ++ "\n"); + + // Init all total variables + long totalSize = 0; + long totalGame = 0; + long totalRom = 0; + long totalDisk = 0; + long totalCRC = 0; + long totalMD5 = 0; + long totalSHA1 = 0; + long totalNodump = 0; + + /// Now process each of the input files + foreach (string filename in newinputs) + { + logger.Verbose("Beginning stat collection for '" + filename + "'", false); + List games = new List(); + DatFile datdata = new DatFile(); + datdata.Parse(filename, 0, 0, logger); + datdata.BucketByGame(false, true, logger, false); + + // Output single DAT stats (if asked) + logger.User("Adding stats for file '" + filename + "'\n", false); + datdata.OutputHTMLStats(sw, logger); + + // Add single DAT stats to totals + totalSize += datdata.TotalSize; + totalGame += datdata.Files.Count; + totalRom += datdata.RomCount; + totalDisk += datdata.DiskCount; + totalCRC += datdata.CRCCount; + totalMD5 += datdata.MD5Count; + totalSHA1 += datdata.SHA1Count; + totalNodump += datdata.NodumpCount; + } + + sw.Write(""); + + // Output total DAT stats + DatFile totaldata = new DatFile + { + FileName = "Totals", + TotalSize = totalSize, + RomCount = totalRom, + DiskCount = totalDisk, + CRCCount = totalCRC, + MD5Count = totalMD5, + SHA1Count = totalSHA1, + NodumpCount = totalNodump, + }; + totaldata.OutputHTMLStats(sw, logger, game: totalGame); + + // Write HTML footer + sw.Write(@"
File NameTotal SizeGamesRomsDisks# with CRC# with MD5# with SHA-1Nodumps
+ + +"); + sw.Flush(); + sw.Dispose(); + } + #endregion #endregion // Static Methods diff --git a/SabreTools.Helper/README.1ST b/SabreTools.Helper/README.1ST index f2f51f16..7e5a4e67 100644 --- a/SabreTools.Helper/README.1ST +++ b/SabreTools.Helper/README.1ST @@ -310,6 +310,18 @@ Options: This should only be used if one of the inputs starts with a flag or another already defined input. + -html, --html Get statistics on all input DATs written to HTML + This will output by default the combined statistics for all input DAT files. The stats + that are outputted are as follows: + - Total uncompressed size + - Number of games found + - Number of roms found + - Number of disks found + - Roms that include a CRC + - Roms that include a MD5 + - Roms that include a SHA-1 + - Roms with Nodump status + -st, --stats Get statistics on all input DATs This will output by default the combined statistics for all input DAT files. The stats that are outputted are as follows: diff --git a/SabreTools/Partials/SabreTools_Inits.cs b/SabreTools/Partials/SabreTools_Inits.cs index 888350c9..0e261312 100644 --- a/SabreTools/Partials/SabreTools_Inits.cs +++ b/SabreTools/Partials/SabreTools_Inits.cs @@ -213,8 +213,7 @@ namespace SabreTools /// Input file or folder names /// False if we're extracting headers (default), true if we're restoring them /// Output directory to write new files to, blank defaults to rom folder - /// Logger object for file and console output - private static void InitHeaderer(List inputs, bool restore, string outDir, Logger logger) + private static void InitHeaderer(List inputs, bool restore, string outDir) { foreach (string input in inputs) { @@ -222,11 +221,11 @@ namespace SabreTools { if (restore) { - FileTools.RestoreHeader(input, outDir, logger); + FileTools.RestoreHeader(input, outDir, _logger); } else { - FileTools.DetectSkipperAndTransform(input, outDir, logger); + FileTools.DetectSkipperAndTransform(input, outDir, _logger); } } else if (Directory.Exists(input)) @@ -235,17 +234,26 @@ namespace SabreTools { if (restore) { - FileTools.RestoreHeader(sub, outDir, logger); + FileTools.RestoreHeader(sub, outDir, _logger); } else { - FileTools.DetectSkipperAndTransform(sub, outDir, logger); + FileTools.DetectSkipperAndTransform(sub, outDir, _logger); } } } } } + /// + /// Wrap getting statistics on a DAT or folder of DATs to HTML + /// + /// List of inputs to be used + private static void InitHTMLStats(List inputs) + { + DatFile.OutputHTMLStats(inputs, _logger); + } + /// /// Wrap sorting files using an input DAT /// diff --git a/SabreTools/SabreTools.cs b/SabreTools/SabreTools.cs index 365c9c66..a18fbb96 100644 --- a/SabreTools/SabreTools.cs +++ b/SabreTools/SabreTools.cs @@ -62,6 +62,7 @@ namespace SabreTools forceunpack = false, hashsplit = false, headerer = false, + html = false, inplace = false, merge = false, noMD5 = false, @@ -212,6 +213,10 @@ namespace SabreTools case "--hash-split": hashsplit = true; break; + case "-html": + case "--html": + html = true; + break; case "-ip": case "--inplace": inplace = true; @@ -518,7 +523,7 @@ namespace SabreTools } // If more than one switch is enabled, show the help screen - if (!(extsplit ^ hashsplit ^ headerer ^ (datfromdir || merge || diffMode != 0 || update + if (!(extsplit ^ hashsplit ^ headerer ^ html ^ (datfromdir || merge || diffMode != 0 || update || outputFormat != 0 || tsv != null|| trim) ^ rem ^ stats ^ typesplit)) { _logger.Error("Only one feature switch is allowed at a time"); @@ -528,7 +533,7 @@ namespace SabreTools } // If a switch that requires a filename is set and no file is, show the help screen - if (inputs.Count == 0 && (datfromdir || extsplit || hashsplit || headerer + if (inputs.Count == 0 && (datfromdir || extsplit || hashsplit || headerer || html || (merge || diffMode != 0 || update || outputFormat != 0 || tsv != null) || stats || trim || typesplit)) { _logger.Error("This feature requires at least one input"); @@ -561,7 +566,13 @@ namespace SabreTools // If we're in headerer mode else if (headerer) { - InitHeaderer(inputs, restore, outDir, _logger); + InitHeaderer(inputs, restore, outDir); + } + + // Get statistics on input files to HTML + else if (html) + { + InitHTMLStats(inputs); } // Get statistics on input files