Split DatFiles namespace

This commit is contained in:
Matt Nadareski
2020-12-10 23:24:09 -08:00
parent 24e73489d2
commit 24d4be0571
37 changed files with 426 additions and 368 deletions

View File

@@ -1,18 +1,13 @@
using System;
using System.Collections;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Xml.Serialization;
using SabreTools.Core;
using SabreTools.DatItems;
using SabreTools.IO;
using SabreTools.Logging;
using SabreTools.DatFiles.Reports;
using NaturalSort;
using Newtonsoft.Json;
@@ -282,7 +277,7 @@ namespace SabreTools.DatFiles
/// </summary>
/// <remarks>Special count only used by statistics output</remarks>
[JsonIgnore, XmlIgnore]
public long GameCount { get; private set; } = 0;
public long GameCount { get; set; } = 0;
/// <summary>
/// Total uncompressed size
@@ -374,8 +369,6 @@ namespace SabreTools.DatFiles
#endregion
#region Instance methods
#region Accessors
/// <summary>
@@ -462,6 +455,47 @@ namespace SabreTools.DatFiles
}
}
/// <summary>
/// Add statistics from another DatStats object
/// </summary>
/// <param name="stats">DatStats object to add from</param>
public void AddStatistics(ItemDictionary stats)
{
TotalCount += stats.Count;
ArchiveCount += stats.ArchiveCount;
BiosSetCount += stats.BiosSetCount;
ChipCount += stats.ChipCount;
DiskCount += stats.DiskCount;
MediaCount += stats.MediaCount;
ReleaseCount += stats.ReleaseCount;
RomCount += stats.RomCount;
SampleCount += stats.SampleCount;
GameCount += stats.GameCount;
TotalSize += stats.TotalSize;
// Individual hash counts
CRCCount += stats.CRCCount;
MD5Count += stats.MD5Count;
#if NET_FRAMEWORK
RIPEMD160Count += stats.RIPEMD160Count;
#endif
SHA1Count += stats.SHA1Count;
SHA256Count += stats.SHA256Count;
SHA384Count += stats.SHA384Count;
SHA512Count += stats.SHA512Count;
SpamSumCount += stats.SpamSumCount;
// Individual status counts
BaddumpCount += stats.BaddumpCount;
GoodCount += stats.GoodCount;
NodumpCount += stats.NodumpCount;
RemovedCount += stats.RemovedCount;
VerifiedCount += stats.VerifiedCount;
}
/// <summary>
/// Get if the file dictionary contains the key
/// </summary>
@@ -746,47 +780,6 @@ namespace SabreTools.DatFiles
}
}
/// <summary>
/// Add statistics from another DatStats object
/// </summary>
/// <param name="stats">DatStats object to add from</param>
private void AddStatistics(ItemDictionary stats)
{
TotalCount += stats.Count;
ArchiveCount += stats.ArchiveCount;
BiosSetCount += stats.BiosSetCount;
ChipCount += stats.ChipCount;
DiskCount += stats.DiskCount;
MediaCount += stats.MediaCount;
ReleaseCount += stats.ReleaseCount;
RomCount += stats.RomCount;
SampleCount += stats.SampleCount;
GameCount += stats.GameCount;
TotalSize += stats.TotalSize;
// Individual hash counts
CRCCount += stats.CRCCount;
MD5Count += stats.MD5Count;
#if NET_FRAMEWORK
RIPEMD160Count += stats.RIPEMD160Count;
#endif
SHA1Count += stats.SHA1Count;
SHA256Count += stats.SHA256Count;
SHA384Count += stats.SHA384Count;
SHA512Count += stats.SHA512Count;
SpamSumCount += stats.SpamSumCount;
// Individual status counts
BaddumpCount += stats.BaddumpCount;
GoodCount += stats.GoodCount;
NodumpCount += stats.NodumpCount;
RemovedCount += stats.RemovedCount;
VerifiedCount += stats.VerifiedCount;
}
/// <summary>
/// Ensure the key exists in the items dictionary
/// </summary>
@@ -1194,6 +1187,44 @@ namespace SabreTools.DatFiles
}
}
/// <summary>
/// Reset all statistics
/// </summary>
public void ResetStatistics()
{
TotalCount = 0;
ArchiveCount = 0;
BiosSetCount = 0;
ChipCount = 0;
DiskCount = 0;
MediaCount = 0;
ReleaseCount = 0;
RomCount = 0;
SampleCount = 0;
GameCount = 0;
TotalSize = 0;
CRCCount = 0;
MD5Count = 0;
#if NET_FRAMEWORK
RIPEMD160Count = 0;
#endif
SHA1Count = 0;
SHA256Count = 0;
SHA384Count = 0;
SHA512Count = 0;
SpamSumCount = 0;
BaddumpCount = 0;
GoodCount = 0;
NodumpCount = 0;
RemovedCount = 0;
VerifiedCount = 0;
}
/// <summary>
/// Get the highest-order Field value that represents the statistics
/// </summary>
@@ -1230,44 +1261,6 @@ namespace SabreTools.DatFiles
return Field.DatItem_CRC;
}
/// <summary>
/// Reset all statistics
/// </summary>
private void ResetStatistics()
{
TotalCount = 0;
ArchiveCount = 0;
BiosSetCount = 0;
ChipCount = 0;
DiskCount = 0;
MediaCount = 0;
ReleaseCount = 0;
RomCount = 0;
SampleCount = 0;
GameCount = 0;
TotalSize = 0;
CRCCount = 0;
MD5Count = 0;
#if NET_FRAMEWORK
RIPEMD160Count = 0;
#endif
SHA1Count = 0;
SHA256Count = 0;
SHA384Count = 0;
SHA512Count = 0;
SpamSumCount = 0;
BaddumpCount = 0;
GoodCount = 0;
NodumpCount = 0;
RemovedCount = 0;
VerifiedCount = 0;
}
/// <summary>
/// Sort the input DAT and get the key to be used by the item
/// </summary>
@@ -1335,216 +1328,5 @@ namespace SabreTools.DatFiles
}
#endregion
#endregion // Instance methods
#region Static methods
#region Writing
/// <summary>
/// Output the stats for a list of input dats as files in a human-readable format
/// </summary>
/// <param name="inputs">List of input files and folders</param>
/// <param name="reportName">Name of the output file</param>
/// <param name="single">True if single DAT stats are output, false otherwise</param>
/// <param name="baddumpCol">True if baddumps should be included in output, false otherwise</param>
/// <param name="nodumpCol">True if nodumps should be included in output, false otherwise</param>
/// <param name="statDatFormat" > Set the statistics output format to use</param>
public static void OutputStats(
List<string> inputs,
string reportName,
string outDir,
bool single,
bool baddumpCol,
bool nodumpCol,
StatReportFormat statDatFormat)
{
// If there's no output format, set the default
if (statDatFormat == StatReportFormat.None)
statDatFormat = StatReportFormat.Textfile;
// Get the proper output file name
if (string.IsNullOrWhiteSpace(reportName))
reportName = "report";
// Get the proper output directory name
outDir = outDir.Ensure();
// Get the dictionary of desired output report names
Dictionary<StatReportFormat, string> outputs = CreateOutStatsNames(outDir, statDatFormat, reportName);
// Make sure we have all files and then order them
List<ParentablePath> files = PathTool.GetFilesOnly(inputs);
files = files
.OrderBy(i => Path.GetDirectoryName(i.CurrentPath))
.ThenBy(i => Path.GetFileName(i.CurrentPath))
.ToList();
// Get all of the writers that we need
List<BaseReport> reports = outputs.Select(kvp => BaseReport.Create(kvp.Key, kvp.Value, baddumpCol, nodumpCol)).ToList();
// Write the header, if any
reports.ForEach(report => report.WriteHeader());
// Init all total variables
ItemDictionary totalStats = new ItemDictionary();
// Init directory-level variables
string lastdir = null;
string basepath = null;
ItemDictionary dirStats = new ItemDictionary();
// Now process each of the input files
foreach (ParentablePath file in files)
{
// Get the directory for the current file
string thisdir = Path.GetDirectoryName(file.CurrentPath);
basepath = Path.GetDirectoryName(Path.GetDirectoryName(file.CurrentPath));
// If we don't have the first file and the directory has changed, show the previous directory stats and reset
if (lastdir != null && thisdir != lastdir)
{
// Output separator if needed
reports.ForEach(report => report.WriteMidSeparator());
DatFile lastdirdat = DatFile.Create();
reports.ForEach(report => report.ReplaceStatistics($"DIR: {WebUtility.HtmlEncode(lastdir)}", dirStats.GameCount, dirStats));
reports.ForEach(report => report.Write());
// Write the mid-footer, if any
reports.ForEach(report => report.WriteFooterSeparator());
// Write the header, if any
reports.ForEach(report => report.WriteMidHeader());
// Reset the directory stats
dirStats.ResetStatistics();
}
staticLogger.Verbose($"Beginning stat collection for '{file.CurrentPath}'");
List<string> games = new List<string>();
DatFile datdata = Parser.CreateAndParse(file.CurrentPath);
datdata.Items.BucketBy(Field.Machine_Name, DedupeType.None, norename: true);
// Output single DAT stats (if asked)
staticLogger.User($"Adding stats for file '{file.CurrentPath}'\n");
if (single)
{
reports.ForEach(report => report.ReplaceStatistics(datdata.Header.FileName, datdata.Items.Keys.Count, datdata.Items));
reports.ForEach(report => report.Write());
}
// Add single DAT stats to dir
dirStats.AddStatistics(datdata.Items);
dirStats.GameCount += datdata.Items.Keys.Count();
// Add single DAT stats to totals
totalStats.AddStatistics(datdata.Items);
totalStats.GameCount += datdata.Items.Keys.Count();
// Make sure to assign the new directory
lastdir = thisdir;
}
// Output the directory stats one last time
reports.ForEach(report => report.WriteMidSeparator());
if (single)
{
reports.ForEach(report => report.ReplaceStatistics($"DIR: {WebUtility.HtmlEncode(lastdir)}", dirStats.GameCount, dirStats));
reports.ForEach(report => report.Write());
}
// Write the mid-footer, if any
reports.ForEach(report => report.WriteFooterSeparator());
// Write the header, if any
reports.ForEach(report => report.WriteMidHeader());
// Reset the directory stats
dirStats.ResetStatistics();
// Output total DAT stats
reports.ForEach(report => report.ReplaceStatistics("DIR: All DATs", totalStats.GameCount, totalStats));
reports.ForEach(report => report.Write());
// Output footer if needed
reports.ForEach(report => report.WriteFooter());
staticLogger.User($"{Environment.NewLine}Please check the log folder if the stats scrolled offscreen");
}
/// <summary>
/// Get the proper extension for the stat output format
/// </summary>
/// <param name="outDir">Output path to use</param>
/// <param name="statDatFormat">StatDatFormat to get the extension for</param>
/// <param name="reportName">Name of the input file to use</param>
/// <returns>Dictionary of output formats mapped to file names</returns>
private static Dictionary<StatReportFormat, string> CreateOutStatsNames(string outDir, StatReportFormat statDatFormat, string reportName, bool overwrite = true)
{
Dictionary<StatReportFormat, string> output = new Dictionary<StatReportFormat, string>();
// First try to create the output directory if we need to
if (!Directory.Exists(outDir))
Directory.CreateDirectory(outDir);
// Double check the outDir for the end delim
if (!outDir.EndsWith(Path.DirectorySeparatorChar.ToString()))
outDir += Path.DirectorySeparatorChar;
// For each output format, get the appropriate stream writer
output.Add(StatReportFormat.None, CreateOutStatsNamesHelper(outDir, ".null", reportName, overwrite));
if (statDatFormat.HasFlag(StatReportFormat.Textfile))
output.Add(StatReportFormat.Textfile, CreateOutStatsNamesHelper(outDir, ".txt", reportName, overwrite));
if (statDatFormat.HasFlag(StatReportFormat.CSV))
output.Add(StatReportFormat.CSV, CreateOutStatsNamesHelper(outDir, ".csv", reportName, overwrite));
if (statDatFormat.HasFlag(StatReportFormat.HTML))
output.Add(StatReportFormat.HTML, CreateOutStatsNamesHelper(outDir, ".html", reportName, overwrite));
if (statDatFormat.HasFlag(StatReportFormat.SSV))
output.Add(StatReportFormat.SSV, CreateOutStatsNamesHelper(outDir, ".ssv", reportName, overwrite));
if (statDatFormat.HasFlag(StatReportFormat.TSV))
output.Add(StatReportFormat.TSV, CreateOutStatsNamesHelper(outDir, ".tsv", reportName, overwrite));
return output;
}
/// <summary>
/// Help generating the outstats name
/// </summary>
/// <param name="outDir">Output directory</param>
/// <param name="extension">Extension to use for the file</param>
/// <param name="reportName">Name of the input file to use</param>
/// <param name="overwrite">True if we ignore existing files, false otherwise</param>
/// <returns>String containing the new filename</returns>
private static string CreateOutStatsNamesHelper(string outDir, string extension, string reportName, bool overwrite)
{
string outfile = outDir + reportName + extension;
outfile = outfile.Replace($"{Path.DirectorySeparatorChar}{Path.DirectorySeparatorChar}", Path.DirectorySeparatorChar.ToString());
if (!overwrite)
{
int i = 1;
while (File.Exists(outfile))
{
outfile = $"{outDir}{reportName}_{i}{extension}";
outfile = outfile.Replace($"{Path.DirectorySeparatorChar}{Path.DirectorySeparatorChar}", Path.DirectorySeparatorChar.ToString());
i++;
}
}
return outfile;
}
#endregion
#endregion // Static methods
}
}