using System; using System.Collections.Generic; using System.IO; using System.Linq; using SabreTools.Helper; namespace SabreTools { public class MergeDiff { // Listing related variables private List _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; // User specified strings private string _name; private string _desc; private string _cat; private string _version; private string _author; // Other required variables private string _date = DateTime.Now.ToString("yyyy-MM-dd"); private Logger _logger; /// /// Create a new MergeDAT object /// /// A List of Strings representing the DATs or DAT folders to be merged /// Internal name of the DAT /// Description and external name of the DAT /// Category for the DAT /// Version of the DAT /// Author of the DAT /// True if all diff variants should be outputted, false otherwise /// True if a DiffDat of all inputs is wanted, false otherwise /// True if the outputted file should remove duplicates, false otherwise /// True if the date should be omitted from the DAT, false otherwise /// True if the forcepacking="unzip" tag is to be added, false otherwise /// True if a old-style DAT should be output, false otherwise /// True if DATs should be parsed into SuperDAT format, false otherwise /// True if the outputted diffs should be cascaded, false otherwise /// Logger object for console and file output public MergeDiff(List 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, 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; _logger = logger; } /// /// Combine DATs, optionally diffing and deduping them /// /// True if the DATs merged correctly, false otherwise 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 int i = 0; DatData userData = new DatData { Name = _name, Description = _desc, Version = _version, Date = _date, Category = _cat, Author = _author, ForcePacking = (_forceunpack ? ForcePacking.Unzip : ForcePacking.None), OutputFormat = (_old ? OutputFormat.ClrMamePro : OutputFormat.Xml), MergeRoms = _dedup, Type = (_superdat ? "SuperDAT" : ""), }; foreach (string input in _inputs) { _logger.User("Adding DAT: " + input.Split('¬')[0]); userData = RomManipulation.Parse(input.Split('¬')[0], i, 0, userData, _logger); i++; } // Modify the Dictionary if necessary and output the results string post = ""; if (_diff && !_cascade) { post = " (No Duplicates)"; // Get all entries that don't have External dupes DatData outerDiffData = new DatData { Name = _name + post, Description = _desc + post, Version = _version, Date = _date, Category = _cat, Author = _author, ForcePacking = (_forceunpack ? ForcePacking.Unzip : ForcePacking.None), OutputFormat = (_old ? OutputFormat.ClrMamePro : OutputFormat.Xml), MergeRoms = _dedup, }; foreach (string key in userData.Roms.Keys) { List temp = userData.Roms[key]; temp = RomManipulation.Merge(temp); foreach (RomData rom in temp) { if (rom.Dupe < DupeType.ExternalHash) { if (outerDiffData.Roms.ContainsKey(key)) { outerDiffData.Roms[key].Add(rom); } else { List tl = new List(); tl.Add(rom); outerDiffData.Roms.Add(key, tl); } } } } // Output the difflist (a-b)+(b-a) diff Output.WriteDatfile(outerDiffData, "", _logger); // For the AB mode-style diffs, get all required dictionaries and output with a new name // Loop through _inputs first and filter from all diffed roms to find the ones that have the same "System" for (int j = 0; j < _inputs.Count; j++) { post = " (" + Path.GetFileNameWithoutExtension(_inputs[j].Split('¬')[0]) + " Only)"; DatData diffData = new DatData { Name = _name + post, Description = _desc + post, Version = _version, Date = _date, Category = _cat, Author = _author, ForcePacking = (_forceunpack ? ForcePacking.Unzip : ForcePacking.None), OutputFormat = (_old ? OutputFormat.ClrMamePro : OutputFormat.Xml), MergeRoms = _dedup, }; foreach (string key in outerDiffData.Roms.Keys) { foreach (RomData rom in outerDiffData.Roms[key]) { if (rom.SystemID == j) { if (diffData.Roms.ContainsKey(key)) { diffData.Roms[key].Add(rom); } else { List tl = new List(); tl.Add(rom); diffData.Roms.Add(key, tl); } } } } Output.WriteDatfile(diffData, "", _logger); } // Get all entries that have External dupes post = " (Duplicates)"; DatData dupeData = new DatData { Name = _name + post, Description = _desc + post, Version = _version, Date = _date, Category = _cat, Author = _author, ForcePacking = (_forceunpack ? ForcePacking.Unzip : ForcePacking.None), OutputFormat = (_old ? OutputFormat.ClrMamePro : OutputFormat.Xml), MergeRoms = _dedup, }; foreach (string key in userData.Roms.Keys) { List temp = userData.Roms[key]; temp = RomManipulation.Merge(temp); foreach (RomData rom in temp) { if (rom.Dupe >= DupeType.ExternalHash) { if (dupeData.Roms.ContainsKey(key)) { dupeData.Roms[key].Add(rom); } else { List tl = new List(); tl.Add(rom); dupeData.Roms.Add(key, tl); } } } } Output.WriteDatfile(dupeData, "", _logger); } // If we're in cascade and diff, output only cascaded diffs else if (_diff && _cascade) { // Loop through _inputs first and filter from all diffed roms to find the ones that have the same "System" for (int j = 0; j < _inputs.Count; j++) { post = " (" + Path.GetFileNameWithoutExtension(_inputs[j].Split('¬')[0]) + " Only)"; DatData diffData = new DatData { Name = _name + post, Description = _desc + post, Version = _version, Date = _date, Category = _cat, Author = _author, ForcePacking = (_forceunpack ? ForcePacking.Unzip : ForcePacking.None), OutputFormat = (_old ? OutputFormat.ClrMamePro : OutputFormat.Xml), MergeRoms = _dedup, }; List keys = userData.Roms.Keys.ToList(); foreach (string key in keys) { List oldroms = RomManipulation.Merge(userData.Roms[key]); List newroms = new List(); foreach (RomData rom in oldroms) { if (rom.SystemID == j) { if (diffData.Roms.ContainsKey(key)) { diffData.Roms[key].Add(rom); } else { List tl = new List(); tl.Add(rom); diffData.Roms.Add(key, tl); } } else { newroms.Add(rom); } } userData.Roms[key] = newroms; } Output.WriteDatfile(diffData, "", _logger); } } // Output all entries with user-defined merge else { // If we're in SuperDAT mode, prefix all games with their respective DATs if (_superdat) { List keys = userData.Roms.Keys.ToList(); foreach (string key in keys) { List newroms = new List(); foreach (RomData rom in userData.Roms[key]) { RomData newrom = rom; string filename = _inputs[newrom.SystemID].Split('¬')[0]; string rootpath = _inputs[newrom.SystemID].Split('¬')[1]; rootpath += (rootpath == "" ? "" : Path.DirectorySeparatorChar.ToString()); filename = filename.Remove(0, rootpath.Length); newrom.Game = Path.GetDirectoryName(filename) + Path.DirectorySeparatorChar.ToString() + Path.GetFileNameWithoutExtension(filename) + Path.DirectorySeparatorChar + newrom.Game; newroms.Add(newrom); } userData.Roms[key] = newroms; } } Output.WriteDatfile(userData, "", _logger); } return true; } } }