[SabreTools] Merge MergeDiff into Update

This commit is contained in:
Matt Nadareski
2016-06-20 15:17:58 -07:00
parent 81434c3b4e
commit 86e3726c06
5 changed files with 434 additions and 573 deletions

View File

@@ -1574,9 +1574,14 @@ namespace SabreTools.Helper
/// <summary> /// <summary>
/// Convert, update, and filter a DAT file /// Convert, update, and filter a DAT file
/// </summary> /// </summary>
/// <param name="inputFileName">Name of the input file or folder</param> /// <param name="inputFileNames">Names of the input files and/or folders</param>
/// <param name="datdata">User specified inputs contained in a DatData object</param> /// <param name="datdata">User specified inputs contained in a DatData object</param>
/// <param name="outputDirectory">Optional param for output directory</param> /// <param name="outputDirectory">Optional param for output directory</param>
/// <param name="merge">True if input files should be merged into a single file, false otherwise</param>
/// <param name="diff">True if the input files should be diffed with each other, false otherwise</param>
/// <param name="cascade">True if the diffed files should be cascade diffed, false otherwise</param>
/// <param name="inplace">True if the cascade-diffed files should overwrite their inputs, false otherwise</param>
/// <param name="bare">True if the date should not be appended to the default name, false otherwise [OBSOLETE]</param>
/// <param name="clean">True to clean the game names to WoD standard, false otherwise (default)</param> /// <param name="clean">True to clean the game names to WoD standard, false otherwise (default)</param>
/// <param name="gamename">Name of the game to match (can use asterisk-partials)</param> /// <param name="gamename">Name of the game to match (can use asterisk-partials)</param>
/// <param name="romname">Name of the rom to match (can use asterisk-partials)</param> /// <param name="romname">Name of the rom to match (can use asterisk-partials)</param>
@@ -1589,59 +1594,139 @@ namespace SabreTools.Helper
/// <param name="sha1">SHA-1 of the rom to match (can use asterisk-partials)</param> /// <param name="sha1">SHA-1 of the rom to match (can use asterisk-partials)</param>
/// <param name="nodump">Select roms with nodump status as follows: null (match all), true (match Nodump only), false (exclude Nodump)</param> /// <param name="nodump">Select roms with nodump status as follows: null (match all), true (match Nodump only), false (exclude Nodump)</param>
/// <param name="logger">Logging object for console and file output</param> /// <param name="logger">Logging object for console and file output</param>
public static void Update(string inputFileName, Dat datdata, string outputDirectory, bool clean, string gamename, string romname, public static void Update(List<string> inputFileNames, Dat datdata, string outputDirectory, bool merge, bool diff, bool cascade, bool inplace,
string romtype, long sgt, long slt, long seq, string crc, string md5, string sha1, bool? nodump, Logger logger) bool bare, bool clean, string gamename, string romname, string romtype, long sgt, long slt, long seq, string crc, string md5,
string sha1, bool? nodump, Logger logger)
{ {
// Clean the input string // If we're in merging or diffing mode, use the full list of inputs
if (inputFileName != "") if (merge || diff)
{ {
inputFileName = Path.GetFullPath(inputFileName); // Create a dictionary of all ROMs from the input DATs
} datdata.FileName = datdata.Description;
Dat userData;
List<Dat> datHeaders = PopulateUserData(inputFileNames, inplace, clean, outputDirectory, datdata, out userData, logger);
if (File.Exists(inputFileName)) // Modify the Dictionary if necessary and output the results
{ if (diff && !cascade)
logger.User("Processing \"" + Path.GetFileName(inputFileName) + "\"");
datdata = Parse(inputFileName, 0, 0, datdata, logger, true, clean);
datdata = Filter(datdata, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, logger);
// If the extension matches, append ".new" to the filename
string extension = (datdata.OutputFormat == OutputFormat.Xml || datdata.OutputFormat == OutputFormat.SabreDat ? ".xml" : ".dat");
if (outputDirectory == "" && Path.GetExtension(inputFileName) == extension)
{ {
datdata.FileName += ".new"; DiffNoCascade(outputDirectory, userData, inputFileNames, logger);
} }
// If we're in cascade and diff, output only cascaded diffs
Output.WriteDatfile(datdata, (outputDirectory == "" ? Path.GetDirectoryName(inputFileName) : outputDirectory), logger); else if (diff && cascade)
}
else if (Directory.Exists(inputFileName))
{
inputFileName = Path.GetFullPath(inputFileName) + Path.DirectorySeparatorChar;
foreach (string file in Directory.EnumerateFiles(inputFileName, "*", SearchOption.AllDirectories))
{ {
logger.User("Processing \"" + Path.GetFullPath(file).Remove(0, inputFileName.Length) + "\""); DiffCascade(outputDirectory, inplace, userData, inputFileNames, datHeaders, logger);
Dat innerDatdata = (Dat)datdata.Clone(); }
innerDatdata.Roms = null; // Output all entries with user-defined merge
innerDatdata = Parse(file, 0, 0, innerDatdata, logger, true, clean); else
innerDatdata = Filter(innerDatdata, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, logger); {
MergeNoDiff(outputDirectory, userData, inputFileNames, datHeaders, logger);
// If the extension matches, append ".new" to the filename
string extension = (innerDatdata.OutputFormat == OutputFormat.Xml || innerDatdata.OutputFormat == OutputFormat.SabreDat ? ".xml" : ".dat");
if (outputDirectory == "" && Path.GetExtension(file) == extension)
{
innerDatdata.FileName += ".new";
}
Output.WriteDatfile(innerDatdata, (outputDirectory == "" ? Path.GetDirectoryName(file) : outputDirectory + Path.GetDirectoryName(file).Remove(0, inputFileName.Length - 1)), logger);
} }
} }
// Otherwise, loop through all of the inputs individually
else else
{ {
logger.Error("I'm sorry but " + inputFileName + " doesn't exist!"); for (int i = 0; i < inputFileNames.Count; i++)
{
string inputFileName = inputFileNames[i];
// Clean the input string
if (inputFileName != "")
{
inputFileName = Path.GetFullPath(inputFileName);
}
if (File.Exists(inputFileName))
{
logger.User("Processing \"" + Path.GetFileName(inputFileName) + "\"");
datdata = Parse(inputFileName, 0, 0, datdata, logger, true, clean);
datdata = Filter(datdata, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, logger);
// If the extension matches, append ".new" to the filename
string extension = (datdata.OutputFormat == OutputFormat.Xml || datdata.OutputFormat == OutputFormat.SabreDat ? ".xml" : ".dat");
if (outputDirectory == "" && Path.GetExtension(inputFileName) == extension)
{
datdata.FileName += ".new";
}
Output.WriteDatfile(datdata, (outputDirectory == "" ? Path.GetDirectoryName(inputFileName) : outputDirectory), logger);
}
else if (Directory.Exists(inputFileName))
{
inputFileName = Path.GetFullPath(inputFileName) + Path.DirectorySeparatorChar;
foreach (string file in Directory.EnumerateFiles(inputFileName, "*", SearchOption.AllDirectories))
{
logger.User("Processing \"" + Path.GetFullPath(file).Remove(0, inputFileName.Length) + "\"");
Dat innerDatdata = (Dat)datdata.Clone();
innerDatdata.Roms = null;
innerDatdata = Parse(file, 0, 0, innerDatdata, logger, true, clean);
innerDatdata = Filter(innerDatdata, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, logger);
// If the extension matches, append ".new" to the filename
string extension = (innerDatdata.OutputFormat == OutputFormat.Xml || innerDatdata.OutputFormat == OutputFormat.SabreDat ? ".xml" : ".dat");
if (outputDirectory == "" && Path.GetExtension(file) == extension)
{
innerDatdata.FileName += ".new";
}
Output.WriteDatfile(innerDatdata, (outputDirectory == "" ? Path.GetDirectoryName(file) : outputDirectory + Path.GetDirectoryName(file).Remove(0, inputFileName.Length - 1)), logger);
}
}
else
{
logger.Error("I'm sorry but " + inputFileName + " doesn't exist!");
}
}
} }
return; return;
} }
/// <summary>
/// Populate the user DatData object from the input files
/// </summary>
/// <param name="userData">Output user DatData object to output</param>
/// <returns>List of DatData objects representing headers</returns>
private static List<Dat> PopulateUserData(List<string> inputs, bool inplace, bool clean, string outdir, Dat inputDat, out Dat userData, Logger logger)
{
List<Dat> datHeaders = new List<Dat>();
int i = 0;
userData = new Dat
{
Roms = new Dictionary<string, List<Rom>>(),
MergeRoms = inputDat.MergeRoms,
};
foreach (string input in inputs)
{
logger.User("Adding DAT: " + input.Split('¬')[0]);
userData = DatTools.Parse(input.Split('¬')[0], i, 0, userData, logger, true, clean);
i++;
// If we are in inplace mode or redirecting output, save the DAT data
if (inplace || !String.IsNullOrEmpty(outdir))
{
datHeaders.Add((Dat)userData.CloneHeader());
// Reset the header values so the next can be captured
userData.FileName = "";
userData.Name = "";
userData.Description = "";
userData.Version = "";
userData.Date = "";
userData.Category = "";
userData.Author = "";
userData.ForcePacking = ForcePacking.None;
userData.OutputFormat = OutputFormat.None;
userData.Type = "";
}
}
// Set the output values
userData = (Dat)inputDat.CloneHeader();
return datHeaders;
}
/// <summary> /// <summary>
/// Filter an input DAT file /// Filter an input DAT file
/// </summary> /// </summary>
@@ -1809,5 +1894,253 @@ namespace SabreTools.Helper
return datdata; return datdata;
} }
/// <summary>
/// Output non-cascading diffs
/// </summary>
/// <param name="userData">Main DatData to draw information from</param>
public static void DiffNoCascade(string outdir, Dat userData, List<string> inputs, Logger logger)
{
DateTime start = DateTime.Now;
logger.User("Initializing all output DATs");
// Don't have External dupes
string post = " (No Duplicates)";
Dat outerDiffData = (Dat)userData.CloneHeader();
outerDiffData.FileName += post;
outerDiffData.Name += post;
outerDiffData.Description += post;
// Have External dupes
post = " (Duplicates)";
Dat dupeData = (Dat)userData.CloneHeader();
dupeData.FileName += post;
dupeData.Name += post;
dupeData.Description += post;
// Create a list of DatData objects representing individual output files
List<Dat> outDats = new List<Dat>();
// Loop through each of the inputs and get or create a new DatData object
for (int j = 0; j < inputs.Count; j++)
{
post = " (" + Path.GetFileNameWithoutExtension(inputs[j].Split('¬')[0]) + " Only)";
Dat diffData = (Dat)userData.CloneHeader();
diffData.FileName += post;
diffData.Name += post;
diffData.Description += post;
outDats.Add(diffData);
}
logger.User("Initializing complete in " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff"));
// Now, loop through the dictionary and populate the correct DATs
start = DateTime.Now;
logger.User("Populating all output DATs");
List<string> keys = userData.Roms.Keys.ToList();
foreach (string key in keys)
{
List<Rom> roms = RomTools.Merge(userData.Roms[key], logger);
if (roms != null && roms.Count > 0)
{
foreach (Rom rom in roms)
{
// No duplicates
if (rom.Dupe < DupeType.ExternalHash)
{
// Individual DATs that are output
if (outDats[rom.Metadata.SystemID].Roms.ContainsKey(key))
{
outDats[rom.Metadata.SystemID].Roms[key].Add(rom);
}
else
{
List<Rom> tl = new List<Rom>();
tl.Add(rom);
outDats[rom.Metadata.SystemID].Roms.Add(key, tl);
}
// Merged no-duplicates DAT
Rom newrom = rom;
newrom.Game += " (" + Path.GetFileNameWithoutExtension(inputs[newrom.Metadata.SystemID].Split('¬')[0]) + ")";
if (outerDiffData.Roms.ContainsKey(key))
{
outerDiffData.Roms[key].Add(newrom);
}
else
{
List<Rom> tl = new List<Rom>();
tl.Add(rom);
outerDiffData.Roms.Add(key, tl);
}
}
// Duplicates only
if (rom.Dupe >= DupeType.ExternalHash)
{
Rom newrom = rom;
newrom.Game += " (" + Path.GetFileNameWithoutExtension(inputs[newrom.Metadata.SystemID].Split('¬')[0]) + ")";
if (dupeData.Roms.ContainsKey(key))
{
dupeData.Roms[key].Add(newrom);
}
else
{
List<Rom> tl = new List<Rom>();
tl.Add(rom);
dupeData.Roms.Add(key, tl);
}
}
}
}
}
logger.User("Populating complete in " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff"));
// Finally, loop through and output each of the DATs
start = DateTime.Now;
logger.User("Outputting all created DATs");
// Output the difflist (a-b)+(b-a) diff
Output.WriteDatfile(outerDiffData, outdir, logger);
// Output the (ab) diff
Output.WriteDatfile(dupeData, outdir, logger);
// Output the individual (a-b) DATs
for (int j = 0; j < inputs.Count; j++)
{
// If we have an output directory set, replace the path
string path = outdir + (Path.GetDirectoryName(inputs[j].Split('¬')[0]).Remove(0, inputs[j].Split('¬')[1].Length));
// If we have more than 0 roms, output
if (outDats[j].Roms.Count > 0)
{
Output.WriteDatfile(outDats[j], path, logger);
}
}
logger.User("Outputting complete in " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff"));
}
/// <summary>
/// Output cascading diffs
/// </summary>
/// <param name="userData">Main DatData to draw information from</param>
/// <param name="datHeaders">Dat headers used optionally</param>
public static void DiffCascade(string outdir, bool inplace, Dat userData, List<string> inputs, List<Dat> datHeaders, Logger logger)
{
string post = "";
// Create a list of DatData objects representing output files
List<Dat> outDats = new List<Dat>();
// Loop through each of the inputs and get or create a new DatData object
DateTime start = DateTime.Now;
logger.User("Initializing all output DATs");
for (int j = 0; j < inputs.Count; j++)
{
post = " (" + Path.GetFileNameWithoutExtension(inputs[j].Split('¬')[0]) + " Only)";
Dat diffData;
// If we're in inplace mode, take the appropriate DatData object already stored
if (inplace || !String.IsNullOrEmpty(outdir))
{
diffData = datHeaders[j];
}
else
{
diffData = (Dat)userData.CloneHeader();
diffData.FileName += post;
diffData.Name += post;
diffData.Description += post;
}
outDats.Add(diffData);
}
logger.User("Initializing complete in " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff"));
// Now, loop through the dictionary and populate the correct DATs
start = DateTime.Now;
logger.User("Populating all output DATs");
List<string> keys = userData.Roms.Keys.ToList();
foreach (string key in keys)
{
List<Rom> roms = RomTools.Merge(userData.Roms[key], logger);
if (roms != null && roms.Count > 0)
{
foreach (Rom rom in roms)
{
if (outDats[rom.Metadata.SystemID].Roms.ContainsKey(key))
{
outDats[rom.Metadata.SystemID].Roms[key].Add(rom);
}
else
{
List<Rom> tl = new List<Rom>();
tl.Add(rom);
outDats[rom.Metadata.SystemID].Roms.Add(key, tl);
}
}
}
}
logger.User("Populating complete in " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff"));
// Finally, loop through and output each of the DATs
start = DateTime.Now;
logger.User("Outputting all created DATs");
for (int j = 0; j < inputs.Count; j++)
{
// If we have an output directory set, replace the path
string path = "";
if (inplace)
{
path = Path.GetDirectoryName(inputs[j].Split('¬')[0]);
}
else if (!String.IsNullOrEmpty(outdir))
{
path = outdir + (Path.GetDirectoryName(inputs[j].Split('¬')[0]).Remove(0, inputs[j].Split('¬')[1].Length));
}
// If we have more than 0 roms, output
if (outDats[j].Roms.Count > 0)
{
Output.WriteDatfile(outDats[j], path, logger);
}
}
logger.User("Outputting complete in " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff"));
}
/// <summary>
/// Output user defined merge
/// </summary>
/// <param name="userData">Main DatData to draw information from</param>
/// <param name="datHeaders">Dat headers used optionally</param>
public static void MergeNoDiff(string outdir, Dat userData, List<string> inputs, List<Dat> datHeaders, Logger logger)
{
// If we're in SuperDAT mode, prefix all games with their respective DATs
if (userData.Type == "SuperDAT")
{
List<string> keys = userData.Roms.Keys.ToList();
foreach (string key in keys)
{
List<Rom> newroms = new List<Rom>();
foreach (Rom rom in userData.Roms[key])
{
Rom newrom = rom;
string filename = inputs[newrom.Metadata.SystemID].Split('¬')[0];
string rootpath = inputs[newrom.Metadata.SystemID].Split('¬')[1];
rootpath += (rootpath == "" ? "" : Path.DirectorySeparatorChar.ToString());
filename = filename.Remove(0, rootpath.Length);
newrom.Game = Path.Combine(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename), newrom.Game);
newroms.Add(newrom);
}
userData.Roms[key] = newroms;
}
}
Output.WriteDatfile(userData, outdir, logger);
}
} }
} }

View File

@@ -1,442 +0,0 @@
using SabreTools.Helper;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace SabreTools
{
public class MergeDiff
{
// Listing related variables
private List<String> _inputs;
// User specified flags
private bool _diff;
private bool _dedup;
private bool _bare;
private bool _forceunpack;
private bool _old;
private bool _superdat;
private bool _cascade;
private bool _inplace;
private bool _clean;
// User specified strings
private string _name;
private string _desc;
private string _cat;
private string _version;
private string _author;
private string _outdir;
// Other required variables
private string _date = DateTime.Now.ToString("yyyy-MM-dd");
private Logger _logger;
/// <summary>
/// Create a new MergeDAT object
/// </summary>
/// <param name="inputs">A List of Strings representing the DATs or DAT folders to be merged</param>
/// <param name="name">Internal name of the DAT</param>
/// <param name="desc">Description and external name of the DAT</param>
/// <param name="cat">Category for the DAT</param>
/// <param name="version">Version of the DAT</param>
/// <param name="author">Author of the DAT</param>
/// <param name="ad">True if all diff variants should be outputted, false otherwise</param>
/// <param name="diff">True if a DiffDat of all inputs is wanted, false otherwise</param>
/// <param name="dedup">True if the outputted file should remove duplicates, false otherwise</param>
/// <param name="bare">True if the date should be omitted from the DAT, false otherwise</param>
/// <param name="forceunpack">True if the forcepacking="unzip" tag is to be added, false otherwise</param>
/// <param name="old">True if a old-style DAT should be output, false otherwise</param>
/// <param name="superdat">True if DATs should be parsed into SuperDAT format, false otherwise</param>
/// <param name="cascade">True if the outputted diffs should be cascaded, false otherwise</param>
/// <param name="inplace">True if cascaded diffs overwrite the source files, false otherwise</param>
/// <param name="outdir">New output directory for outputted DATs (blank means default)</param>
/// <param name="clean">True to clean the game names to WoD standard, false otherwise (default)</param>
/// <param name="logger">Logger object for console and file output</param>
public MergeDiff(List<String> inputs, string name, string desc, string cat, string version, string author,
bool diff, bool dedup, bool bare, bool forceunpack, bool old, bool superdat, bool cascade, bool inplace,
string outdir, bool clean, Logger logger)
{
_inputs = inputs;
_name = name;
_desc = desc;
_cat = cat;
_version = version;
_author = author;
_diff = diff;
_dedup = dedup;
_bare = bare;
_forceunpack = forceunpack;
_old = old;
_superdat = superdat;
_cascade = cascade;
_inplace = inplace;
_outdir = outdir;
_clean = clean;
_logger = logger;
}
/// <summary>
/// Combine DATs, optionally diffing and deduping them
/// </summary>
/// <returns>True if the DATs merged correctly, false otherwise</returns>
public bool Process()
{
// Check if there are enough inputs
if (_inputs.Count < 1)
{
_logger.Warning("At least 1 input is required!");
return false;
}
// Get the values that will be used
if (_name == "")
{
_name = (_diff ? "DiffDAT" : "MergeDAT") + (_superdat ? "-SuperDAT" : "") + (_dedup ? "-deduped" : "");
}
if (_desc == "")
{
_desc = (_diff ? "DiffDAT" : "MergeDAT") + (_superdat ? "-SuperDAT" : "") + (_dedup ? " - deduped" : "");
if (!_bare)
{
_desc += " (" + _date + ")";
}
}
if (_cat == "" && _diff)
{
_cat = "DiffDAT";
}
if (_author == "")
{
_author = "SabreTools";
}
// Create a dictionary of all ROMs from the input DATs
Dat userData;
List<Dat> datHeaders = PopulateUserData(out userData);
// Modify the Dictionary if necessary and output the results
if (_diff && !_cascade)
{
DiffNoCascade(_outdir, userData, _inputs, _logger);
}
// If we're in cascade and diff, output only cascaded diffs
else if (_diff && _cascade)
{
DiffCascade(_outdir, _inplace, userData, _inputs, datHeaders, _logger);
}
// Output all entries with user-defined merge
else
{
MergeNoDiff(_outdir, userData, _inputs, datHeaders, _logger);
}
return true;
}
/// <summary>
/// Populate the user DatData object from the input files
/// </summary>
/// <param name="userData">Output user DatData object to output</param>
/// <returns>List of DatData objects representing headers</returns>
private List<Dat> PopulateUserData(out Dat userData)
{
List<Dat> datHeaders = new List<Dat>();
int i = 0;
userData = new Dat
{
Roms = new Dictionary<string, List<Rom>>(),
MergeRoms = _dedup,
};
foreach (string input in _inputs)
{
_logger.User("Adding DAT: " + input.Split('¬')[0]);
userData = DatTools.Parse(input.Split('¬')[0], i, 0, userData, _logger, true, _clean);
i++;
// If we are in inplace mode or redirecting output, save the DAT data
if (_inplace || !String.IsNullOrEmpty(_outdir))
{
datHeaders.Add((Dat)userData.CloneHeader());
// Reset the header values so the next can be captured
userData.FileName = "";
userData.Name = "";
userData.Description = "";
userData.Version = "";
userData.Date = "";
userData.Category = "";
userData.Author = "";
userData.ForcePacking = ForcePacking.None;
userData.OutputFormat = OutputFormat.None;
userData.Type = "";
}
}
// Set the output values
userData.FileName = _desc;
userData.Name = _name;
userData.Description = _desc;
userData.Version = _version;
userData.Date = _date;
userData.Category = _cat;
userData.Author = _author;
userData.ForcePacking = (_forceunpack ? ForcePacking.Unzip : ForcePacking.None);
userData.OutputFormat = (_old ? OutputFormat.ClrMamePro : OutputFormat.Xml);
userData.Type = (_superdat ? "SuperDAT" : "");
return datHeaders;
}
/// <summary>
/// Output non-cascading diffs
/// </summary>
/// <param name="userData">Main DatData to draw information from</param>
public void DiffNoCascade(string outdir, Dat userData, List<string> inputs, Logger logger)
{
DateTime start = DateTime.Now;
logger.User("Initializing all output DATs");
// Don't have External dupes
string post = " (No Duplicates)";
Dat outerDiffData = (Dat)userData.CloneHeader();
outerDiffData.FileName += post;
outerDiffData.Name += post;
outerDiffData.Description += post;
// Have External dupes
post = " (Duplicates)";
Dat dupeData = (Dat)userData.CloneHeader();
dupeData.FileName += post;
dupeData.Name += post;
dupeData.Description += post;
// Create a list of DatData objects representing individual output files
List<Dat> outDats = new List<Dat>();
// Loop through each of the inputs and get or create a new DatData object
for (int j = 0; j < inputs.Count; j++)
{
post = " (" + Path.GetFileNameWithoutExtension(inputs[j].Split('¬')[0]) + " Only)";
Dat diffData = (Dat)userData.CloneHeader();
diffData.FileName += post;
diffData.Name += post;
diffData.Description += post;
outDats.Add(diffData);
}
logger.User("Initializing complete in " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff"));
// Now, loop through the dictionary and populate the correct DATs
start = DateTime.Now;
logger.User("Populating all output DATs");
List<string> keys = userData.Roms.Keys.ToList();
foreach (string key in keys)
{
List<Rom> roms = RomTools.Merge(userData.Roms[key], logger);
if (roms != null && roms.Count > 0)
{
foreach (Rom rom in roms)
{
// No duplicates
if (rom.Dupe < DupeType.ExternalHash)
{
// Individual DATs that are output
if (outDats[rom.Metadata.SystemID].Roms.ContainsKey(key))
{
outDats[rom.Metadata.SystemID].Roms[key].Add(rom);
}
else
{
List<Rom> tl = new List<Rom>();
tl.Add(rom);
outDats[rom.Metadata.SystemID].Roms.Add(key, tl);
}
// Merged no-duplicates DAT
Rom newrom = rom;
newrom.Game += " (" + Path.GetFileNameWithoutExtension(inputs[newrom.Metadata.SystemID].Split('¬')[0]) + ")";
if (outerDiffData.Roms.ContainsKey(key))
{
outerDiffData.Roms[key].Add(newrom);
}
else
{
List<Rom> tl = new List<Rom>();
tl.Add(rom);
outerDiffData.Roms.Add(key, tl);
}
}
// Duplicates only
if (rom.Dupe >= DupeType.ExternalHash)
{
Rom newrom = rom;
newrom.Game += " (" + Path.GetFileNameWithoutExtension(inputs[newrom.Metadata.SystemID].Split('¬')[0]) + ")";
if (dupeData.Roms.ContainsKey(key))
{
dupeData.Roms[key].Add(newrom);
}
else
{
List<Rom> tl = new List<Rom>();
tl.Add(rom);
dupeData.Roms.Add(key, tl);
}
}
}
}
}
logger.User("Populating complete in " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff"));
// Finally, loop through and output each of the DATs
start = DateTime.Now;
logger.User("Outputting all created DATs");
// Output the difflist (a-b)+(b-a) diff
Output.WriteDatfile(outerDiffData, outdir, logger);
// Output the (ab) diff
Output.WriteDatfile(dupeData, outdir, logger);
// Output the individual (a-b) DATs
for (int j = 0; j < inputs.Count; j++)
{
// If we have an output directory set, replace the path
string path = outdir + (Path.GetDirectoryName(inputs[j].Split('¬')[0]).Remove(0, inputs[j].Split('¬')[1].Length));
// If we have more than 0 roms, output
if (outDats[j].Roms.Count > 0)
{
Output.WriteDatfile(outDats[j], path, logger);
}
}
logger.User("Outputting complete in " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff"));
}
/// <summary>
/// Output cascading diffs
/// </summary>
/// <param name="userData">Main DatData to draw information from</param>
/// <param name="datHeaders">Dat headers used optionally</param>
private void DiffCascade(string outdir, bool inplace, Dat userData, List<string> inputs, List<Dat> datHeaders, Logger logger)
{
string post = "";
// Create a list of DatData objects representing output files
List<Dat> outDats = new List<Dat>();
// Loop through each of the inputs and get or create a new DatData object
DateTime start = DateTime.Now;
logger.User("Initializing all output DATs");
for (int j = 0; j < inputs.Count; j++)
{
post = " (" + Path.GetFileNameWithoutExtension(inputs[j].Split('¬')[0]) + " Only)";
Dat diffData;
// If we're in inplace mode, take the appropriate DatData object already stored
if (inplace || !String.IsNullOrEmpty(outdir))
{
diffData = datHeaders[j];
}
else
{
diffData = (Dat)userData.CloneHeader();
diffData.FileName += post;
diffData.Name += post;
diffData.Description += post;
}
outDats.Add(diffData);
}
logger.User("Initializing complete in " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff"));
// Now, loop through the dictionary and populate the correct DATs
start = DateTime.Now;
logger.User("Populating all output DATs");
List<string> keys = userData.Roms.Keys.ToList();
foreach (string key in keys)
{
List<Rom> roms = RomTools.Merge(userData.Roms[key], logger);
if (roms != null && roms.Count > 0)
{
foreach (Rom rom in roms)
{
if (outDats[rom.Metadata.SystemID].Roms.ContainsKey(key))
{
outDats[rom.Metadata.SystemID].Roms[key].Add(rom);
}
else
{
List<Rom> tl = new List<Rom>();
tl.Add(rom);
outDats[rom.Metadata.SystemID].Roms.Add(key, tl);
}
}
}
}
logger.User("Populating complete in " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff"));
// Finally, loop through and output each of the DATs
start = DateTime.Now;
logger.User("Outputting all created DATs");
for (int j = 0; j < inputs.Count; j++)
{
// If we have an output directory set, replace the path
string path = "";
if (inplace)
{
path = Path.GetDirectoryName(inputs[j].Split('¬')[0]);
}
else if (!String.IsNullOrEmpty(outdir))
{
path = outdir + (Path.GetDirectoryName(inputs[j].Split('¬')[0]).Remove(0, inputs[j].Split('¬')[1].Length));
}
// If we have more than 0 roms, output
if (outDats[j].Roms.Count > 0)
{
Output.WriteDatfile(outDats[j], path, logger);
}
}
logger.User("Outputting complete in " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff"));
}
/// <summary>
/// Output user defined merge
/// </summary>
/// <param name="userData">Main DatData to draw information from</param>
/// <param name="datHeaders">Dat headers used optionally</param>
private void MergeNoDiff(string outdir, Dat userData, List<string> inputs, List<Dat> datHeaders, Logger logger)
{
// If we're in SuperDAT mode, prefix all games with their respective DATs
if (userData.Type == "SuperDAT")
{
List<string> keys = userData.Roms.Keys.ToList();
foreach (string key in keys)
{
List<Rom> newroms = new List<Rom>();
foreach (Rom rom in userData.Roms[key])
{
Rom newrom = rom;
string filename = inputs[newrom.Metadata.SystemID].Split('¬')[0];
string rootpath = inputs[newrom.Metadata.SystemID].Split('¬')[1];
rootpath += (rootpath == "" ? "" : Path.DirectorySeparatorChar.ToString());
filename = filename.Remove(0, rootpath.Length);
newrom.Game = Path.Combine(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename), newrom.Game);
newroms.Add(newrom);
}
userData.Roms[key] = newroms;
}
}
Output.WriteDatfile(userData, outdir, logger);
}
}
}

View File

@@ -74,7 +74,7 @@ namespace SabreTools
/// <summary> /// <summary>
/// Wrap converting and updating DAT file from any format to any format /// Wrap converting and updating DAT file from any format to any format
/// </summary> /// </summary>
/// <param name="input">Input filename</param> /// <param name="input">List of input filenames</param>
/// /* Normal DAT header info */ /// /* Normal DAT header info */
/// <param name="filename">New filename</param> /// <param name="filename">New filename</param>
/// <param name="name">New name</param> /// <param name="name">New name</param>
@@ -107,6 +107,12 @@ namespace SabreTools
/// <param name="datprefix">Add the dat name as a directory prefix</param> /// <param name="datprefix">Add the dat name as a directory prefix</param>
/// <param name="romba">Output files in romba format</param> /// <param name="romba">Output files in romba format</param>
/// <param name="tsv">Output files in TSV format</param> /// <param name="tsv">Output files in TSV format</param>
/// /* Merging and Diffing info */
/// <param name="merge">True if input files should be merged into a single file, false otherwise</param>
/// <param name="diff">True if the input files should be diffed with each other, false otherwise</param>
/// <param name="cascade">True if the diffed files should be cascade diffed, false otherwise</param>
/// <param name="inplace">True if the cascade-diffed files should overwrite their inputs, false otherwise</param>
/// <param name="bare">True if the date should not be appended to the default name, false otherwise [OBSOLETE]</param>
/// /* Filtering info */ /// /* Filtering info */
/// <param name="gamename">Name of the game to match (can use asterisk-partials)</param> /// <param name="gamename">Name of the game to match (can use asterisk-partials)</param>
/// <param name="romname">Name of the rom to match (can use asterisk-partials)</param> /// <param name="romname">Name of the rom to match (can use asterisk-partials)</param>
@@ -122,7 +128,7 @@ namespace SabreTools
/// <param name="outdir">Optional param for output directory</param> /// <param name="outdir">Optional param for output directory</param>
/// <param name="clean">True to clean the game names to WoD standard, false otherwise (default)</param> /// <param name="clean">True to clean the game names to WoD standard, false otherwise (default)</param>
/// <param name="dedup">True to dedupe the roms in the DAT, false otherwise (default)</param> /// <param name="dedup">True to dedupe the roms in the DAT, false otherwise (default)</param>
private static void InitUpdate(string input, private static void InitUpdate(List<string> inputs,
/* Normal DAT header info */ /* Normal DAT header info */
string filename, string filename,
string name, string name,
@@ -157,6 +163,13 @@ namespace SabreTools
bool romba, bool romba,
bool tsv, bool tsv,
/* Merging and Diffing info */
bool merge,
bool diff,
bool cascade,
bool inplace,
bool bare,
/* Filtering info */ /* Filtering info */
string gamename, string gamename,
string romname, string romname,
@@ -227,6 +240,32 @@ namespace SabreTools
addext = (addext == "" || addext.StartsWith(".") ? addext : "." + addext); addext = (addext == "" || addext.StartsWith(".") ? addext : "." + addext);
repext = (repext == "" || repext.StartsWith(".") ? repext : "." + repext); repext = (repext == "" || repext.StartsWith(".") ? repext : "." + repext);
// If we're in merge or diff mode and the names aren't set, set defaults
if (merge || diff)
{
// Get the values that will be used
if (name == "")
{
name = (diff ? "DiffDAT" : "MergeDAT") + (superdat ? "-SuperDAT" : "") + (dedup ? "-deduped" : "");
}
if (description == "")
{
description = (diff ? "DiffDAT" : "MergeDAT") + (superdat ? "-SuperDAT" : "") + (dedup ? " - deduped" : "");
if (!bare)
{
description += " (" + date + ")";
}
}
if (category == "" && diff)
{
category = "DiffDAT";
}
if (author == "")
{
author = "SabreTools";
}
}
// Populate the DatData object // Populate the DatData object
Dat userInputDat = new Dat Dat userInputDat = new Dat
{ {
@@ -262,31 +301,37 @@ namespace SabreTools
if (outputCMP) if (outputCMP)
{ {
userInputDat.OutputFormat = OutputFormat.ClrMamePro; userInputDat.OutputFormat = OutputFormat.ClrMamePro;
DatTools.Update(input, userInputDat, outdir, clean, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, _logger); DatTools.Update(inputs, userInputDat, outdir, merge, diff, cascade, inplace, bare, clean,
gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, _logger);
} }
if (outputMiss || romba) if (outputMiss)
{ {
userInputDat.OutputFormat = OutputFormat.MissFile; userInputDat.OutputFormat = OutputFormat.MissFile;
DatTools.Update(input, userInputDat, outdir, clean, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, _logger); DatTools.Update(inputs, userInputDat, outdir, merge, diff, cascade, inplace, bare, clean,
gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, _logger);
} }
if (outputRC) if (outputRC)
{ {
userInputDat.OutputFormat = OutputFormat.RomCenter; userInputDat.OutputFormat = OutputFormat.RomCenter;
DatTools.Update(input, userInputDat, outdir, clean, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, _logger); DatTools.Update(inputs, userInputDat, outdir, merge, diff, cascade, inplace, bare, clean,
gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, _logger);
} }
if (outputSD) if (outputSD)
{ {
userInputDat.OutputFormat = OutputFormat.SabreDat; userInputDat.OutputFormat = OutputFormat.SabreDat;
DatTools.Update(input, userInputDat, outdir, clean, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, _logger); DatTools.Update(inputs, userInputDat, outdir, merge, diff, cascade, inplace, bare, clean,
gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, _logger);
} }
if (outputXML) if (outputXML)
{ {
userInputDat.OutputFormat = OutputFormat.Xml; userInputDat.OutputFormat = OutputFormat.Xml;
DatTools.Update(input, userInputDat, outdir, clean, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, _logger); DatTools.Update(inputs, userInputDat, outdir, merge, diff, cascade, inplace, bare, clean,
gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, _logger);
} }
if (!outputCMP && !(outputMiss || romba) && !outputRC && !outputSD && !outputXML) if (!outputCMP && !outputMiss && !outputRC && !outputSD && !outputXML)
{ {
DatTools.Update(input, userInputDat, outdir, clean, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, _logger); DatTools.Update(inputs, userInputDat, outdir, merge, diff, cascade, inplace, bare, clean,
gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, _logger);
} }
} }
@@ -372,71 +417,6 @@ namespace SabreTools
} }
} }
/// <summary>
/// Wrap merging, diffing, and deduping 2 or mor DATs
/// </summary>
/// <param name="inputs">A List of Strings representing the DATs or DAT folders to be merged</param>
/// <param name="name">Internal name of the DAT</param>
/// <param name="desc">Description and external name of the DAT</param>
/// <param name="cat">Category for the DAT</param>
/// <param name="version">Version of the DAT</param>
/// <param name="author">Author of the DAT</param>
/// <param name="diff">True if a DiffDat of all inputs is wanted, false otherwise</param>
/// <param name="dedup">True if the outputted file should remove duplicates, false otherwise</param>
/// <param name="bare">True if the date should be omitted from the DAT, false otherwise</param>
/// <param name="forceunpack">True if the forcepacking="unzip" tag is to be added, false otherwise</param>
/// <param name="old">True if a old-style DAT should be output, false otherwise</param>
/// <param name="superdat">True if DATs should be merged in SuperDAT style, false otherwise</param>
/// <param name="cascade">True if the outputted diffs should be cascaded, false otherwise</param>
/// <param name="inplace">True if cascaded diffs overwrite the source files, false otherwise</param>
/// <param name="outdir">Output directory for the files (blank is default)</param>
/// <param name="clean">True to clean the game names to WoD standard, false otherwise (default)</param>
private static void InitMergeDiff(List<string> inputs, string name, string desc, string cat, string version, string author,
bool diff, bool dedup, bool bare, bool forceunpack, bool old, bool superdat, bool cascade, bool inplace, string outdir = "", bool clean = false)
{
// Make sure there are no folders in inputs
List<string> newInputs = new List<string>();
foreach (string input in inputs)
{
if (Directory.Exists(input))
{
foreach (string file in Directory.EnumerateFiles(input, "*", SearchOption.AllDirectories))
{
try
{
newInputs.Add(Path.GetFullPath(file) + "¬" + Path.GetFullPath(input));
}
catch (PathTooLongException)
{
_logger.Warning("The path for " + file + " was too long");
}
catch (Exception ex)
{
_logger.Error(ex.ToString());
}
}
}
else if (File.Exists(input))
{
try
{
newInputs.Add(Path.GetFullPath(input) + "¬" + Path.GetDirectoryName(Path.GetFullPath(input)));
}
catch (PathTooLongException)
{
_logger.Warning("The path for " + input + " was too long");
}
catch (Exception ex)
{
_logger.Error(ex.ToString());
}
}
}
MergeDiff md = new MergeDiff(newInputs, name, desc, cat, version, author, diff, dedup, bare, forceunpack, old, superdat, cascade, inplace, outdir, clean, _logger);
md.Process();
}
/// <summary> /// <summary>
/// Wrap splitting a DAT by 2 extensions /// Wrap splitting a DAT by 2 extensions
/// </summary> /// </summary>

View File

@@ -638,16 +638,13 @@ namespace SabreTools
ListSystems(); ListSystems();
} }
// Convert, update, and filter a DAT or folder of DATs // Convert, update, merge, diff, and filter a DAT or folder of DATs
else if (update || outputCMP || outputMiss || outputRC || outputSD || outputXML) else if (update || outputCMP || outputMiss || outputRC || outputSD || outputXML || merge || diff)
{ {
foreach (string input in inputs) InitUpdate(inputs, filename, name, description, category, version, date, author, email, homepage, url, comment, header,
{ superdat, forcemerge, forcend, forcepack, outputCMP, outputMiss, outputRC, outputSD, outputXML, usegame, prefix,
InitUpdate(input, filename, name, description, category, version, date, author, email, homepage, url, comment, header, postfix, quotes, repext, addext, datprefix, romba, tsv, merge, diff, cascade, inplace, bare, gamename, romname,
superdat, forcemerge, forcend, forcepack, outputCMP, outputMiss, outputRC, outputSD, outputXML, usegame, prefix, romtype, sgt, slt, seq, crc, md5, sha1, nodump, outdir, clean, dedup);
postfix, quotes, repext, addext, datprefix, romba, tsv, gamename, romname, romtype, sgt, slt, seq, crc, md5,
sha1, nodump, outdir, clean, dedup);
}
} }
// Add a source or system // Add a source or system
@@ -699,12 +696,6 @@ namespace SabreTools
InitExtSplit(inputs, exta, extb, outdir); InitExtSplit(inputs, exta, extb, outdir);
} }
// Merge, diff, and dedupe at least 2 DATs
else if (merge || diff)
{
InitMergeDiff(inputs, name, description, category, version, author, diff, dedup, bare, forceunpack, old, superdat, cascade, inplace, outdir, clean);
}
// Split a DAT by available hashes // Split a DAT by available hashes
else if (hashsplit) else if (hashsplit)
{ {

View File

@@ -106,7 +106,6 @@
<Compile Include="ImportExport\GenerateTwo.cs" /> <Compile Include="ImportExport\GenerateTwo.cs" />
<Compile Include="SabreTools.cs" /> <Compile Include="SabreTools.cs" />
<Compile Include="ImportExport\ImportTwo.cs" /> <Compile Include="ImportExport\ImportTwo.cs" />
<Compile Include="MergeDiff.cs" />
<Compile Include="Partials\SabreTools_Helpers.cs" /> <Compile Include="Partials\SabreTools_Helpers.cs" />
<Compile Include="Partials\SabreTools_Inits.cs" /> <Compile Include="Partials\SabreTools_Inits.cs" />
<Compile Include="Partials\SabreTools_Menus.cs" /> <Compile Include="Partials\SabreTools_Menus.cs" />