2016-04-19 01:11:23 -07:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.IO;
|
2016-04-19 15:41:06 -07:00
|
|
|
|
using System.Linq;
|
2016-09-01 20:38:41 -07:00
|
|
|
|
using System.Text;
|
2016-04-19 01:11:23 -07:00
|
|
|
|
using System.Text.RegularExpressions;
|
2016-09-07 10:58:21 -07:00
|
|
|
|
using System.Threading.Tasks;
|
2016-09-01 20:38:41 -07:00
|
|
|
|
using System.Web;
|
2016-04-19 01:11:23 -07:00
|
|
|
|
using System.Xml;
|
|
|
|
|
|
|
|
|
|
|
|
namespace SabreTools.Helper
|
|
|
|
|
|
{
|
2016-08-29 17:28:08 -07:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// DAT manipulation tools that rely on Rom and related structs
|
|
|
|
|
|
/// </summary>
|
2016-06-11 15:08:24 -07:00
|
|
|
|
public class DatTools
|
2016-04-19 01:11:23 -07:00
|
|
|
|
{
|
2016-08-29 17:28:08 -07:00
|
|
|
|
#region DAT Parsing
|
|
|
|
|
|
|
2016-04-19 15:41:06 -07:00
|
|
|
|
/// <summary>
|
2016-05-16 20:51:05 -07:00
|
|
|
|
/// Get what type of DAT the input file is
|
2016-04-19 15:41:06 -07:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="filename">Name of the file to be parsed</param>
|
2016-09-09 15:54:10 -07:00
|
|
|
|
/// <returns>The OutputFormat corresponding to the DAT</returns>
|
2016-05-27 17:45:34 -07:00
|
|
|
|
/// <remarks>There is currently no differentiation between XML and SabreDAT here</remarks>
|
2016-09-09 15:54:10 -07:00
|
|
|
|
public static OutputFormat GetOutputFormat(string filename, Logger logger)
|
2016-04-19 15:41:06 -07:00
|
|
|
|
{
|
2016-09-05 20:31:44 -07:00
|
|
|
|
// Limit the output formats based on extension
|
|
|
|
|
|
string ext = Path.GetExtension(filename).ToLowerInvariant();
|
|
|
|
|
|
if (ext != ".dat" && ext != ".xml")
|
|
|
|
|
|
{
|
2016-09-09 15:25:37 -07:00
|
|
|
|
return 0;
|
2016-09-05 20:31:44 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-06 11:38:55 -07:00
|
|
|
|
// Read the input file, if possible
|
|
|
|
|
|
logger.Log("Attempting to read file: \"" + filename + "\"");
|
|
|
|
|
|
|
|
|
|
|
|
// Check if file exists
|
|
|
|
|
|
if (!File.Exists(filename))
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.Warning("File '" + filename + "' could not read from!");
|
2016-09-09 15:25:37 -07:00
|
|
|
|
return 0;
|
2016-09-06 11:38:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-19 15:41:06 -07:00
|
|
|
|
try
|
|
|
|
|
|
{
|
2016-08-29 16:33:07 -07:00
|
|
|
|
StreamReader sr = File.OpenText(filename);
|
2016-04-25 00:25:08 -07:00
|
|
|
|
string first = sr.ReadLine();
|
|
|
|
|
|
sr.Close();
|
2016-06-13 10:29:07 -07:00
|
|
|
|
sr.Dispose();
|
2016-05-16 20:51:05 -07:00
|
|
|
|
if (first.Contains("<") && first.Contains(">"))
|
2016-04-20 15:30:56 -07:00
|
|
|
|
{
|
2016-09-09 15:54:10 -07:00
|
|
|
|
return OutputFormat.Xml;
|
2016-04-20 15:30:56 -07:00
|
|
|
|
}
|
2016-05-16 20:51:05 -07:00
|
|
|
|
else if (first.Contains("[") && first.Contains("]"))
|
2016-04-20 15:30:56 -07:00
|
|
|
|
{
|
2016-09-09 15:54:10 -07:00
|
|
|
|
return OutputFormat.RomCenter;
|
2016-05-16 20:51:05 -07:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2016-09-09 15:54:10 -07:00
|
|
|
|
return OutputFormat.ClrMamePro;
|
2016-04-20 15:30:56 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-05-16 20:51:05 -07:00
|
|
|
|
catch (Exception)
|
2016-04-20 15:30:56 -07:00
|
|
|
|
{
|
2016-09-09 15:25:37 -07:00
|
|
|
|
return 0;
|
2016-04-20 15:37:49 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-25 00:26:19 -07:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Get the XmlTextReader associated with a file, if possible
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="filename">Name of the file to be parsed</param>
|
|
|
|
|
|
/// <param name="logger">Logger object for console and file output</param>
|
|
|
|
|
|
/// <returns>The XmlTextReader representing the (possibly converted) file, null otherwise</returns>
|
|
|
|
|
|
public static XmlTextReader GetXmlTextReader(string filename, Logger logger)
|
|
|
|
|
|
{
|
2016-05-18 16:37:39 -07:00
|
|
|
|
logger.Log("Attempting to read file: \"" + filename + "\"");
|
2016-04-25 00:26:19 -07:00
|
|
|
|
|
|
|
|
|
|
// Check if file exists
|
2016-08-29 16:33:07 -07:00
|
|
|
|
if (!File.Exists(filename))
|
2016-04-25 00:26:19 -07:00
|
|
|
|
{
|
|
|
|
|
|
logger.Warning("File '" + filename + "' could not read from!");
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-05-16 20:51:05 -07:00
|
|
|
|
XmlTextReader xtr;
|
2016-05-27 16:06:19 -07:00
|
|
|
|
xtr = new XmlTextReader(filename);
|
2016-05-16 20:51:05 -07:00
|
|
|
|
xtr.WhitespaceHandling = WhitespaceHandling.None;
|
|
|
|
|
|
xtr.DtdProcessing = DtdProcessing.Ignore;
|
|
|
|
|
|
return xtr;
|
2016-04-21 14:35:11 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-27 00:53:15 -07:00
|
|
|
|
/// <summary>
|
2016-05-16 13:42:21 -07:00
|
|
|
|
/// Parse a DAT and return all found games and roms within
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="filename">Name of the file to be parsed</param>
|
|
|
|
|
|
/// <param name="sysid">System ID for the DAT</param>
|
|
|
|
|
|
/// <param name="srcid">Source ID for the DAT</param>
|
|
|
|
|
|
/// <param name="datdata">The DatData object representing found roms to this point</param>
|
|
|
|
|
|
/// <param name="logger">Logger object for console and/or file output</param>
|
2016-05-29 13:27:34 -07:00
|
|
|
|
/// <param name="keep">True if full pathnames are to be kept, false otherwise (default)</param>
|
|
|
|
|
|
/// <param name="clean">True if game names are sanitized, false otherwise (default)</param>
|
2016-09-14 10:33:45 -07:00
|
|
|
|
/// <param name="softlist">True if SL XML names should be kept, false otherwise (default)</param>
|
|
|
|
|
|
/// <param name="keepext">True if original extension should be kept, false otherwise (default)</param>
|
2016-09-18 21:05:48 -07:00
|
|
|
|
public static void Parse(string filename, int sysid, int srcid, ref Dat datdata, Logger logger, bool keep = false, bool clean = false, bool softlist = false, bool keepext = false)
|
2016-09-06 11:38:55 -07:00
|
|
|
|
{
|
2016-09-18 21:05:48 -07:00
|
|
|
|
Parse(filename, sysid, srcid, ref datdata, null, null, null, -1, -1, -1, null, null, null, null, false, false, "", logger, keep, clean, softlist, keepext);
|
2016-09-06 11:38:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Parse a DAT and return all found games and roms within
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="filename">Name of the file to be parsed</param>
|
|
|
|
|
|
/// <param name="sysid">System ID for the DAT</param>
|
|
|
|
|
|
/// <param name="srcid">Source ID for the DAT</param>
|
|
|
|
|
|
/// <param name="datdata">The DatData object representing found roms to this point</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="romtype">Type of the rom to match</param>
|
|
|
|
|
|
/// <param name="sgt">Find roms greater than or equal to this size</param>
|
|
|
|
|
|
/// <param name="slt">Find roms less than or equal to this size</param>
|
|
|
|
|
|
/// <param name="seq">Find roms equal to this size</param>
|
|
|
|
|
|
/// <param name="crc">CRC of the rom to match (can use asterisk-partials)</param>
|
|
|
|
|
|
/// <param name="md5">MD5 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="trim">True if we are supposed to trim names to NTFS length, false otherwise</param>
|
|
|
|
|
|
/// <param name="single">True if all games should be replaced by '!', false otherwise</param>
|
|
|
|
|
|
/// <param name="root">String representing root directory to compare against for length calculation</param>
|
|
|
|
|
|
/// <param name="logger">Logger object for console and/or file output</param>
|
|
|
|
|
|
/// <param name="keep">True if full pathnames are to be kept, false otherwise (default)</param>
|
|
|
|
|
|
/// <param name="clean">True if game names are sanitized, false otherwise (default)</param>
|
2016-09-06 21:15:17 -07:00
|
|
|
|
/// <param name="softlist">True if SL XML names should be kept, false otherwise (default)</param>
|
|
|
|
|
|
/// <param name="keepext">True if original extension should be kept, false otherwise (default)</param>
|
2016-09-06 11:38:55 -07:00
|
|
|
|
public static Dat Parse(
|
|
|
|
|
|
// Standard Dat parsing
|
|
|
|
|
|
string filename,
|
|
|
|
|
|
int sysid,
|
|
|
|
|
|
int srcid,
|
2016-09-18 21:05:48 -07:00
|
|
|
|
ref Dat datdata,
|
2016-09-06 11:38:55 -07:00
|
|
|
|
|
|
|
|
|
|
// Rom filtering
|
|
|
|
|
|
string gamename,
|
|
|
|
|
|
string romname,
|
|
|
|
|
|
string romtype,
|
|
|
|
|
|
long sgt,
|
|
|
|
|
|
long slt,
|
|
|
|
|
|
long seq,
|
|
|
|
|
|
string crc,
|
|
|
|
|
|
string md5,
|
|
|
|
|
|
string sha1,
|
|
|
|
|
|
bool? nodump,
|
|
|
|
|
|
|
|
|
|
|
|
// Rom renaming
|
|
|
|
|
|
bool trim,
|
|
|
|
|
|
bool single,
|
|
|
|
|
|
string root,
|
|
|
|
|
|
|
|
|
|
|
|
// Miscellaneous
|
|
|
|
|
|
Logger logger,
|
|
|
|
|
|
bool keep = false,
|
|
|
|
|
|
bool clean = false,
|
|
|
|
|
|
bool softlist = false,
|
|
|
|
|
|
bool keepext = false)
|
2016-04-28 10:37:33 -07:00
|
|
|
|
{
|
2016-08-26 12:25:31 -07:00
|
|
|
|
// Check the file extension first as a safeguard
|
|
|
|
|
|
string ext = Path.GetExtension(filename).ToLowerInvariant();
|
|
|
|
|
|
if (ext != ".txt" && ext != ".dat" && ext != ".xml")
|
|
|
|
|
|
{
|
|
|
|
|
|
return datdata;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-05-25 11:29:19 -07:00
|
|
|
|
// If the output filename isn't set already, get the internal filename
|
2016-08-23 16:04:52 -07:00
|
|
|
|
datdata.FileName = (String.IsNullOrEmpty(datdata.FileName) ? (keepext ? Path.GetFileName(filename) : Path.GetFileNameWithoutExtension(filename)) : datdata.FileName);
|
2016-05-25 11:29:19 -07:00
|
|
|
|
|
2016-05-26 21:43:28 -07:00
|
|
|
|
// If the output type isn't set already, get the internal output type
|
2016-09-09 15:54:10 -07:00
|
|
|
|
datdata.OutputFormat = (datdata.OutputFormat == 0 ? GetOutputFormat(filename, logger) : datdata.OutputFormat);
|
2016-05-26 21:43:28 -07:00
|
|
|
|
|
2016-05-21 00:45:56 -07:00
|
|
|
|
// Make sure there's a dictionary to read to
|
2016-08-29 13:52:13 -07:00
|
|
|
|
if (datdata.Files == null)
|
2016-05-21 00:45:56 -07:00
|
|
|
|
{
|
2016-08-29 13:57:46 -07:00
|
|
|
|
datdata.Files = new Dictionary<string, List<Rom>>();
|
2016-05-21 00:45:56 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-05-27 16:06:19 -07:00
|
|
|
|
// Now parse the correct type of DAT
|
2016-09-06 11:38:55 -07:00
|
|
|
|
switch (GetOutputFormat(filename, logger))
|
2016-05-27 16:06:19 -07:00
|
|
|
|
{
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.ClrMamePro:
|
2016-09-06 11:38:55 -07:00
|
|
|
|
return ParseCMP(filename, sysid, srcid, datdata, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, trim, single, root, logger, keep, clean);
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.RomCenter:
|
2016-09-06 11:38:55 -07:00
|
|
|
|
return ParseRC(filename, sysid, srcid, datdata, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, trim, single, root, logger, clean);
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.SabreDat:
|
|
|
|
|
|
case OutputFormat.Xml:
|
2016-09-06 11:38:55 -07:00
|
|
|
|
return ParseXML(filename, sysid, srcid, datdata, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, trim, single, root, logger, keep, clean, softlist);
|
2016-05-27 16:06:19 -07:00
|
|
|
|
default:
|
|
|
|
|
|
return datdata;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Parse a ClrMamePro DAT and return all found games and roms within
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="filename">Name of the file to be parsed</param>
|
|
|
|
|
|
/// <param name="sysid">System ID for the DAT</param>
|
|
|
|
|
|
/// <param name="srcid">Source ID for the DAT</param>
|
|
|
|
|
|
/// <param name="datdata">The DatData object representing found roms to this point</param>
|
2016-09-06 11:38:55 -07:00
|
|
|
|
/// <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="romtype">Type of the rom to match</param>
|
|
|
|
|
|
/// <param name="sgt">Find roms greater than or equal to this size</param>
|
|
|
|
|
|
/// <param name="slt">Find roms less than or equal to this size</param>
|
|
|
|
|
|
/// <param name="seq">Find roms equal to this size</param>
|
|
|
|
|
|
/// <param name="crc">CRC of the rom to match (can use asterisk-partials)</param>
|
|
|
|
|
|
/// <param name="md5">MD5 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="trim">True if we are supposed to trim names to NTFS length, false otherwise</param>
|
|
|
|
|
|
/// <param name="single">True if all games should be replaced by '!', false otherwise</param>
|
|
|
|
|
|
/// <param name="root">String representing root directory to compare against for length calculation</param>
|
2016-05-27 16:06:19 -07:00
|
|
|
|
/// <param name="logger">Logger object for console and/or file output</param>
|
2016-05-29 13:27:34 -07:00
|
|
|
|
/// <param name="keep">True if full pathnames are to be kept, false otherwise (default)</param>
|
2016-05-29 13:36:02 -07:00
|
|
|
|
/// <param name="clean">True if game names are sanitized, false otherwise (default)</param>
|
2016-05-27 16:06:19 -07:00
|
|
|
|
/// <returns>DatData object representing the read-in data</returns>
|
2016-09-06 11:38:55 -07:00
|
|
|
|
private static Dat ParseCMP(
|
|
|
|
|
|
// Standard Dat parsing
|
|
|
|
|
|
string filename,
|
|
|
|
|
|
int sysid,
|
|
|
|
|
|
int srcid,
|
|
|
|
|
|
Dat datdata,
|
|
|
|
|
|
|
|
|
|
|
|
// Rom filtering
|
|
|
|
|
|
string gamename,
|
|
|
|
|
|
string romname,
|
|
|
|
|
|
string romtype,
|
|
|
|
|
|
long sgt,
|
|
|
|
|
|
long slt,
|
|
|
|
|
|
long seq,
|
|
|
|
|
|
string crc,
|
|
|
|
|
|
string md5,
|
|
|
|
|
|
string sha1,
|
|
|
|
|
|
bool? nodump,
|
|
|
|
|
|
|
|
|
|
|
|
// Rom renaming
|
|
|
|
|
|
bool trim,
|
|
|
|
|
|
bool single,
|
|
|
|
|
|
string root,
|
|
|
|
|
|
|
|
|
|
|
|
// Miscellaneous
|
|
|
|
|
|
Logger logger,
|
|
|
|
|
|
bool keep,
|
|
|
|
|
|
bool clean)
|
2016-05-27 16:06:19 -07:00
|
|
|
|
{
|
2016-09-06 11:38:55 -07:00
|
|
|
|
// Open a file reader
|
2016-08-29 16:33:07 -07:00
|
|
|
|
StreamReader sr = new StreamReader(File.OpenRead(filename));
|
2016-05-27 16:06:19 -07:00
|
|
|
|
|
|
|
|
|
|
bool block = false, superdat = false;
|
2016-09-12 23:04:28 -07:00
|
|
|
|
string blockname = "", tempgamename = "", gamedesc = "", cloneof = "",
|
|
|
|
|
|
romof = "", sampleof = "", year = "", manufacturer = "";
|
2016-05-27 16:06:19 -07:00
|
|
|
|
while (!sr.EndOfStream)
|
|
|
|
|
|
{
|
|
|
|
|
|
string line = sr.ReadLine();
|
|
|
|
|
|
|
|
|
|
|
|
// Comments in CMP DATs start with a #
|
|
|
|
|
|
if (line.Trim().StartsWith("#"))
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// If the line is the header or a game
|
|
|
|
|
|
if (Regex.IsMatch(line, Constants.HeaderPatternCMP))
|
|
|
|
|
|
{
|
|
|
|
|
|
GroupCollection gc = Regex.Match(line, Constants.HeaderPatternCMP).Groups;
|
|
|
|
|
|
|
2016-09-12 23:29:23 -07:00
|
|
|
|
if (gc[1].Value == "clrmamepro" || gc[1].Value == "romvault" || gc[1].Value.ToLowerInvariant() == "doscenter")
|
2016-05-27 16:06:19 -07:00
|
|
|
|
{
|
|
|
|
|
|
blockname = "header";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
block = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-13 10:48:45 -07:00
|
|
|
|
// If the line is a rom-like item and we're in a block
|
|
|
|
|
|
else if ((line.Trim().StartsWith("rom (")
|
|
|
|
|
|
|| line.Trim().StartsWith("disk (")
|
|
|
|
|
|
|| line.Trim().StartsWith("file (")
|
|
|
|
|
|
|| (line.Trim().StartsWith("sample") && !line.Trim().StartsWith("sampleof"))
|
|
|
|
|
|
) && block)
|
|
|
|
|
|
{
|
|
|
|
|
|
ItemType temptype = ItemType.Rom;
|
|
|
|
|
|
if (line.Trim().StartsWith("rom ("))
|
|
|
|
|
|
{
|
|
|
|
|
|
temptype = ItemType.Rom;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (line.Trim().StartsWith("disk ("))
|
|
|
|
|
|
{
|
|
|
|
|
|
temptype = ItemType.Disk;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (line.Trim().StartsWith("file ("))
|
|
|
|
|
|
{
|
|
|
|
|
|
temptype = ItemType.Rom;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (line.Trim().StartsWith("sample"))
|
|
|
|
|
|
{
|
|
|
|
|
|
temptype = ItemType.Sample;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-08-29 13:57:46 -07:00
|
|
|
|
Rom rom = new Rom
|
2016-05-27 16:06:19 -07:00
|
|
|
|
{
|
2016-08-29 13:42:27 -07:00
|
|
|
|
Machine = new Machine
|
2016-08-29 13:41:42 -07:00
|
|
|
|
{
|
2016-09-06 11:38:55 -07:00
|
|
|
|
Name = tempgamename,
|
2016-08-29 13:41:42 -07:00
|
|
|
|
Description = gamedesc,
|
2016-09-12 23:04:28 -07:00
|
|
|
|
CloneOf = cloneof,
|
|
|
|
|
|
RomOf = romof,
|
|
|
|
|
|
SampleOf = sampleof,
|
|
|
|
|
|
Manufacturer = manufacturer,
|
|
|
|
|
|
Year = year,
|
2016-08-29 13:41:42 -07:00
|
|
|
|
},
|
2016-09-13 10:48:45 -07:00
|
|
|
|
Type = temptype,
|
2016-06-16 17:27:32 -07:00
|
|
|
|
Metadata = new SourceMetadata { SystemID = sysid, SourceID = srcid },
|
2016-05-27 16:06:19 -07:00
|
|
|
|
};
|
|
|
|
|
|
|
2016-09-13 10:48:45 -07:00
|
|
|
|
// If we have a sample, treat it special
|
|
|
|
|
|
if (temptype == ItemType.Sample)
|
|
|
|
|
|
{
|
|
|
|
|
|
line = line.Trim().Remove(0, 6).Trim().Replace("\"", ""); // Remove "sample" from the input string
|
|
|
|
|
|
rom.Name = line;
|
|
|
|
|
|
}
|
2016-05-27 16:06:19 -07:00
|
|
|
|
|
2016-09-13 10:48:45 -07:00
|
|
|
|
// Otherwise, process the rest of the line
|
|
|
|
|
|
else
|
2016-05-27 16:06:19 -07:00
|
|
|
|
{
|
2016-09-13 10:48:45 -07:00
|
|
|
|
string[] gc = line.Trim().Split(' ');
|
|
|
|
|
|
|
|
|
|
|
|
// Loop over all attributes and add them if possible
|
|
|
|
|
|
bool quote = false;
|
|
|
|
|
|
string attrib = "", val = "";
|
|
|
|
|
|
for (int i = 2; i < gc.Length; i++)
|
2016-05-27 16:06:19 -07:00
|
|
|
|
{
|
2016-09-13 10:48:45 -07:00
|
|
|
|
//If the item is empty, we automatically skip it because it's a fluke
|
|
|
|
|
|
if (gc[i].Trim() == String.Empty)
|
2016-05-27 16:06:19 -07:00
|
|
|
|
{
|
2016-09-13 10:48:45 -07:00
|
|
|
|
continue;
|
2016-05-27 16:06:19 -07:00
|
|
|
|
}
|
2016-09-13 10:48:45 -07:00
|
|
|
|
// Special case for nodump...
|
|
|
|
|
|
else if (gc[i] == "nodump" && attrib != "status" && attrib != "flags")
|
|
|
|
|
|
{
|
|
|
|
|
|
rom.Nodump = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
// Even number of quotes, not in a quote, not in attribute
|
|
|
|
|
|
else if (Regex.Matches(gc[i], "\"").Count % 2 == 0 && !quote && attrib == "")
|
|
|
|
|
|
{
|
|
|
|
|
|
attrib = gc[i].Replace("\"", "");
|
|
|
|
|
|
}
|
|
|
|
|
|
// Even number of quotes, not in a quote, in attribute
|
|
|
|
|
|
else if (Regex.Matches(gc[i], "\"").Count % 2 == 0 && !quote && attrib != "")
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (attrib.ToLowerInvariant())
|
|
|
|
|
|
{
|
|
|
|
|
|
case "name":
|
|
|
|
|
|
rom.Name = gc[i].Replace("\"", "");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "size":
|
|
|
|
|
|
Int64.TryParse(gc[i].Replace("\"", ""), out rom.HashData.Size);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "crc":
|
|
|
|
|
|
rom.HashData.CRC = gc[i].Replace("\"", "").ToLowerInvariant();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "md5":
|
|
|
|
|
|
rom.HashData.MD5 = gc[i].Replace("\"", "").ToLowerInvariant();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "sha1":
|
|
|
|
|
|
rom.HashData.SHA1 = gc[i].Replace("\"", "").ToLowerInvariant();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "flags":
|
|
|
|
|
|
if (gc[i].Replace("\"", "").ToLowerInvariant() == "nodump")
|
|
|
|
|
|
{
|
|
|
|
|
|
rom.Nodump = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "date":
|
|
|
|
|
|
rom.Date = gc[i].Replace("\"", "") + " " + gc[i + 1].Replace("\"", "");
|
|
|
|
|
|
i++;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2016-05-27 16:06:19 -07:00
|
|
|
|
|
2016-09-13 10:48:45 -07:00
|
|
|
|
attrib = "";
|
|
|
|
|
|
}
|
|
|
|
|
|
// Even number of quotes, in a quote, not in attribute
|
|
|
|
|
|
else if (Regex.Matches(gc[i], "\"").Count % 2 == 0 && quote && attrib == "")
|
2016-05-27 16:06:19 -07:00
|
|
|
|
{
|
2016-09-13 10:48:45 -07:00
|
|
|
|
// Attributes can't have quoted names
|
|
|
|
|
|
}
|
|
|
|
|
|
// Even number of quotes, in a quote, in attribute
|
|
|
|
|
|
else if (Regex.Matches(gc[i], "\"").Count % 2 == 0 && quote && attrib != "")
|
|
|
|
|
|
{
|
|
|
|
|
|
val += " " + gc[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
// Odd number of quotes, not in a quote, not in attribute
|
|
|
|
|
|
else if (Regex.Matches(gc[i], "\"").Count % 2 == 1 && !quote && attrib == "")
|
|
|
|
|
|
{
|
|
|
|
|
|
// Attributes can't have quoted names
|
2016-05-27 16:06:19 -07:00
|
|
|
|
}
|
2016-09-13 10:48:45 -07:00
|
|
|
|
// Odd number of quotes, not in a quote, in attribute
|
|
|
|
|
|
else if (Regex.Matches(gc[i], "\"").Count % 2 == 1 && !quote && attrib != "")
|
|
|
|
|
|
{
|
|
|
|
|
|
val = gc[i].Replace("\"", "");
|
|
|
|
|
|
quote = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
// Odd number of quotes, in a quote, not in attribute
|
|
|
|
|
|
else if (Regex.Matches(gc[i], "\"").Count % 2 == 1 && quote && attrib == "")
|
|
|
|
|
|
{
|
|
|
|
|
|
quote = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
// Odd number of quotes, in a quote, in attribute
|
|
|
|
|
|
else if (Regex.Matches(gc[i], "\"").Count % 2 == 1 && quote && attrib != "")
|
|
|
|
|
|
{
|
|
|
|
|
|
val += " " + gc[i].Replace("\"", "");
|
|
|
|
|
|
switch (attrib.ToLowerInvariant())
|
|
|
|
|
|
{
|
|
|
|
|
|
case "name":
|
|
|
|
|
|
rom.Name = val;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "size":
|
|
|
|
|
|
Int64.TryParse(val, out rom.HashData.Size);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "crc":
|
|
|
|
|
|
rom.HashData.CRC = val.ToLowerInvariant();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "md5":
|
|
|
|
|
|
rom.HashData.MD5 = val.ToLowerInvariant();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "sha1":
|
|
|
|
|
|
rom.HashData.SHA1 = val.ToLowerInvariant();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "flags":
|
|
|
|
|
|
if (val.ToLowerInvariant() == "nodump")
|
|
|
|
|
|
{
|
|
|
|
|
|
rom.Nodump = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "date":
|
|
|
|
|
|
rom.Date = gc[i].Replace("\"", "") + " " + gc[i + 1].Replace("\"", "");
|
|
|
|
|
|
i++;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2016-05-27 16:06:19 -07:00
|
|
|
|
|
2016-09-13 10:48:45 -07:00
|
|
|
|
quote = false;
|
|
|
|
|
|
attrib = "";
|
|
|
|
|
|
val = "";
|
|
|
|
|
|
}
|
2016-05-27 16:06:19 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-06 11:38:55 -07:00
|
|
|
|
// Now process and add the rom
|
|
|
|
|
|
string key = "";
|
|
|
|
|
|
datdata = ParseAddHelper(rom, datdata, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, trim, single, root, clean, logger, out key);
|
2016-05-27 16:06:19 -07:00
|
|
|
|
}
|
|
|
|
|
|
// If the line is anything but a rom or disk and we're in a block
|
|
|
|
|
|
else if (Regex.IsMatch(line, Constants.ItemPatternCMP) && block)
|
|
|
|
|
|
{
|
|
|
|
|
|
GroupCollection gc = Regex.Match(line, Constants.ItemPatternCMP).Groups;
|
|
|
|
|
|
|
2016-09-12 23:04:28 -07:00
|
|
|
|
if (blockname != "header")
|
2016-05-27 16:06:19 -07:00
|
|
|
|
{
|
2016-09-12 23:04:28 -07:00
|
|
|
|
string itemval = gc[2].Value.Replace("\"", "");
|
|
|
|
|
|
switch (gc[1].Value)
|
|
|
|
|
|
{
|
|
|
|
|
|
case "name":
|
2016-09-13 16:04:24 -07:00
|
|
|
|
tempgamename = (itemval.ToLowerInvariant().EndsWith(".zip") ? itemval.Remove(itemval.Length - 4) : itemval);
|
2016-09-12 23:04:28 -07:00
|
|
|
|
break;
|
|
|
|
|
|
case "description":
|
|
|
|
|
|
gamedesc = itemval;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "romof":
|
|
|
|
|
|
romof = itemval;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "cloneof":
|
|
|
|
|
|
cloneof = itemval;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "year":
|
|
|
|
|
|
year = itemval;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "manufacturer":
|
|
|
|
|
|
manufacturer = itemval;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "sampleof":
|
|
|
|
|
|
sampleof = itemval;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2016-08-29 12:02:25 -07:00
|
|
|
|
}
|
2016-05-27 16:06:19 -07:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
string itemval = gc[2].Value.Replace("\"", "");
|
|
|
|
|
|
switch (gc[1].Value)
|
|
|
|
|
|
{
|
|
|
|
|
|
case "name":
|
2016-09-12 23:29:23 -07:00
|
|
|
|
case "Name:":
|
2016-05-27 16:06:19 -07:00
|
|
|
|
datdata.Name = (String.IsNullOrEmpty(datdata.Name) ? itemval : datdata.Name);
|
|
|
|
|
|
superdat = superdat || itemval.Contains(" - SuperDAT");
|
|
|
|
|
|
if (keep && superdat)
|
|
|
|
|
|
{
|
|
|
|
|
|
datdata.Type = (String.IsNullOrEmpty(datdata.Type) ? "SuperDAT" : datdata.Type);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "description":
|
2016-09-12 23:29:23 -07:00
|
|
|
|
case "Description:":
|
2016-05-27 16:06:19 -07:00
|
|
|
|
datdata.Description = (String.IsNullOrEmpty(datdata.Description) ? itemval : datdata.Description);
|
|
|
|
|
|
break;
|
2016-07-25 10:19:20 -07:00
|
|
|
|
case "rootdir":
|
|
|
|
|
|
datdata.RootDir = (String.IsNullOrEmpty(datdata.RootDir) ? itemval : datdata.RootDir);
|
|
|
|
|
|
break;
|
2016-05-27 16:06:19 -07:00
|
|
|
|
case "category":
|
|
|
|
|
|
datdata.Category = (String.IsNullOrEmpty(datdata.Category) ? itemval : datdata.Category);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "version":
|
2016-09-12 23:29:23 -07:00
|
|
|
|
case "Version:":
|
2016-05-27 16:06:19 -07:00
|
|
|
|
datdata.Version = (String.IsNullOrEmpty(datdata.Version) ? itemval : datdata.Version);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "date":
|
2016-09-12 23:29:23 -07:00
|
|
|
|
case "Date:":
|
2016-05-27 16:06:19 -07:00
|
|
|
|
datdata.Date = (String.IsNullOrEmpty(datdata.Date) ? itemval : datdata.Date);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "author":
|
2016-09-12 23:29:23 -07:00
|
|
|
|
case "Author:":
|
2016-05-27 16:06:19 -07:00
|
|
|
|
datdata.Author = (String.IsNullOrEmpty(datdata.Author) ? itemval : datdata.Author);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "email":
|
|
|
|
|
|
datdata.Email = (String.IsNullOrEmpty(datdata.Email) ? itemval : datdata.Email);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "homepage":
|
2016-09-12 23:29:23 -07:00
|
|
|
|
case "Homepage:":
|
2016-05-27 16:06:19 -07:00
|
|
|
|
datdata.Homepage = (String.IsNullOrEmpty(datdata.Homepage) ? itemval : datdata.Homepage);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "url":
|
|
|
|
|
|
datdata.Url = (String.IsNullOrEmpty(datdata.Url) ? itemval : datdata.Url);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "comment":
|
2016-09-12 23:29:23 -07:00
|
|
|
|
case "Comment:":
|
2016-05-27 16:06:19 -07:00
|
|
|
|
datdata.Comment = (String.IsNullOrEmpty(datdata.Comment) ? itemval : datdata.Comment);
|
|
|
|
|
|
break;
|
2016-06-16 17:01:33 -07:00
|
|
|
|
case "header":
|
|
|
|
|
|
datdata.Header = (String.IsNullOrEmpty(datdata.Header) ? itemval : datdata.Header);
|
|
|
|
|
|
break;
|
2016-05-27 16:06:19 -07:00
|
|
|
|
case "type":
|
|
|
|
|
|
datdata.Type = (String.IsNullOrEmpty(datdata.Type) ? itemval : datdata.Type);
|
|
|
|
|
|
superdat = superdat || itemval.Contains("SuperDAT");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "forcemerging":
|
|
|
|
|
|
switch (itemval)
|
|
|
|
|
|
{
|
|
|
|
|
|
case "none":
|
|
|
|
|
|
datdata.ForceMerging = ForceMerging.None;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "split":
|
|
|
|
|
|
datdata.ForceMerging = ForceMerging.Split;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "full":
|
|
|
|
|
|
datdata.ForceMerging = ForceMerging.Full;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "forcezipping":
|
2016-09-13 10:48:45 -07:00
|
|
|
|
switch (itemval)
|
|
|
|
|
|
{
|
|
|
|
|
|
case "yes":
|
|
|
|
|
|
datdata.ForcePacking = ForcePacking.Zip;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "no":
|
|
|
|
|
|
datdata.ForcePacking = ForcePacking.Unzip;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2016-05-27 16:06:19 -07:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// If we find an end bracket that's not associated with anything else, the block is done
|
|
|
|
|
|
else if (Regex.IsMatch(line, Constants.EndPatternCMP) && block)
|
|
|
|
|
|
{
|
|
|
|
|
|
block = false;
|
|
|
|
|
|
blockname = "";
|
2016-09-06 11:38:55 -07:00
|
|
|
|
tempgamename = "";
|
2016-05-27 16:06:19 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-06-13 10:29:07 -07:00
|
|
|
|
sr.Close();
|
|
|
|
|
|
sr.Dispose();
|
|
|
|
|
|
|
2016-05-27 16:06:19 -07:00
|
|
|
|
return datdata;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Parse a RomCenter DAT and return all found games and roms within
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="filename">Name of the file to be parsed</param>
|
|
|
|
|
|
/// <param name="sysid">System ID for the DAT</param>
|
|
|
|
|
|
/// <param name="srcid">Source ID for the DAT</param>
|
|
|
|
|
|
/// <param name="datdata">The DatData object representing found roms to this point</param>
|
2016-09-06 11:38:55 -07:00
|
|
|
|
/// <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="romtype">Type of the rom to match</param>
|
|
|
|
|
|
/// <param name="sgt">Find roms greater than or equal to this size</param>
|
|
|
|
|
|
/// <param name="slt">Find roms less than or equal to this size</param>
|
|
|
|
|
|
/// <param name="seq">Find roms equal to this size</param>
|
|
|
|
|
|
/// <param name="crc">CRC of the rom to match (can use asterisk-partials)</param>
|
|
|
|
|
|
/// <param name="md5">MD5 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="trim">True if we are supposed to trim names to NTFS length, false otherwise</param>
|
|
|
|
|
|
/// <param name="single">True if all games should be replaced by '!', false otherwise</param>
|
|
|
|
|
|
/// <param name="root">String representing root directory to compare against for length calculation</param>
|
2016-05-27 16:06:19 -07:00
|
|
|
|
/// <param name="logger">Logger object for console and/or file output</param>
|
2016-05-29 13:36:02 -07:00
|
|
|
|
/// <param name="clean">True if game names are sanitized, false otherwise (default)</param>
|
2016-05-27 16:06:19 -07:00
|
|
|
|
/// <returns>DatData object representing the read-in data</returns>
|
2016-09-06 11:38:55 -07:00
|
|
|
|
private static Dat ParseRC(
|
|
|
|
|
|
// Standard Dat parsing
|
|
|
|
|
|
string filename,
|
|
|
|
|
|
int sysid,
|
|
|
|
|
|
int srcid,
|
|
|
|
|
|
Dat datdata,
|
|
|
|
|
|
|
|
|
|
|
|
// Rom filtering
|
|
|
|
|
|
string gamename,
|
|
|
|
|
|
string romname,
|
|
|
|
|
|
string romtype,
|
|
|
|
|
|
long sgt,
|
|
|
|
|
|
long slt,
|
|
|
|
|
|
long seq,
|
|
|
|
|
|
string crc,
|
|
|
|
|
|
string md5,
|
|
|
|
|
|
string sha1,
|
|
|
|
|
|
bool? nodump,
|
|
|
|
|
|
|
|
|
|
|
|
// Rom renaming
|
|
|
|
|
|
bool trim,
|
|
|
|
|
|
bool single,
|
|
|
|
|
|
string root,
|
|
|
|
|
|
|
|
|
|
|
|
// Miscellaneous
|
|
|
|
|
|
Logger logger,
|
|
|
|
|
|
bool clean)
|
2016-05-27 16:06:19 -07:00
|
|
|
|
{
|
2016-09-06 11:38:55 -07:00
|
|
|
|
// Open a file reader
|
2016-08-29 16:33:07 -07:00
|
|
|
|
StreamReader sr = new StreamReader(File.OpenRead(filename));
|
2016-05-27 16:06:19 -07:00
|
|
|
|
|
|
|
|
|
|
string blocktype = "";
|
|
|
|
|
|
while (!sr.EndOfStream)
|
|
|
|
|
|
{
|
|
|
|
|
|
string line = sr.ReadLine();
|
|
|
|
|
|
|
|
|
|
|
|
// If the line is the start of the credits section
|
|
|
|
|
|
if (line.ToLowerInvariant().Contains("[credits]"))
|
|
|
|
|
|
{
|
|
|
|
|
|
blocktype = "credits";
|
|
|
|
|
|
}
|
|
|
|
|
|
// If the line is the start of the dat section
|
|
|
|
|
|
else if (line.ToLowerInvariant().Contains("[dat]"))
|
|
|
|
|
|
{
|
|
|
|
|
|
blocktype = "dat";
|
|
|
|
|
|
}
|
|
|
|
|
|
// If the line is the start of the emulator section
|
|
|
|
|
|
else if (line.ToLowerInvariant().Contains("[emulator]"))
|
|
|
|
|
|
{
|
|
|
|
|
|
blocktype = "emulator";
|
|
|
|
|
|
}
|
|
|
|
|
|
// If the line is the start of the game section
|
|
|
|
|
|
else if (line.ToLowerInvariant().Contains("[games]"))
|
|
|
|
|
|
{
|
|
|
|
|
|
blocktype = "games";
|
|
|
|
|
|
}
|
|
|
|
|
|
// Otherwise, it's not a section and it's data, so get out all data
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// If we have an author
|
|
|
|
|
|
if (line.StartsWith("author="))
|
|
|
|
|
|
{
|
|
|
|
|
|
datdata.Author = (String.IsNullOrEmpty(datdata.Author) ? line.Split('=')[1] : datdata.Author);
|
|
|
|
|
|
}
|
|
|
|
|
|
// If we have one of the three version tags
|
|
|
|
|
|
else if (line.StartsWith("version="))
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (blocktype)
|
|
|
|
|
|
{
|
|
|
|
|
|
case "credits":
|
|
|
|
|
|
datdata.Version = (String.IsNullOrEmpty(datdata.Version) ? line.Split('=')[1] : datdata.Version);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "emulator":
|
|
|
|
|
|
datdata.Description = (String.IsNullOrEmpty(datdata.Description) ? line.Split('=')[1] : datdata.Description);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// If we have a comment
|
|
|
|
|
|
else if (line.StartsWith("comment="))
|
|
|
|
|
|
{
|
|
|
|
|
|
datdata.Comment = (String.IsNullOrEmpty(datdata.Comment) ? line.Split('=')[1] : datdata.Comment);
|
|
|
|
|
|
}
|
|
|
|
|
|
// If we have the split flag
|
|
|
|
|
|
else if (line.StartsWith("split="))
|
|
|
|
|
|
{
|
|
|
|
|
|
int split = 0;
|
|
|
|
|
|
if (Int32.TryParse(line.Split('=')[1], out split))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (split == 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
datdata.ForceMerging = ForceMerging.Split;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// If we have the merge tag
|
|
|
|
|
|
else if (line.StartsWith("merge="))
|
|
|
|
|
|
{
|
|
|
|
|
|
int merge = 0;
|
|
|
|
|
|
if (Int32.TryParse(line.Split('=')[1], out merge))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (merge == 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
datdata.ForceMerging = ForceMerging.Full;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// If we have the refname tag
|
|
|
|
|
|
else if (line.StartsWith("refname="))
|
|
|
|
|
|
{
|
|
|
|
|
|
datdata.Name = (String.IsNullOrEmpty(datdata.Name) ? line.Split('=')[1] : datdata.Name);
|
|
|
|
|
|
}
|
|
|
|
|
|
// If we have a rom
|
|
|
|
|
|
else if (line.StartsWith("¬"))
|
|
|
|
|
|
{
|
|
|
|
|
|
/*
|
|
|
|
|
|
The rominfo order is as follows:
|
|
|
|
|
|
1 - parent name
|
|
|
|
|
|
2 - parent description
|
|
|
|
|
|
3 - game name
|
|
|
|
|
|
4 - game description
|
|
|
|
|
|
5 - rom name
|
|
|
|
|
|
6 - rom crc
|
|
|
|
|
|
7 - rom size
|
|
|
|
|
|
8 - romof name
|
|
|
|
|
|
9 - merge name
|
|
|
|
|
|
*/
|
|
|
|
|
|
string[] rominfo = line.Split('¬');
|
2016-05-29 13:36:02 -07:00
|
|
|
|
|
2016-08-29 13:57:46 -07:00
|
|
|
|
Rom rom = new Rom
|
2016-05-27 16:06:19 -07:00
|
|
|
|
{
|
2016-08-29 13:42:27 -07:00
|
|
|
|
Machine = new Machine
|
2016-08-29 13:41:42 -07:00
|
|
|
|
{
|
|
|
|
|
|
Name = rominfo[3],
|
|
|
|
|
|
Description = rominfo[4],
|
2016-09-12 23:04:28 -07:00
|
|
|
|
CloneOf = rominfo[1],
|
|
|
|
|
|
RomOf = rominfo[8],
|
2016-08-29 13:41:42 -07:00
|
|
|
|
},
|
2016-05-27 16:06:19 -07:00
|
|
|
|
Name = rominfo[5],
|
2016-08-29 14:43:31 -07:00
|
|
|
|
HashData = new Hash
|
2016-08-29 13:05:32 -07:00
|
|
|
|
{
|
|
|
|
|
|
CRC = rominfo[6].ToLowerInvariant(),
|
|
|
|
|
|
Size = Int64.Parse(rominfo[7]),
|
|
|
|
|
|
},
|
2016-06-16 17:27:32 -07:00
|
|
|
|
Metadata = new SourceMetadata { SystemID = sysid, SourceID = srcid },
|
2016-05-27 16:06:19 -07:00
|
|
|
|
};
|
|
|
|
|
|
|
2016-09-06 11:38:55 -07:00
|
|
|
|
// Now process and add the rom
|
|
|
|
|
|
string key = "";
|
|
|
|
|
|
datdata = ParseAddHelper(rom, datdata, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, trim, single, root, clean, logger, out key);
|
2016-05-27 16:06:19 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-06-13 10:29:07 -07:00
|
|
|
|
sr.Close();
|
|
|
|
|
|
sr.Dispose();
|
|
|
|
|
|
|
2016-05-27 16:06:19 -07:00
|
|
|
|
return datdata;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Parse an XML DAT (Logiqx, SabreDAT, or SL) and return all found games and roms within
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="filename">Name of the file to be parsed</param>
|
|
|
|
|
|
/// <param name="sysid">System ID for the DAT</param>
|
|
|
|
|
|
/// <param name="srcid">Source ID for the DAT</param>
|
|
|
|
|
|
/// <param name="datdata">The DatData object representing found roms to this point</param>
|
2016-09-06 11:38:55 -07:00
|
|
|
|
/// <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="romtype">Type of the rom to match</param>
|
|
|
|
|
|
/// <param name="sgt">Find roms greater than or equal to this size</param>
|
|
|
|
|
|
/// <param name="slt">Find roms less than or equal to this size</param>
|
|
|
|
|
|
/// <param name="seq">Find roms equal to this size</param>
|
|
|
|
|
|
/// <param name="crc">CRC of the rom to match (can use asterisk-partials)</param>
|
|
|
|
|
|
/// <param name="md5">MD5 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="trim">True if we are supposed to trim names to NTFS length, false otherwise</param>
|
|
|
|
|
|
/// <param name="single">True if all games should be replaced by '!', false otherwise</param>
|
|
|
|
|
|
/// <param name="root">String representing root directory to compare against for length calculation</param>
|
2016-05-27 16:06:19 -07:00
|
|
|
|
/// <param name="logger">Logger object for console and/or file output</param>
|
2016-05-29 13:27:34 -07:00
|
|
|
|
/// <param name="keep">True if full pathnames are to be kept, false otherwise (default)</param>
|
|
|
|
|
|
/// <param name="clean">True if game names are sanitized, false otherwise (default)</param>
|
2016-07-12 11:03:02 -07:00
|
|
|
|
/// <param name="softlist">True if SL XML names should be kept, false otherwise (default)</param>
|
2016-05-27 16:06:19 -07:00
|
|
|
|
/// <returns>DatData object representing the read-in data</returns>
|
2016-09-06 11:38:55 -07:00
|
|
|
|
private static Dat ParseXML(
|
|
|
|
|
|
// Standard Dat parsing
|
|
|
|
|
|
string filename,
|
|
|
|
|
|
int sysid,
|
|
|
|
|
|
int srcid,
|
|
|
|
|
|
Dat datdata,
|
|
|
|
|
|
|
|
|
|
|
|
// Rom filtering
|
|
|
|
|
|
string gamename,
|
|
|
|
|
|
string romname,
|
|
|
|
|
|
string romtype,
|
|
|
|
|
|
long sgt,
|
|
|
|
|
|
long slt,
|
|
|
|
|
|
long seq,
|
|
|
|
|
|
string crc,
|
|
|
|
|
|
string md5,
|
|
|
|
|
|
string sha1,
|
|
|
|
|
|
bool? nodump,
|
|
|
|
|
|
|
|
|
|
|
|
// Rom renaming
|
|
|
|
|
|
bool trim,
|
|
|
|
|
|
bool single,
|
|
|
|
|
|
string root,
|
|
|
|
|
|
|
|
|
|
|
|
// Miscellaneous
|
|
|
|
|
|
Logger logger,
|
|
|
|
|
|
bool keep,
|
|
|
|
|
|
bool clean,
|
|
|
|
|
|
bool softlist)
|
2016-05-27 16:06:19 -07:00
|
|
|
|
{
|
2016-05-18 23:51:54 -07:00
|
|
|
|
// Prepare all internal variables
|
|
|
|
|
|
XmlReader subreader, headreader, flagreader;
|
2016-09-06 11:38:55 -07:00
|
|
|
|
bool superdat = false, isnodump = false, empty = true;
|
|
|
|
|
|
string key = "", date = "";
|
2016-05-18 23:51:54 -07:00
|
|
|
|
long size = -1;
|
|
|
|
|
|
List<string> parent = new List<string>();
|
|
|
|
|
|
|
2016-04-28 10:37:33 -07:00
|
|
|
|
XmlTextReader xtr = GetXmlTextReader(filename, logger);
|
|
|
|
|
|
if (xtr != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
xtr.MoveToContent();
|
2016-05-19 11:00:10 -07:00
|
|
|
|
while (!xtr.EOF)
|
2016-04-28 10:37:33 -07:00
|
|
|
|
{
|
2016-05-19 10:28:53 -07:00
|
|
|
|
// If we're ending a folder or game, take care of possibly empty games and removing from the parent
|
|
|
|
|
|
if (xtr.NodeType == XmlNodeType.EndElement && (xtr.Name == "directory" || xtr.Name == "dir"))
|
2016-05-18 23:51:54 -07:00
|
|
|
|
{
|
2016-05-19 10:28:53 -07:00
|
|
|
|
// If we didn't find any items in the folder, make sure to add the blank rom
|
|
|
|
|
|
if (empty)
|
2016-05-19 09:30:38 -07:00
|
|
|
|
{
|
2016-05-21 15:04:33 +02:00
|
|
|
|
string tempgame = String.Join("\\", parent);
|
|
|
|
|
|
|
2016-08-29 13:57:46 -07:00
|
|
|
|
Rom rom = new Rom
|
2016-05-19 10:28:53 -07:00
|
|
|
|
{
|
2016-08-29 13:50:55 -07:00
|
|
|
|
Type = ItemType.Rom,
|
2016-05-19 10:28:53 -07:00
|
|
|
|
Name = "null",
|
2016-08-29 13:42:27 -07:00
|
|
|
|
Machine = new Machine
|
2016-08-29 13:41:42 -07:00
|
|
|
|
{
|
|
|
|
|
|
Name = tempgame,
|
|
|
|
|
|
Description = tempgame,
|
|
|
|
|
|
},
|
2016-08-29 14:43:31 -07:00
|
|
|
|
HashData = new Hash
|
2016-08-29 13:05:32 -07:00
|
|
|
|
{
|
|
|
|
|
|
Size = -1,
|
|
|
|
|
|
CRC = "null",
|
|
|
|
|
|
MD5 = "null",
|
|
|
|
|
|
SHA1 = "null",
|
|
|
|
|
|
},
|
2016-05-19 10:28:53 -07:00
|
|
|
|
};
|
|
|
|
|
|
|
2016-09-06 11:38:55 -07:00
|
|
|
|
// Now process and add the rom
|
|
|
|
|
|
datdata = ParseAddHelper(rom, datdata, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, trim, single, root, clean, logger, out key);
|
2016-05-19 10:28:53 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Regardless, end the current folder
|
2016-05-20 23:56:21 -07:00
|
|
|
|
int parentcount = parent.Count;
|
|
|
|
|
|
if (parentcount == 0)
|
2016-05-19 10:56:36 -07:00
|
|
|
|
{
|
2016-05-22 17:24:19 -07:00
|
|
|
|
logger.Log("Empty parent: " + String.Join("\\", parent));
|
2016-05-19 10:56:36 -07:00
|
|
|
|
empty = true;
|
|
|
|
|
|
}
|
2016-05-19 10:28:53 -07:00
|
|
|
|
|
|
|
|
|
|
// If we have an end folder element, remove one item from the parent, if possible
|
2016-05-20 23:56:21 -07:00
|
|
|
|
if (parentcount > 0)
|
2016-05-19 10:28:53 -07:00
|
|
|
|
{
|
|
|
|
|
|
parent.RemoveAt(parent.Count - 1);
|
2016-05-20 23:56:21 -07:00
|
|
|
|
if (keep && parentcount > 1)
|
2016-05-19 10:28:53 -07:00
|
|
|
|
{
|
|
|
|
|
|
datdata.Type = (String.IsNullOrEmpty(datdata.Type) ? "SuperDAT" : datdata.Type);
|
2016-05-19 12:19:28 -07:00
|
|
|
|
superdat = true;
|
2016-05-19 10:28:53 -07:00
|
|
|
|
}
|
2016-05-19 09:30:38 -07:00
|
|
|
|
}
|
2016-05-18 23:51:54 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-28 10:37:33 -07:00
|
|
|
|
// We only want elements
|
|
|
|
|
|
if (xtr.NodeType != XmlNodeType.Element)
|
|
|
|
|
|
{
|
2016-05-19 10:56:36 -07:00
|
|
|
|
xtr.Read();
|
|
|
|
|
|
continue;
|
2016-04-28 10:37:33 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
switch (xtr.Name)
|
|
|
|
|
|
{
|
2016-09-13 11:24:02 -07:00
|
|
|
|
// Handle MAME listxml since they're halfway between a SL and a Logiqx XML
|
|
|
|
|
|
case "mame":
|
|
|
|
|
|
if (xtr.GetAttribute("build") != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
datdata.Name = (String.IsNullOrEmpty(datdata.Name) ? xtr.GetAttribute("build") : datdata.Name);
|
|
|
|
|
|
datdata.Description = (String.IsNullOrEmpty(datdata.Description) ? datdata.Name : datdata.Name);
|
|
|
|
|
|
}
|
|
|
|
|
|
xtr.Read();
|
|
|
|
|
|
break;
|
2016-05-27 10:47:41 -07:00
|
|
|
|
// New software lists have this behavior
|
|
|
|
|
|
case "softwarelist":
|
|
|
|
|
|
if (xtr.GetAttribute("name") != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
datdata.Name = (String.IsNullOrEmpty(datdata.Name) ? xtr.GetAttribute("name") : datdata.Name);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (xtr.GetAttribute("description") != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
datdata.Description = (String.IsNullOrEmpty(datdata.Description) ? xtr.GetAttribute("description") : datdata.Description);
|
|
|
|
|
|
}
|
2016-05-27 10:55:21 -07:00
|
|
|
|
xtr.Read();
|
2016-05-27 10:47:41 -07:00
|
|
|
|
break;
|
2016-05-27 16:59:28 -07:00
|
|
|
|
// Handle M1 DATs since they're 99% the same as a SL DAT
|
|
|
|
|
|
case "m1":
|
|
|
|
|
|
datdata.Name = (String.IsNullOrEmpty(datdata.Name) ? "M1" : datdata.Name);
|
|
|
|
|
|
datdata.Description = (String.IsNullOrEmpty(datdata.Description) ? "M1" : datdata.Description);
|
|
|
|
|
|
if (xtr.GetAttribute("version") != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
datdata.Version = (String.IsNullOrEmpty(datdata.Version) ? xtr.GetAttribute("version") : datdata.Version);
|
|
|
|
|
|
}
|
2016-09-13 11:24:02 -07:00
|
|
|
|
xtr.Read();
|
2016-05-27 16:59:28 -07:00
|
|
|
|
break;
|
2016-09-06 11:38:55 -07:00
|
|
|
|
// We want to process the entire subtree of the header
|
2016-04-28 10:37:33 -07:00
|
|
|
|
case "header":
|
2016-05-18 23:51:54 -07:00
|
|
|
|
headreader = xtr.ReadSubtree();
|
2016-05-16 14:28:23 -07:00
|
|
|
|
|
|
|
|
|
|
if (headreader != null)
|
2016-04-28 10:37:33 -07:00
|
|
|
|
{
|
2016-05-16 15:17:11 -07:00
|
|
|
|
while (!headreader.EOF)
|
2016-05-16 14:28:23 -07:00
|
|
|
|
{
|
|
|
|
|
|
// We only want elements
|
2016-05-16 15:17:11 -07:00
|
|
|
|
if (headreader.NodeType != XmlNodeType.Element || headreader.Name == "header")
|
2016-05-16 14:28:23 -07:00
|
|
|
|
{
|
2016-05-16 15:17:11 -07:00
|
|
|
|
headreader.Read();
|
2016-05-16 14:28:23 -07:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Get all header items (ONLY OVERWRITE IF THERE'S NO DATA)
|
2016-05-16 15:17:11 -07:00
|
|
|
|
string content = "";
|
|
|
|
|
|
switch (headreader.Name)
|
2016-05-16 14:28:23 -07:00
|
|
|
|
{
|
|
|
|
|
|
case "name":
|
2016-05-17 16:53:02 -07:00
|
|
|
|
content = headreader.ReadElementContentAsString(); ;
|
2016-05-18 23:51:54 -07:00
|
|
|
|
datdata.Name = (String.IsNullOrEmpty(datdata.Name) ? content : datdata.Name);
|
2016-05-17 16:53:02 -07:00
|
|
|
|
superdat = superdat || content.Contains(" - SuperDAT");
|
2016-05-20 23:56:21 -07:00
|
|
|
|
if (keep && superdat)
|
2016-05-18 23:51:54 -07:00
|
|
|
|
{
|
|
|
|
|
|
datdata.Type = (String.IsNullOrEmpty(datdata.Type) ? "SuperDAT" : datdata.Type);
|
|
|
|
|
|
}
|
2016-05-16 14:28:23 -07:00
|
|
|
|
break;
|
|
|
|
|
|
case "description":
|
2016-05-16 15:17:11 -07:00
|
|
|
|
content = headreader.ReadElementContentAsString();
|
2016-05-18 23:51:54 -07:00
|
|
|
|
datdata.Description = (String.IsNullOrEmpty(datdata.Description) ? content : datdata.Description);
|
2016-05-16 14:28:23 -07:00
|
|
|
|
break;
|
2016-07-25 10:19:20 -07:00
|
|
|
|
case "rootdir":
|
|
|
|
|
|
content = headreader.ReadElementContentAsString();
|
|
|
|
|
|
datdata.RootDir = (String.IsNullOrEmpty(datdata.RootDir) ? content : datdata.RootDir);
|
|
|
|
|
|
break;
|
2016-05-16 14:28:23 -07:00
|
|
|
|
case "category":
|
2016-05-16 15:17:11 -07:00
|
|
|
|
content = headreader.ReadElementContentAsString();
|
2016-05-18 23:51:54 -07:00
|
|
|
|
datdata.Category = (String.IsNullOrEmpty(datdata.Category) ? content : datdata.Category);
|
2016-05-16 14:28:23 -07:00
|
|
|
|
break;
|
|
|
|
|
|
case "version":
|
2016-05-16 15:17:11 -07:00
|
|
|
|
content = headreader.ReadElementContentAsString();
|
2016-05-18 23:51:54 -07:00
|
|
|
|
datdata.Version = (String.IsNullOrEmpty(datdata.Version) ? content : datdata.Version);
|
2016-05-16 14:28:23 -07:00
|
|
|
|
break;
|
|
|
|
|
|
case "date":
|
2016-05-16 15:17:11 -07:00
|
|
|
|
content = headreader.ReadElementContentAsString();
|
2016-09-14 09:54:29 -07:00
|
|
|
|
datdata.Date = (String.IsNullOrEmpty(datdata.Date) ? content.Replace(".", "/") : datdata.Date);
|
2016-05-16 14:28:23 -07:00
|
|
|
|
break;
|
|
|
|
|
|
case "author":
|
2016-05-16 15:17:11 -07:00
|
|
|
|
content = headreader.ReadElementContentAsString();
|
2016-05-18 23:51:54 -07:00
|
|
|
|
datdata.Author = (String.IsNullOrEmpty(datdata.Author) ? content : datdata.Author);
|
|
|
|
|
|
|
|
|
|
|
|
// Special cases for SabreDAT
|
|
|
|
|
|
datdata.Email = (String.IsNullOrEmpty(datdata.Email) && !String.IsNullOrEmpty(headreader.GetAttribute("email")) ?
|
|
|
|
|
|
headreader.GetAttribute("email") : datdata.Email);
|
|
|
|
|
|
datdata.Homepage = (String.IsNullOrEmpty(datdata.Homepage) && !String.IsNullOrEmpty(headreader.GetAttribute("homepage")) ?
|
|
|
|
|
|
headreader.GetAttribute("homepage") : datdata.Email);
|
|
|
|
|
|
datdata.Url = (String.IsNullOrEmpty(datdata.Url) && !String.IsNullOrEmpty(headreader.GetAttribute("url")) ?
|
|
|
|
|
|
headreader.GetAttribute("url") : datdata.Email);
|
2016-05-16 14:28:23 -07:00
|
|
|
|
break;
|
|
|
|
|
|
case "email":
|
2016-05-16 15:17:11 -07:00
|
|
|
|
content = headreader.ReadElementContentAsString();
|
2016-05-18 23:51:54 -07:00
|
|
|
|
datdata.Email = (String.IsNullOrEmpty(datdata.Email) ? content : datdata.Email);
|
2016-05-16 14:28:23 -07:00
|
|
|
|
break;
|
|
|
|
|
|
case "homepage":
|
2016-05-16 15:17:11 -07:00
|
|
|
|
content = headreader.ReadElementContentAsString();
|
2016-05-18 23:51:54 -07:00
|
|
|
|
datdata.Homepage = (String.IsNullOrEmpty(datdata.Homepage) ? content : datdata.Homepage);
|
2016-05-16 14:28:23 -07:00
|
|
|
|
break;
|
|
|
|
|
|
case "url":
|
2016-05-16 15:17:11 -07:00
|
|
|
|
content = headreader.ReadElementContentAsString();
|
2016-05-18 23:51:54 -07:00
|
|
|
|
datdata.Url = (String.IsNullOrEmpty(datdata.Url) ? content : datdata.Url);
|
2016-05-16 14:28:23 -07:00
|
|
|
|
break;
|
|
|
|
|
|
case "comment":
|
2016-05-16 15:17:11 -07:00
|
|
|
|
content = headreader.ReadElementContentAsString();
|
2016-05-18 23:51:54 -07:00
|
|
|
|
datdata.Comment = (String.IsNullOrEmpty(datdata.Comment) ? content : datdata.Comment);
|
2016-05-16 14:28:23 -07:00
|
|
|
|
break;
|
2016-05-17 16:53:02 -07:00
|
|
|
|
case "type":
|
|
|
|
|
|
content = headreader.ReadElementContentAsString();
|
2016-05-18 23:51:54 -07:00
|
|
|
|
datdata.Type = (String.IsNullOrEmpty(datdata.Type) ? content : datdata.Type);
|
2016-05-17 16:53:02 -07:00
|
|
|
|
superdat = superdat || content.Contains("SuperDAT");
|
|
|
|
|
|
break;
|
2016-05-16 14:28:23 -07:00
|
|
|
|
case "clrmamepro":
|
2016-09-13 10:48:45 -07:00
|
|
|
|
case "romcenter":
|
2016-06-16 17:01:33 -07:00
|
|
|
|
if (headreader.GetAttribute("header") != null)
|
|
|
|
|
|
{
|
2016-06-16 17:06:52 -07:00
|
|
|
|
datdata.Header = (String.IsNullOrEmpty(datdata.Header) ? headreader.GetAttribute("header") : datdata.Header);
|
2016-06-16 17:01:33 -07:00
|
|
|
|
}
|
2016-09-13 10:48:45 -07:00
|
|
|
|
if (headreader.GetAttribute("plugin") != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
datdata.Header = (String.IsNullOrEmpty(datdata.Header) ? headreader.GetAttribute("plugin") : datdata.Header);
|
|
|
|
|
|
}
|
2016-05-16 14:28:23 -07:00
|
|
|
|
if (headreader.GetAttribute("forcemerging") != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (headreader.GetAttribute("forcemerging"))
|
|
|
|
|
|
{
|
|
|
|
|
|
case "split":
|
|
|
|
|
|
datdata.ForceMerging = ForceMerging.Split;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "none":
|
|
|
|
|
|
datdata.ForceMerging = ForceMerging.None;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "full":
|
|
|
|
|
|
datdata.ForceMerging = ForceMerging.Full;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (headreader.GetAttribute("forcenodump") != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (headreader.GetAttribute("forcenodump"))
|
|
|
|
|
|
{
|
|
|
|
|
|
case "obsolete":
|
|
|
|
|
|
datdata.ForceNodump = ForceNodump.Obsolete;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "required":
|
|
|
|
|
|
datdata.ForceNodump = ForceNodump.Required;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "ignore":
|
|
|
|
|
|
datdata.ForceNodump = ForceNodump.Ignore;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (headreader.GetAttribute("forcepacking") != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (headreader.GetAttribute("forcepacking"))
|
|
|
|
|
|
{
|
|
|
|
|
|
case "zip":
|
|
|
|
|
|
datdata.ForcePacking = ForcePacking.Zip;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "unzip":
|
|
|
|
|
|
datdata.ForcePacking = ForcePacking.Unzip;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-05-16 15:17:11 -07:00
|
|
|
|
headreader.Read();
|
2016-05-16 14:28:23 -07:00
|
|
|
|
break;
|
2016-05-18 23:51:54 -07:00
|
|
|
|
case "flags":
|
|
|
|
|
|
flagreader = xtr.ReadSubtree();
|
|
|
|
|
|
if (flagreader != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
while (!flagreader.EOF)
|
|
|
|
|
|
{
|
|
|
|
|
|
// We only want elements
|
|
|
|
|
|
if (flagreader.NodeType != XmlNodeType.Element || flagreader.Name == "flags")
|
|
|
|
|
|
{
|
|
|
|
|
|
flagreader.Read();
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
switch (flagreader.Name)
|
|
|
|
|
|
{
|
|
|
|
|
|
case "flag":
|
|
|
|
|
|
if (flagreader.GetAttribute("name") != null && flagreader.GetAttribute("value") != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
content = flagreader.GetAttribute("value");
|
|
|
|
|
|
switch (flagreader.GetAttribute("name"))
|
|
|
|
|
|
{
|
|
|
|
|
|
case "type":
|
2016-06-02 10:29:46 -07:00
|
|
|
|
datdata.Type = (String.IsNullOrEmpty(datdata.Type) ? content : datdata.Type);
|
2016-05-18 23:51:54 -07:00
|
|
|
|
superdat = superdat || content.Contains("SuperDAT");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "forcemerging":
|
|
|
|
|
|
switch (content)
|
|
|
|
|
|
{
|
|
|
|
|
|
case "split":
|
|
|
|
|
|
datdata.ForceMerging = ForceMerging.Split;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "none":
|
|
|
|
|
|
datdata.ForceMerging = ForceMerging.None;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "full":
|
|
|
|
|
|
datdata.ForceMerging = ForceMerging.Full;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "forcenodump":
|
|
|
|
|
|
switch (content)
|
|
|
|
|
|
{
|
|
|
|
|
|
case "obsolete":
|
|
|
|
|
|
datdata.ForceNodump = ForceNodump.Obsolete;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "required":
|
|
|
|
|
|
datdata.ForceNodump = ForceNodump.Required;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "ignore":
|
|
|
|
|
|
datdata.ForceNodump = ForceNodump.Ignore;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "forcepacking":
|
|
|
|
|
|
switch (content)
|
|
|
|
|
|
{
|
|
|
|
|
|
case "zip":
|
|
|
|
|
|
datdata.ForcePacking = ForcePacking.Zip;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "unzip":
|
|
|
|
|
|
datdata.ForcePacking = ForcePacking.Unzip;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
flagreader.Read();
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
flagreader.Read();
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
headreader.Skip();
|
|
|
|
|
|
break;
|
2016-05-16 22:25:03 -07:00
|
|
|
|
default:
|
|
|
|
|
|
headreader.Read();
|
|
|
|
|
|
break;
|
2016-05-16 14:28:23 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-04-28 10:37:33 -07:00
|
|
|
|
}
|
2016-05-16 14:28:23 -07:00
|
|
|
|
|
|
|
|
|
|
// Skip the header node now that we've processed it
|
|
|
|
|
|
xtr.Skip();
|
2016-04-28 10:37:33 -07:00
|
|
|
|
break;
|
|
|
|
|
|
case "machine":
|
|
|
|
|
|
case "game":
|
|
|
|
|
|
case "software":
|
|
|
|
|
|
string temptype = xtr.Name;
|
2016-09-12 23:04:28 -07:00
|
|
|
|
string tempname = "", gamedesc = "", romof = "",
|
|
|
|
|
|
cloneof = "", sampleof = "", year = "", manufacturer = "";
|
2016-04-28 10:37:33 -07:00
|
|
|
|
|
|
|
|
|
|
// We want to process the entire subtree of the game
|
2016-05-18 23:51:54 -07:00
|
|
|
|
subreader = xtr.ReadSubtree();
|
2016-04-28 10:37:33 -07:00
|
|
|
|
|
2016-05-22 17:24:19 -07:00
|
|
|
|
// Safeguard for interesting case of "software" without anything except roms
|
|
|
|
|
|
bool software = false;
|
|
|
|
|
|
|
|
|
|
|
|
// If we have a subtree, add what is possible
|
2016-04-28 10:37:33 -07:00
|
|
|
|
if (subreader != null)
|
|
|
|
|
|
{
|
2016-09-05 20:31:44 -07:00
|
|
|
|
subreader.MoveToContent();
|
2016-07-12 11:03:02 -07:00
|
|
|
|
if (!softlist && temptype == "software" && subreader.ReadToFollowing("description"))
|
2016-04-28 10:37:33 -07:00
|
|
|
|
{
|
|
|
|
|
|
tempname = subreader.ReadElementContentAsString();
|
2016-09-05 20:31:44 -07:00
|
|
|
|
gamedesc = tempname;
|
2016-05-20 13:00:55 -07:00
|
|
|
|
tempname = tempname.Replace('/', '_').Replace("\"", "''");
|
2016-05-22 17:24:19 -07:00
|
|
|
|
software = true;
|
2016-04-28 10:37:33 -07:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// There are rare cases where a malformed XML will not have the required attributes. We can only skip them.
|
|
|
|
|
|
if (xtr.AttributeCount == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.Error("No attributes were found");
|
2016-05-22 17:24:19 -07:00
|
|
|
|
xtr.Skip();
|
2016-04-28 10:37:33 -07:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
tempname = xtr.GetAttribute("name");
|
2016-09-12 23:04:28 -07:00
|
|
|
|
romof = (xtr.GetAttribute("romof") != null ? xtr.GetAttribute("romof") : "");
|
|
|
|
|
|
cloneof = (xtr.GetAttribute("cloneof") != null ? xtr.GetAttribute("cloneof") : "");
|
|
|
|
|
|
sampleof = (xtr.GetAttribute("sampleof") != null ? xtr.GetAttribute("sampleof") : "");
|
2016-04-28 10:37:33 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-05-18 22:22:49 -07:00
|
|
|
|
if (superdat && !keep)
|
2016-04-28 10:37:33 -07:00
|
|
|
|
{
|
2016-05-19 12:19:28 -07:00
|
|
|
|
string tempout = Regex.Match(tempname, @".*?\\(.*)").Groups[1].Value;
|
|
|
|
|
|
if (tempout != "")
|
|
|
|
|
|
{
|
|
|
|
|
|
tempname = tempout;
|
|
|
|
|
|
}
|
2016-04-28 10:37:33 -07:00
|
|
|
|
}
|
2016-05-19 09:30:38 -07:00
|
|
|
|
// Get the name of the game from the parent
|
|
|
|
|
|
else if (superdat && keep && parent.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
tempname = String.Join("\\", parent) + "\\" + tempname;
|
|
|
|
|
|
}
|
2016-04-28 10:37:33 -07:00
|
|
|
|
|
2016-08-31 14:58:55 -07:00
|
|
|
|
while (software || !subreader.EOF)
|
2016-04-28 10:37:33 -07:00
|
|
|
|
{
|
2016-05-22 17:24:19 -07:00
|
|
|
|
software = false;
|
|
|
|
|
|
|
2016-04-28 10:37:33 -07:00
|
|
|
|
// We only want elements
|
|
|
|
|
|
if (subreader.NodeType != XmlNodeType.Element)
|
|
|
|
|
|
{
|
2016-08-31 14:58:55 -07:00
|
|
|
|
subreader.Read();
|
2016-04-28 10:37:33 -07:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Get the roms from the machine
|
|
|
|
|
|
switch (subreader.Name)
|
|
|
|
|
|
{
|
2016-08-29 12:02:25 -07:00
|
|
|
|
case "description":
|
|
|
|
|
|
gamedesc = subreader.ReadElementContentAsString();
|
|
|
|
|
|
break;
|
2016-09-12 23:04:28 -07:00
|
|
|
|
case "year":
|
|
|
|
|
|
year = subreader.ReadElementContentAsString();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "manufacturer":
|
|
|
|
|
|
manufacturer = subreader.ReadElementContentAsString();
|
|
|
|
|
|
break;
|
2016-09-13 10:48:45 -07:00
|
|
|
|
case "release":
|
|
|
|
|
|
bool? defaultrel = null;
|
|
|
|
|
|
if (subreader.GetAttribute("default") != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (subreader.GetAttribute("default") == "yes")
|
|
|
|
|
|
{
|
|
|
|
|
|
defaultrel = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (subreader.GetAttribute("default") == "no")
|
|
|
|
|
|
{
|
|
|
|
|
|
defaultrel = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Rom relrom = new Rom
|
|
|
|
|
|
{
|
|
|
|
|
|
Machine = new Machine
|
|
|
|
|
|
{
|
|
|
|
|
|
Name = tempname,
|
|
|
|
|
|
Description = gamedesc,
|
|
|
|
|
|
RomOf = romof,
|
|
|
|
|
|
CloneOf = cloneof,
|
|
|
|
|
|
SampleOf = sampleof,
|
|
|
|
|
|
},
|
|
|
|
|
|
Name = subreader.GetAttribute("name"),
|
|
|
|
|
|
Type = ItemType.Release,
|
|
|
|
|
|
Region = subreader.GetAttribute("region"),
|
|
|
|
|
|
Language = subreader.GetAttribute("language"),
|
|
|
|
|
|
Default = defaultrel,
|
|
|
|
|
|
Metadata = new SourceMetadata { SystemID = sysid, System = filename, SourceID = srcid },
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Now process and add the rom
|
|
|
|
|
|
datdata = ParseAddHelper(relrom, datdata, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, trim, single, root, clean, logger, out key);
|
|
|
|
|
|
|
|
|
|
|
|
subreader.Read();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "biosset":
|
|
|
|
|
|
bool? defaultbios = null;
|
|
|
|
|
|
if (subreader.GetAttribute("default") != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (subreader.GetAttribute("default") == "yes")
|
|
|
|
|
|
{
|
|
|
|
|
|
defaultbios = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (subreader.GetAttribute("default") == "no")
|
|
|
|
|
|
{
|
|
|
|
|
|
defaultbios = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Rom biosrom = new Rom
|
|
|
|
|
|
{
|
|
|
|
|
|
Machine = new Machine
|
|
|
|
|
|
{
|
|
|
|
|
|
Name = tempname,
|
|
|
|
|
|
Description = gamedesc,
|
|
|
|
|
|
RomOf = romof,
|
|
|
|
|
|
CloneOf = cloneof,
|
|
|
|
|
|
SampleOf = sampleof,
|
|
|
|
|
|
},
|
|
|
|
|
|
Name = subreader.GetAttribute("name"),
|
|
|
|
|
|
Type = ItemType.BiosSet,
|
|
|
|
|
|
Description = subreader.GetAttribute("description"),
|
|
|
|
|
|
Default = defaultbios,
|
|
|
|
|
|
Metadata = new SourceMetadata { SystemID = sysid, System = filename, SourceID = srcid },
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Now process and add the rom
|
|
|
|
|
|
datdata = ParseAddHelper(biosrom, datdata, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, trim, single, root, clean, logger, out key);
|
|
|
|
|
|
|
|
|
|
|
|
subreader.Read();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "archive":
|
|
|
|
|
|
case "sample":
|
|
|
|
|
|
Rom samplerom = new Rom
|
|
|
|
|
|
{
|
|
|
|
|
|
Machine = new Machine
|
|
|
|
|
|
{
|
|
|
|
|
|
Name = tempname,
|
|
|
|
|
|
Description = gamedesc,
|
|
|
|
|
|
RomOf = romof,
|
|
|
|
|
|
CloneOf = cloneof,
|
|
|
|
|
|
SampleOf = sampleof,
|
|
|
|
|
|
},
|
|
|
|
|
|
Name = subreader.GetAttribute("name"),
|
|
|
|
|
|
Type = (subreader.Name == "sample" ? ItemType.Sample : ItemType.Archive),
|
|
|
|
|
|
Metadata = new SourceMetadata { SystemID = sysid, System = filename, SourceID = srcid },
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Now process and add the rom
|
|
|
|
|
|
datdata = ParseAddHelper(samplerom, datdata, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, trim, single, root, clean, logger, out key);
|
|
|
|
|
|
|
|
|
|
|
|
subreader.Read();
|
|
|
|
|
|
break;
|
2016-04-28 10:37:33 -07:00
|
|
|
|
case "rom":
|
|
|
|
|
|
case "disk":
|
2016-05-19 10:28:53 -07:00
|
|
|
|
empty = false;
|
|
|
|
|
|
|
2016-05-18 16:59:34 -07:00
|
|
|
|
// If the rom is nodump, flag it
|
2016-09-06 11:38:55 -07:00
|
|
|
|
isnodump = false;
|
2016-05-20 10:21:24 -07:00
|
|
|
|
if (subreader.GetAttribute("flags") == "nodump" || subreader.GetAttribute("status") == "nodump")
|
2016-05-06 10:59:05 -07:00
|
|
|
|
{
|
2016-05-18 16:37:39 -07:00
|
|
|
|
logger.Log("Nodump detected: " +
|
2016-05-20 10:21:24 -07:00
|
|
|
|
(subreader.GetAttribute("name") != null && subreader.GetAttribute("name") != "" ? "\"" + xtr.GetAttribute("name") + "\"" : "ROM NAME NOT FOUND"));
|
2016-09-06 11:38:55 -07:00
|
|
|
|
isnodump = true;
|
2016-05-06 10:59:05 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-05-20 10:21:24 -07:00
|
|
|
|
// If the rom has a Date attached, read it in and then sanitize it
|
|
|
|
|
|
date = "";
|
|
|
|
|
|
if (subreader.GetAttribute("date") != null)
|
|
|
|
|
|
{
|
2016-09-14 09:54:29 -07:00
|
|
|
|
DateTime dateTime = DateTime.Now;
|
|
|
|
|
|
if (DateTime.TryParse(subreader.GetAttribute("date"), out dateTime))
|
|
|
|
|
|
{
|
|
|
|
|
|
date = dateTime.ToString();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
date = subreader.GetAttribute("date");
|
|
|
|
|
|
}
|
2016-05-20 10:21:24 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-05-14 19:41:07 -07:00
|
|
|
|
// Take care of hex-sized files
|
2016-05-18 23:51:54 -07:00
|
|
|
|
size = -1;
|
2016-05-20 10:21:24 -07:00
|
|
|
|
if (subreader.GetAttribute("size") != null && subreader.GetAttribute("size").Contains("0x"))
|
2016-05-14 19:41:07 -07:00
|
|
|
|
{
|
2016-05-20 10:21:24 -07:00
|
|
|
|
size = Convert.ToInt64(subreader.GetAttribute("size"), 16);
|
2016-05-14 19:41:07 -07:00
|
|
|
|
}
|
2016-05-20 10:21:24 -07:00
|
|
|
|
else if (subreader.GetAttribute("size") != null)
|
2016-05-14 19:41:07 -07:00
|
|
|
|
{
|
2016-05-20 10:21:24 -07:00
|
|
|
|
Int64.TryParse(subreader.GetAttribute("size"), out size);
|
2016-05-14 19:41:07 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-05-15 13:23:29 -07:00
|
|
|
|
// If the rom is continue or ignore, add the size to the previous rom
|
2016-05-20 10:21:24 -07:00
|
|
|
|
if (subreader.GetAttribute("loadflag") == "continue" || subreader.GetAttribute("loadflag") == "ignore")
|
2016-05-14 19:41:07 -07:00
|
|
|
|
{
|
2016-08-29 13:52:13 -07:00
|
|
|
|
int index = datdata.Files[key].Count() - 1;
|
2016-08-29 13:57:46 -07:00
|
|
|
|
Rom lastrom = datdata.Files[key][index];
|
2016-08-29 13:05:32 -07:00
|
|
|
|
lastrom.HashData.Size += size;
|
2016-08-29 13:52:13 -07:00
|
|
|
|
datdata.Files[key].RemoveAt(index);
|
|
|
|
|
|
datdata.Files[key].Add(lastrom);
|
2016-09-05 20:31:44 -07:00
|
|
|
|
subreader.Read();
|
2016-05-15 13:23:29 -07:00
|
|
|
|
continue;
|
2016-05-14 19:41:07 -07:00
|
|
|
|
}
|
2016-04-28 10:37:33 -07:00
|
|
|
|
|
2016-05-29 13:27:34 -07:00
|
|
|
|
// If we're in clean mode, sanitize the game name
|
|
|
|
|
|
if (clean)
|
|
|
|
|
|
{
|
2016-06-13 23:42:27 -07:00
|
|
|
|
tempname = Style.CleanGameName(tempname.Split(Path.DirectorySeparatorChar));
|
2016-05-29 13:27:34 -07:00
|
|
|
|
}
|
2016-05-06 12:56:02 -07:00
|
|
|
|
|
2016-09-06 11:38:55 -07:00
|
|
|
|
Rom inrom = new Rom
|
2016-04-28 10:37:33 -07:00
|
|
|
|
{
|
2016-09-06 11:38:55 -07:00
|
|
|
|
Machine = new Machine
|
2016-05-06 10:59:05 -07:00
|
|
|
|
{
|
2016-09-06 11:38:55 -07:00
|
|
|
|
Name = tempname,
|
|
|
|
|
|
Description = gamedesc,
|
2016-09-12 23:04:28 -07:00
|
|
|
|
RomOf = romof,
|
|
|
|
|
|
CloneOf = cloneof,
|
|
|
|
|
|
SampleOf = sampleof,
|
2016-09-06 11:38:55 -07:00
|
|
|
|
},
|
|
|
|
|
|
Name = subreader.GetAttribute("name"),
|
|
|
|
|
|
Type = (subreader.Name.ToLowerInvariant() == "disk" ? ItemType.Disk : ItemType.Rom),
|
|
|
|
|
|
HashData = new Hash
|
2016-05-06 10:59:05 -07:00
|
|
|
|
{
|
2016-09-06 11:38:55 -07:00
|
|
|
|
Size = size,
|
|
|
|
|
|
CRC = subreader.GetAttribute("crc")?.ToLowerInvariant(),
|
|
|
|
|
|
MD5 = subreader.GetAttribute("md5")?.ToLowerInvariant(),
|
|
|
|
|
|
SHA1 = subreader.GetAttribute("sha1")?.ToLowerInvariant(),
|
|
|
|
|
|
},
|
|
|
|
|
|
Nodump = isnodump,
|
|
|
|
|
|
Date = date,
|
|
|
|
|
|
Metadata = new SourceMetadata { SystemID = sysid, System = filename, SourceID = srcid },
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Now process and add the rom
|
|
|
|
|
|
datdata = ParseAddHelper(inrom, datdata, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, trim, single, root, clean, logger, out key);
|
2016-05-31 23:34:19 -07:00
|
|
|
|
|
2016-08-31 14:58:55 -07:00
|
|
|
|
subreader.Read();
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
subreader.Read();
|
2016-04-28 10:37:33 -07:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-05-19 10:28:53 -07:00
|
|
|
|
// If we didn't find any items in the folder, make sure to add the blank rom
|
|
|
|
|
|
if (empty)
|
|
|
|
|
|
{
|
|
|
|
|
|
tempname = (parent.Count > 0 ? String.Join("\\", parent) + Path.DirectorySeparatorChar : "") + tempname;
|
|
|
|
|
|
|
2016-09-06 11:38:55 -07:00
|
|
|
|
Rom inrom = new Rom
|
2016-05-19 10:28:53 -07:00
|
|
|
|
{
|
2016-08-29 13:50:55 -07:00
|
|
|
|
Type = ItemType.Rom,
|
2016-05-19 10:28:53 -07:00
|
|
|
|
Name = "null",
|
2016-08-29 13:42:27 -07:00
|
|
|
|
Machine = new Machine
|
2016-08-29 13:41:42 -07:00
|
|
|
|
{
|
|
|
|
|
|
Name = tempname,
|
|
|
|
|
|
Description = tempname,
|
|
|
|
|
|
},
|
2016-08-29 14:43:31 -07:00
|
|
|
|
HashData = new Hash
|
2016-08-29 13:05:32 -07:00
|
|
|
|
{
|
|
|
|
|
|
Size = -1,
|
|
|
|
|
|
CRC = "null",
|
|
|
|
|
|
MD5 = "null",
|
|
|
|
|
|
SHA1 = "null",
|
|
|
|
|
|
}
|
2016-05-19 10:28:53 -07:00
|
|
|
|
};
|
|
|
|
|
|
|
2016-09-06 11:38:55 -07:00
|
|
|
|
// Now process and add the rom
|
|
|
|
|
|
datdata = ParseAddHelper(inrom, datdata, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, trim, single, root, clean, logger, out key);
|
|
|
|
|
|
|
|
|
|
|
|
// Regardless, end the current folder
|
|
|
|
|
|
if (parent.Count == 0)
|
2016-05-19 10:28:53 -07:00
|
|
|
|
{
|
2016-09-06 11:38:55 -07:00
|
|
|
|
empty = true;
|
2016-05-19 10:28:53 -07:00
|
|
|
|
}
|
2016-05-19 10:56:36 -07:00
|
|
|
|
}
|
|
|
|
|
|
xtr.Skip();
|
2016-04-28 10:37:33 -07:00
|
|
|
|
break;
|
2016-05-19 09:30:38 -07:00
|
|
|
|
case "dir":
|
2016-05-18 23:51:54 -07:00
|
|
|
|
case "directory":
|
|
|
|
|
|
// Set SuperDAT flag for all SabreDAT inputs, regardless of depth
|
|
|
|
|
|
superdat = true;
|
|
|
|
|
|
if (keep)
|
|
|
|
|
|
{
|
|
|
|
|
|
datdata.Type = (datdata.Type == "" ? "SuperDAT" : datdata.Type);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string foldername = (xtr.GetAttribute("name") == null ? "" : xtr.GetAttribute("name"));
|
|
|
|
|
|
if (foldername != "")
|
|
|
|
|
|
{
|
|
|
|
|
|
parent.Add(foldername);
|
|
|
|
|
|
}
|
2016-05-19 10:56:36 -07:00
|
|
|
|
|
2016-05-18 23:51:54 -07:00
|
|
|
|
xtr.Read();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "file":
|
2016-05-19 10:28:53 -07:00
|
|
|
|
empty = false;
|
|
|
|
|
|
|
2016-05-18 23:51:54 -07:00
|
|
|
|
// If the rom is nodump, flag it
|
2016-09-06 11:38:55 -07:00
|
|
|
|
isnodump = false;
|
2016-05-18 23:51:54 -07:00
|
|
|
|
flagreader = xtr.ReadSubtree();
|
|
|
|
|
|
if (flagreader != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
while (!flagreader.EOF)
|
|
|
|
|
|
{
|
|
|
|
|
|
// We only want elements
|
|
|
|
|
|
if (flagreader.NodeType != XmlNodeType.Element || flagreader.Name == "flags")
|
|
|
|
|
|
{
|
|
|
|
|
|
flagreader.Read();
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
switch (flagreader.Name)
|
|
|
|
|
|
{
|
|
|
|
|
|
case "flag":
|
|
|
|
|
|
case "status":
|
|
|
|
|
|
if (flagreader.GetAttribute("name") != null && flagreader.GetAttribute("value") != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
string content = flagreader.GetAttribute("value");
|
|
|
|
|
|
switch (flagreader.GetAttribute("name"))
|
|
|
|
|
|
{
|
|
|
|
|
|
case "nodump":
|
|
|
|
|
|
logger.Log("Nodump detected: " + (xtr.GetAttribute("name") != null && xtr.GetAttribute("name") != "" ?
|
|
|
|
|
|
"\"" + xtr.GetAttribute("name") + "\"" : "ROM NAME NOT FOUND"));
|
2016-09-06 11:38:55 -07:00
|
|
|
|
isnodump = true;
|
2016-05-18 23:51:54 -07:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
flagreader.Read();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-05-20 10:21:24 -07:00
|
|
|
|
// If the rom has a Date attached, read it in and then sanitize it
|
|
|
|
|
|
date = "";
|
|
|
|
|
|
if (xtr.GetAttribute("date") != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
date = DateTime.Parse(xtr.GetAttribute("date")).ToString();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-05-18 23:51:54 -07:00
|
|
|
|
// Take care of hex-sized files
|
|
|
|
|
|
size = -1;
|
|
|
|
|
|
if (xtr.GetAttribute("size") != null && xtr.GetAttribute("size").Contains("0x"))
|
|
|
|
|
|
{
|
|
|
|
|
|
size = Convert.ToInt64(xtr.GetAttribute("size"), 16);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (xtr.GetAttribute("size") != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Int64.TryParse(xtr.GetAttribute("size"), out size);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// If the rom is continue or ignore, add the size to the previous rom
|
|
|
|
|
|
if (xtr.GetAttribute("loadflag") == "continue" || xtr.GetAttribute("loadflag") == "ignore")
|
|
|
|
|
|
{
|
2016-08-29 13:52:13 -07:00
|
|
|
|
int index = datdata.Files[key].Count() - 1;
|
2016-08-29 13:57:46 -07:00
|
|
|
|
Rom lastrom = datdata.Files[key][index];
|
2016-08-29 13:05:32 -07:00
|
|
|
|
lastrom.HashData.Size += size;
|
2016-08-29 13:52:13 -07:00
|
|
|
|
datdata.Files[key].RemoveAt(index);
|
|
|
|
|
|
datdata.Files[key].Add(lastrom);
|
2016-05-18 23:51:54 -07:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Get the name of the game from the parent
|
|
|
|
|
|
tempname = String.Join("\\", parent);
|
|
|
|
|
|
|
2016-05-29 14:39:07 -07:00
|
|
|
|
// If we aren't keeping names, trim out the path
|
|
|
|
|
|
if (!keep || !superdat)
|
2016-05-18 23:51:54 -07:00
|
|
|
|
{
|
2016-05-19 12:19:28 -07:00
|
|
|
|
string tempout = Regex.Match(tempname, @".*?\\(.*)").Groups[1].Value;
|
|
|
|
|
|
if (tempout != "")
|
|
|
|
|
|
{
|
|
|
|
|
|
tempname = tempout;
|
|
|
|
|
|
}
|
2016-05-18 23:51:54 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-06 11:38:55 -07:00
|
|
|
|
Rom rom = new Rom
|
2016-05-18 23:51:54 -07:00
|
|
|
|
{
|
2016-09-06 11:38:55 -07:00
|
|
|
|
Machine = new Machine
|
2016-05-18 23:51:54 -07:00
|
|
|
|
{
|
2016-09-06 11:38:55 -07:00
|
|
|
|
Name = tempname,
|
|
|
|
|
|
},
|
|
|
|
|
|
Name = xtr.GetAttribute("name"),
|
|
|
|
|
|
Type = (xtr.GetAttribute("type").ToLowerInvariant() == "disk" ? ItemType.Disk : ItemType.Rom),
|
|
|
|
|
|
HashData = new Hash
|
2016-05-18 23:51:54 -07:00
|
|
|
|
{
|
2016-09-06 11:38:55 -07:00
|
|
|
|
Size = size,
|
|
|
|
|
|
CRC = xtr.GetAttribute("crc")?.ToLowerInvariant(),
|
|
|
|
|
|
MD5 = xtr.GetAttribute("md5")?.ToLowerInvariant(),
|
|
|
|
|
|
SHA1 = xtr.GetAttribute("sha1")?.ToLowerInvariant(),
|
|
|
|
|
|
},
|
|
|
|
|
|
Nodump = isnodump,
|
|
|
|
|
|
Date = date,
|
|
|
|
|
|
Metadata = new SourceMetadata { SystemID = sysid, System = filename, SourceID = srcid },
|
|
|
|
|
|
};
|
2016-05-18 23:51:54 -07:00
|
|
|
|
|
2016-09-06 11:38:55 -07:00
|
|
|
|
// Now process and add the rom
|
|
|
|
|
|
datdata = ParseAddHelper(rom, datdata, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, trim, single, root, clean, logger, out key);
|
2016-05-31 23:34:19 -07:00
|
|
|
|
|
2016-05-18 23:51:54 -07:00
|
|
|
|
xtr.Read();
|
|
|
|
|
|
break;
|
2016-04-28 10:37:33 -07:00
|
|
|
|
default:
|
|
|
|
|
|
xtr.Read();
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-06-13 10:29:07 -07:00
|
|
|
|
|
|
|
|
|
|
xtr.Close();
|
|
|
|
|
|
xtr.Dispose();
|
2016-04-28 10:37:33 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-05-16 14:28:23 -07:00
|
|
|
|
return datdata;
|
2016-04-28 10:37:33 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-06 11:38:55 -07:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Add a rom to the Dat after checking
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="rom">Rom data to check against</param>
|
|
|
|
|
|
/// <param name="datdata">Dat to add information to, if possible</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="romtype">Type of the rom to match</param>
|
|
|
|
|
|
/// <param name="sgt">Find roms greater than or equal to this size</param>
|
|
|
|
|
|
/// <param name="slt">Find roms less than or equal to this size</param>
|
|
|
|
|
|
/// <param name="seq">Find roms equal to this size</param>
|
|
|
|
|
|
/// <param name="crc">CRC of the rom to match (can use asterisk-partials)</param>
|
|
|
|
|
|
/// <param name="md5">MD5 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="trim">True if we are supposed to trim names to NTFS length, false otherwise</param>
|
|
|
|
|
|
/// <param name="single">True if all games should be replaced by '!', false otherwise</param>
|
|
|
|
|
|
/// <param name="root">String representing root directory to compare against for length calculation</param>
|
|
|
|
|
|
/// <param name="logger">Logger object for console and/or file output</param>
|
|
|
|
|
|
private static Dat ParseAddHelper(Rom rom, Dat datdata, string gamename, string romname, string romtype, long sgt, long slt,
|
|
|
|
|
|
long seq, string crc, string md5, string sha1, bool? nodump, bool trim, bool single, string root, bool clean, Logger logger, out string key)
|
|
|
|
|
|
{
|
|
|
|
|
|
key = "";
|
|
|
|
|
|
|
2016-09-09 10:00:37 -07:00
|
|
|
|
// If there's no name in the rom, we log and skip it
|
|
|
|
|
|
if (String.IsNullOrEmpty(rom.Name))
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.Warning("Rom with no name found! Skipping...");
|
|
|
|
|
|
return datdata;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-06 11:38:55 -07:00
|
|
|
|
// If we're in cleaning mode, sanitize the game name
|
|
|
|
|
|
rom.Machine.Name = (clean ? Style.CleanGameName(rom.Machine.Name) : rom.Machine.Name);
|
|
|
|
|
|
|
|
|
|
|
|
// Sanitize the hashes from null, hex sizes, and "true blank" strings
|
|
|
|
|
|
rom.HashData.CRC = Style.CleanHashData(rom.HashData.CRC, Constants.CRCLength);
|
|
|
|
|
|
rom.HashData.MD5 = Style.CleanHashData(rom.HashData.MD5, Constants.MD5Length);
|
|
|
|
|
|
rom.HashData.SHA1 = Style.CleanHashData(rom.HashData.SHA1, Constants.SHA1Length);
|
|
|
|
|
|
|
|
|
|
|
|
// If we have a rom and it's missing size AND the hashes match a 0-byte file, fill in the rest of the info
|
|
|
|
|
|
if (rom.Type == ItemType.Rom
|
|
|
|
|
|
&& (rom.HashData.Size == 0 || rom.HashData.Size == -1)
|
|
|
|
|
|
&& ((rom.HashData.CRC == Constants.CRCZero || rom.HashData.CRC == "")
|
|
|
|
|
|
|| rom.HashData.MD5 == Constants.MD5Zero
|
|
|
|
|
|
|| rom.HashData.SHA1 == Constants.SHA1Zero))
|
|
|
|
|
|
{
|
|
|
|
|
|
rom.HashData.Size = Constants.SizeZero;
|
|
|
|
|
|
rom.HashData.CRC = Constants.CRCZero;
|
|
|
|
|
|
rom.HashData.MD5 = Constants.MD5Zero;
|
|
|
|
|
|
rom.HashData.SHA1 = Constants.SHA1Zero;
|
|
|
|
|
|
}
|
|
|
|
|
|
// If the file has no size and it's not the above case, skip and log
|
|
|
|
|
|
else if (rom.Type == ItemType.Rom && (rom.HashData.Size == 0 || rom.HashData.Size == -1))
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.Warning("Incomplete entry for \"" + rom.Name + "\" will be output as nodump");
|
|
|
|
|
|
rom.Nodump = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// If the rom passes the filter, include it
|
|
|
|
|
|
if (Filter(rom, gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, logger))
|
|
|
|
|
|
{
|
|
|
|
|
|
// If we are in single game mode, rename all games
|
|
|
|
|
|
if (single)
|
|
|
|
|
|
{
|
|
|
|
|
|
rom.Machine.Name = "!";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// If we are in NTFS trim mode, trim the game name
|
|
|
|
|
|
if (trim)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Windows max name length is 260
|
|
|
|
|
|
int usableLength = 260 - rom.Machine.Name.Length - root.Length;
|
|
|
|
|
|
if (rom.Name.Length > usableLength)
|
|
|
|
|
|
{
|
|
|
|
|
|
string ext = Path.GetExtension(rom.Name);
|
|
|
|
|
|
rom.Name = rom.Name.Substring(0, usableLength - ext.Length);
|
|
|
|
|
|
rom.Name += ext;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// If we have a disk, make sure that the value for size is -1
|
|
|
|
|
|
if (rom.Type == ItemType.Disk)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.Log("Disk found: \"" + rom.Name + "\"");
|
|
|
|
|
|
rom.HashData.Size = -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-08 21:48:50 -07:00
|
|
|
|
lock (datdata.Files)
|
2016-09-06 11:38:55 -07:00
|
|
|
|
{
|
2016-09-08 21:48:50 -07:00
|
|
|
|
key = rom.HashData.Size + "-" + rom.HashData.CRC;
|
|
|
|
|
|
if (datdata.Files.ContainsKey(key))
|
|
|
|
|
|
{
|
|
|
|
|
|
datdata.Files[key].Add(rom);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
List<Rom> newvalue = new List<Rom>();
|
|
|
|
|
|
newvalue.Add(rom);
|
|
|
|
|
|
datdata.Files.Add(key, newvalue);
|
|
|
|
|
|
}
|
2016-09-06 11:38:55 -07:00
|
|
|
|
|
2016-09-08 21:48:50 -07:00
|
|
|
|
// Add statistical data
|
|
|
|
|
|
datdata.RomCount += (rom.Type == ItemType.Rom ? 1 : 0);
|
|
|
|
|
|
datdata.DiskCount += (rom.Type == ItemType.Disk ? 1 : 0);
|
|
|
|
|
|
datdata.TotalSize += (rom.Nodump ? 0 : rom.HashData.Size);
|
|
|
|
|
|
datdata.CRCCount += (String.IsNullOrEmpty(rom.HashData.CRC) ? 0 : 1);
|
|
|
|
|
|
datdata.MD5Count += (String.IsNullOrEmpty(rom.HashData.MD5) ? 0 : 1);
|
|
|
|
|
|
datdata.SHA1Count += (String.IsNullOrEmpty(rom.HashData.SHA1) ? 0 : 1);
|
|
|
|
|
|
datdata.NodumpCount += (rom.Nodump ? 1 : 0);
|
|
|
|
|
|
}
|
2016-09-06 11:38:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return datdata;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-08-29 17:28:08 -07:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
2016-09-01 20:38:41 -07:00
|
|
|
|
#region Bucketing
|
2016-08-29 17:28:08 -07:00
|
|
|
|
|
2016-06-16 17:39:53 -07:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Take an arbitrarily ordered List and return a Dictionary sorted by Game
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="list">Input unsorted list</param>
|
|
|
|
|
|
/// <param name="mergeroms">True if roms should be deduped, false otherwise</param>
|
|
|
|
|
|
/// <param name="norename">True if games should only be compared on game and file name, false if system and source are counted</param>
|
|
|
|
|
|
/// <param name="logger">Logger object for file and console output</param>
|
|
|
|
|
|
/// <param name="output">True if the number of hashes counted is to be output (default), false otherwise</param>
|
|
|
|
|
|
/// <returns>SortedDictionary bucketed by game name</returns>
|
2016-08-29 13:57:46 -07:00
|
|
|
|
public static SortedDictionary<string, List<Rom>> BucketByGame(List<Rom> list, bool mergeroms, bool norename, Logger logger, bool output = true)
|
2016-06-16 17:39:53 -07:00
|
|
|
|
{
|
2016-08-29 13:57:46 -07:00
|
|
|
|
Dictionary<string, List<Rom>> dict = new Dictionary<string, List<Rom>>();
|
2016-06-16 17:39:53 -07:00
|
|
|
|
dict.Add("key", list);
|
|
|
|
|
|
return BucketByGame(dict, mergeroms, norename, logger, output);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-05-23 14:15:09 -07:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Take an arbitrarily bucketed Dictionary and return one sorted by Game
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="dict">Input unsorted dictionary</param>
|
2016-06-12 21:52:27 -07:00
|
|
|
|
/// <param name="mergeroms">True if roms should be deduped, false otherwise</param>
|
2016-05-23 14:15:09 -07:00
|
|
|
|
/// <param name="norename">True if games should only be compared on game and file name, false if system and source are counted</param>
|
|
|
|
|
|
/// <param name="logger">Logger object for file and console output</param>
|
2016-06-12 21:52:27 -07:00
|
|
|
|
/// <param name="output">True if the number of hashes counted is to be output (default), false otherwise</param>
|
2016-05-23 14:15:09 -07:00
|
|
|
|
/// <returns>SortedDictionary bucketed by game name</returns>
|
2016-08-29 13:57:46 -07:00
|
|
|
|
public static SortedDictionary<string, List<Rom>> BucketByGame(IDictionary<string, List<Rom>> dict, bool mergeroms, bool norename, Logger logger, bool output = true)
|
2016-05-23 14:15:09 -07:00
|
|
|
|
{
|
2016-09-09 16:10:59 -07:00
|
|
|
|
logger.User("Organizing " + (mergeroms ? "and merging " : "") + "roms for output");
|
|
|
|
|
|
|
2016-08-29 13:57:46 -07:00
|
|
|
|
SortedDictionary<string, List<Rom>> sortable = new SortedDictionary<string, List<Rom>>();
|
2016-05-23 14:15:09 -07:00
|
|
|
|
long count = 0;
|
2016-06-12 21:52:27 -07:00
|
|
|
|
|
|
|
|
|
|
// If we have a null dict or an empty one, output a new dictionary
|
|
|
|
|
|
if (dict == null || dict.Count == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
return sortable;
|
|
|
|
|
|
}
|
2016-09-07 13:59:25 -07:00
|
|
|
|
|
2016-06-12 21:52:27 -07:00
|
|
|
|
// Process each all of the roms
|
2016-07-12 11:39:47 -07:00
|
|
|
|
foreach (string key in dict.Keys)
|
2016-05-23 14:15:09 -07:00
|
|
|
|
{
|
2016-08-29 13:57:46 -07:00
|
|
|
|
List<Rom> roms = dict[key];
|
2016-05-23 14:15:09 -07:00
|
|
|
|
if (mergeroms)
|
|
|
|
|
|
{
|
2016-07-12 11:39:47 -07:00
|
|
|
|
roms = RomTools.Merge(roms, logger);
|
2016-05-23 14:15:09 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-08-29 13:57:46 -07:00
|
|
|
|
foreach (Rom rom in roms)
|
2016-05-23 14:15:09 -07:00
|
|
|
|
{
|
|
|
|
|
|
count++;
|
2016-08-29 13:41:42 -07:00
|
|
|
|
string newkey = (norename ? ""
|
|
|
|
|
|
: rom.Metadata.SystemID.ToString().PadLeft(10, '0')
|
|
|
|
|
|
+ "-"
|
|
|
|
|
|
+ rom.Metadata.SourceID.ToString().PadLeft(10, '0') + "-")
|
2016-09-07 12:39:09 -07:00
|
|
|
|
+ (String.IsNullOrEmpty(rom.Machine.Name)
|
|
|
|
|
|
? "Default"
|
|
|
|
|
|
: rom.Machine.Name.ToLowerInvariant());
|
2016-07-12 11:39:47 -07:00
|
|
|
|
if (sortable.ContainsKey(newkey))
|
2016-05-23 14:15:09 -07:00
|
|
|
|
{
|
2016-07-12 11:39:47 -07:00
|
|
|
|
sortable[newkey].Add(rom);
|
2016-05-23 14:15:09 -07:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2016-08-29 13:57:46 -07:00
|
|
|
|
List<Rom> temp = new List<Rom>();
|
2016-05-23 14:15:09 -07:00
|
|
|
|
temp.Add(rom);
|
2016-07-12 11:39:47 -07:00
|
|
|
|
sortable.Add(newkey, temp);
|
2016-05-23 14:15:09 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-07 12:16:19 -07:00
|
|
|
|
// Now go through and sort all of the lists
|
2016-09-14 11:05:40 -07:00
|
|
|
|
List<string> keys = sortable.Keys.ToList();
|
|
|
|
|
|
foreach (string key in keys)
|
2016-09-07 12:16:19 -07:00
|
|
|
|
{
|
2016-09-14 11:05:40 -07:00
|
|
|
|
List<Rom> sortedlist = sortable[key];
|
|
|
|
|
|
RomTools.Sort(ref sortedlist, norename);
|
|
|
|
|
|
sortable[key] = sortedlist;
|
2016-09-07 12:16:19 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-06-12 21:52:27 -07:00
|
|
|
|
// Output the count if told to
|
|
|
|
|
|
if (output)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.User("A total of " + count + " file hashes will be written out to file");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-05-23 14:15:09 -07:00
|
|
|
|
return sortable;
|
|
|
|
|
|
}
|
2016-05-29 21:15:05 -07:00
|
|
|
|
|
2016-06-16 17:39:53 -07:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Take an arbitrarily ordered List and return a Dictionary sorted by size and hash
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="list">Input unsorted list</param>
|
|
|
|
|
|
/// <param name="mergeroms">True if roms should be deduped, false otherwise</param>
|
|
|
|
|
|
/// <param name="norename">True if games should only be compared on game and file name, false if system and source are counted</param>
|
|
|
|
|
|
/// <param name="logger">Logger object for file and console output</param>
|
|
|
|
|
|
/// <param name="output">True if the number of hashes counted is to be output (default), false otherwise</param>
|
|
|
|
|
|
/// <returns>SortedDictionary bucketed by size and hash</returns>
|
2016-08-29 13:57:46 -07:00
|
|
|
|
public static SortedDictionary<string, List<Rom>> BucketByHashSize(List<Rom> list, bool mergeroms, bool norename, Logger logger, bool output = true)
|
2016-06-16 17:39:53 -07:00
|
|
|
|
{
|
2016-08-29 13:57:46 -07:00
|
|
|
|
Dictionary<string, List<Rom>> dict = new Dictionary<string, List<Rom>>();
|
2016-06-16 17:39:53 -07:00
|
|
|
|
dict.Add("key", list);
|
|
|
|
|
|
return BucketByHashSize(dict, mergeroms, norename, logger, output);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Take an arbitrarily bucketed Dictionary and return one sorted by size and hash
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="dict">Input unsorted dictionary</param>
|
|
|
|
|
|
/// <param name="mergeroms">True if roms should be deduped, false otherwise</param>
|
|
|
|
|
|
/// <param name="norename">True if games should only be compared on game and file name, false if system and source are counted</param>
|
|
|
|
|
|
/// <param name="logger">Logger object for file and console output</param>
|
|
|
|
|
|
/// <param name="output">True if the number of hashes counted is to be output (default), false otherwise</param>
|
|
|
|
|
|
/// <returns>SortedDictionary bucketed by size and hash</returns>
|
2016-08-29 13:57:46 -07:00
|
|
|
|
public static SortedDictionary<string, List<Rom>> BucketByHashSize(IDictionary<string, List<Rom>> dict, bool mergeroms, bool norename, Logger logger, bool output = true)
|
2016-06-16 17:39:53 -07:00
|
|
|
|
{
|
2016-08-29 13:57:46 -07:00
|
|
|
|
SortedDictionary<string, List<Rom>> sortable = new SortedDictionary<string, List<Rom>>();
|
2016-06-16 17:39:53 -07:00
|
|
|
|
long count = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// If we have a null dict or an empty one, output a new dictionary
|
|
|
|
|
|
if (dict == null || dict.Count == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
return sortable;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Process each all of the roms
|
2016-08-29 13:57:46 -07:00
|
|
|
|
foreach (List<Rom> roms in dict.Values)
|
2016-06-16 17:39:53 -07:00
|
|
|
|
{
|
2016-08-29 13:57:46 -07:00
|
|
|
|
List<Rom> newroms = roms;
|
2016-06-16 17:39:53 -07:00
|
|
|
|
if (mergeroms)
|
|
|
|
|
|
{
|
|
|
|
|
|
newroms = RomTools.Merge(newroms, logger);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-08-29 13:57:46 -07:00
|
|
|
|
foreach (Rom rom in newroms)
|
2016-06-16 17:39:53 -07:00
|
|
|
|
{
|
|
|
|
|
|
count++;
|
2016-08-29 13:05:32 -07:00
|
|
|
|
string key = rom.HashData.Size + "-" + rom.HashData.CRC;
|
2016-06-16 17:39:53 -07:00
|
|
|
|
if (sortable.ContainsKey(key))
|
|
|
|
|
|
{
|
|
|
|
|
|
sortable[key].Add(rom);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2016-08-29 13:57:46 -07:00
|
|
|
|
List<Rom> temp = new List<Rom>();
|
2016-06-16 17:39:53 -07:00
|
|
|
|
temp.Add(rom);
|
|
|
|
|
|
sortable.Add(key, temp);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-07 12:16:19 -07:00
|
|
|
|
// Now go through and sort all of the lists
|
2016-09-14 11:05:40 -07:00
|
|
|
|
List<string> keys = sortable.Keys.ToList();
|
|
|
|
|
|
foreach (string key in keys)
|
2016-09-07 12:16:19 -07:00
|
|
|
|
{
|
2016-09-14 11:05:40 -07:00
|
|
|
|
List<Rom> sortedlist = sortable[key];
|
|
|
|
|
|
RomTools.Sort(ref sortedlist, norename);
|
|
|
|
|
|
sortable[key] = sortedlist;
|
2016-09-07 12:16:19 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-06-16 17:39:53 -07:00
|
|
|
|
// Output the count if told to
|
|
|
|
|
|
if (output)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.User("A total of " + count + " file hashes will be written out to file");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return sortable;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-08-29 17:28:08 -07:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
2016-09-01 20:38:41 -07:00
|
|
|
|
#region Converting and Updating
|
2016-08-29 17:28:08 -07:00
|
|
|
|
|
2016-09-06 11:38:55 -07:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Determine if a rom should be included based on filters
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="romdata">User supplied Rom to check</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="romtype">Type of the rom to match</param>
|
|
|
|
|
|
/// <param name="sgt">Find roms greater than or equal to this size</param>
|
|
|
|
|
|
/// <param name="slt">Find roms less than or equal to this size</param>
|
|
|
|
|
|
/// <param name="seq">Find roms equal to this size</param>
|
|
|
|
|
|
/// <param name="crc">CRC of the rom to match (can use asterisk-partials)</param>
|
|
|
|
|
|
/// <param name="md5">MD5 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="logger">Logging object for console and file output</param>
|
|
|
|
|
|
/// <returns>Returns true if it should be included, false otherwise</returns>
|
|
|
|
|
|
public static bool Filter(Rom romdata, string gamename, string romname, string romtype, long sgt,
|
|
|
|
|
|
long slt, long seq, string crc, string md5, string sha1, bool? nodump, Logger logger)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Filter on nodump status
|
|
|
|
|
|
if (nodump == true && !romdata.Nodump)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (nodump == false && romdata.Nodump)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Filter on game name
|
2016-09-06 12:18:30 -07:00
|
|
|
|
if (!String.IsNullOrEmpty(gamename))
|
2016-09-06 11:38:55 -07:00
|
|
|
|
{
|
|
|
|
|
|
if (gamename.StartsWith("*") && gamename.EndsWith("*"))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!romdata.Machine.Name.ToLowerInvariant().Contains(gamename.ToLowerInvariant().Replace("*", "")))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (gamename.StartsWith("*"))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!romdata.Machine.Name.EndsWith(gamename.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (gamename.EndsWith("*"))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!romdata.Machine.Name.StartsWith(gamename.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-09-06 12:34:09 -07:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!String.Equals(romdata.Machine.Name, gamename, StringComparison.InvariantCultureIgnoreCase))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-09-06 11:38:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Filter on rom name
|
2016-09-06 12:18:30 -07:00
|
|
|
|
if (!String.IsNullOrEmpty(romname))
|
2016-09-06 11:38:55 -07:00
|
|
|
|
{
|
2016-09-06 12:34:09 -07:00
|
|
|
|
if (romname.StartsWith("*") && romname.EndsWith("*"))
|
2016-09-06 11:38:55 -07:00
|
|
|
|
{
|
2016-09-06 12:34:09 -07:00
|
|
|
|
if (!romdata.Name.ToLowerInvariant().Contains(romname.ToLowerInvariant().Replace("*", "")))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2016-09-06 11:38:55 -07:00
|
|
|
|
}
|
2016-09-06 12:34:09 -07:00
|
|
|
|
else if (romname.StartsWith("*"))
|
2016-09-06 11:38:55 -07:00
|
|
|
|
{
|
2016-09-06 12:34:09 -07:00
|
|
|
|
if (!romdata.Name.EndsWith(romname.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2016-09-06 11:38:55 -07:00
|
|
|
|
}
|
2016-09-06 12:34:09 -07:00
|
|
|
|
else if (romname.EndsWith("*"))
|
2016-09-06 11:38:55 -07:00
|
|
|
|
{
|
2016-09-06 12:34:09 -07:00
|
|
|
|
if (!romdata.Name.StartsWith(romname.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!String.Equals(romdata.Name, romname, StringComparison.InvariantCultureIgnoreCase))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2016-09-06 11:38:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Filter on rom type
|
2016-09-17 15:24:37 -07:00
|
|
|
|
if (String.IsNullOrEmpty(romtype) && romdata.Type != ItemType.Rom && romdata.Type != ItemType.Disk)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2016-09-06 13:05:11 -07:00
|
|
|
|
if (!String.IsNullOrEmpty(romtype) && !String.Equals(romdata.Type.ToString(), romtype, StringComparison.InvariantCultureIgnoreCase))
|
2016-09-06 11:38:55 -07:00
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Filter on rom size
|
|
|
|
|
|
if (seq != -1 && romdata.HashData.Size != seq)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
if (sgt != -1 && romdata.HashData.Size < sgt)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (slt != -1 && romdata.HashData.Size > slt)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Filter on crc
|
2016-09-06 12:18:30 -07:00
|
|
|
|
if (!String.IsNullOrEmpty(crc))
|
2016-09-06 11:38:55 -07:00
|
|
|
|
{
|
2016-09-06 12:34:09 -07:00
|
|
|
|
if (crc.StartsWith("*") && crc.EndsWith("*"))
|
2016-09-06 11:38:55 -07:00
|
|
|
|
{
|
2016-09-06 12:34:09 -07:00
|
|
|
|
if (!romdata.HashData.CRC.ToLowerInvariant().Contains(crc.ToLowerInvariant().Replace("*", "")))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2016-09-06 11:38:55 -07:00
|
|
|
|
}
|
2016-09-06 12:34:09 -07:00
|
|
|
|
else if (crc.StartsWith("*"))
|
2016-09-06 11:38:55 -07:00
|
|
|
|
{
|
2016-09-06 12:34:09 -07:00
|
|
|
|
if (!romdata.HashData.CRC.EndsWith(crc.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2016-09-06 11:38:55 -07:00
|
|
|
|
}
|
2016-09-06 12:34:09 -07:00
|
|
|
|
else if (crc.EndsWith("*"))
|
2016-09-06 11:38:55 -07:00
|
|
|
|
{
|
2016-09-06 12:34:09 -07:00
|
|
|
|
if (!romdata.HashData.CRC.StartsWith(crc.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!String.Equals(romdata.HashData.CRC, crc, StringComparison.InvariantCultureIgnoreCase))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2016-09-06 11:38:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Filter on md5
|
2016-09-06 12:18:30 -07:00
|
|
|
|
if (!String.IsNullOrEmpty(md5))
|
2016-09-06 11:38:55 -07:00
|
|
|
|
{
|
2016-09-06 12:34:09 -07:00
|
|
|
|
if (md5.StartsWith("*") && md5.EndsWith("*"))
|
2016-09-06 11:38:55 -07:00
|
|
|
|
{
|
2016-09-06 12:34:09 -07:00
|
|
|
|
if (!romdata.HashData.MD5.ToLowerInvariant().Contains(md5.ToLowerInvariant().Replace("*", "")))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2016-09-06 11:38:55 -07:00
|
|
|
|
}
|
2016-09-06 12:34:09 -07:00
|
|
|
|
else if (md5.StartsWith("*"))
|
2016-09-06 11:38:55 -07:00
|
|
|
|
{
|
2016-09-06 12:34:09 -07:00
|
|
|
|
if (!romdata.HashData.MD5.EndsWith(md5.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2016-09-06 11:38:55 -07:00
|
|
|
|
}
|
2016-09-06 12:34:09 -07:00
|
|
|
|
else if (md5.EndsWith("*"))
|
2016-09-06 11:38:55 -07:00
|
|
|
|
{
|
2016-09-06 12:34:09 -07:00
|
|
|
|
if (!romdata.HashData.MD5.StartsWith(md5.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!String.Equals(romdata.HashData.MD5, md5, StringComparison.InvariantCultureIgnoreCase))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2016-09-06 11:38:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Filter on sha1
|
2016-09-06 12:18:30 -07:00
|
|
|
|
if (!String.IsNullOrEmpty(sha1))
|
2016-09-06 11:38:55 -07:00
|
|
|
|
{
|
2016-09-06 12:34:09 -07:00
|
|
|
|
if (sha1.StartsWith("*") && sha1.EndsWith("*"))
|
2016-09-06 11:38:55 -07:00
|
|
|
|
{
|
2016-09-06 12:34:09 -07:00
|
|
|
|
if (!romdata.HashData.SHA1.ToLowerInvariant().Contains(sha1.ToLowerInvariant().Replace("*", "")))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2016-09-06 11:38:55 -07:00
|
|
|
|
}
|
2016-09-06 12:34:09 -07:00
|
|
|
|
else if (sha1.StartsWith("*"))
|
2016-09-06 11:38:55 -07:00
|
|
|
|
{
|
2016-09-06 12:34:09 -07:00
|
|
|
|
if (!romdata.HashData.SHA1.EndsWith(sha1.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2016-09-06 11:38:55 -07:00
|
|
|
|
}
|
2016-09-06 12:34:09 -07:00
|
|
|
|
else if (sha1.EndsWith("*"))
|
2016-09-06 11:38:55 -07:00
|
|
|
|
{
|
2016-09-06 12:34:09 -07:00
|
|
|
|
if (!romdata.HashData.SHA1.StartsWith(sha1.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!String.Equals(romdata.HashData.SHA1, sha1, StringComparison.InvariantCultureIgnoreCase))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2016-09-06 11:38:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-06-20 15:17:58 -07:00
|
|
|
|
/// <summary>
|
2016-09-12 15:29:07 -07:00
|
|
|
|
/// Output user defined merge
|
2016-06-20 15:17:58 -07:00
|
|
|
|
/// </summary>
|
2016-09-16 16:35:58 -07:00
|
|
|
|
/// <param name="outDir">Output directory to write the DATs to</param>
|
2016-06-20 16:23:55 -07:00
|
|
|
|
/// <param name="inputs">List of inputs to write out from</param>
|
2016-09-12 15:29:07 -07:00
|
|
|
|
/// <param name="userData">Main DatData to draw information from</param>
|
|
|
|
|
|
/// <param name="datHeaders">Dat headers used optionally</param>
|
2016-06-20 16:23:55 -07:00
|
|
|
|
/// <param name="logger">Logging object for console and file output</param>
|
2016-09-16 16:35:58 -07:00
|
|
|
|
public static void MergeNoDiff(string outDir, Dat userData, List<string> inputs, List<Dat> datHeaders, Logger logger)
|
2016-06-20 15:17:58 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
// If we're in SuperDAT mode, prefix all games with their respective DATs
|
|
|
|
|
|
if (userData.Type == "SuperDAT")
|
2016-08-26 12:12:32 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
List<string> keys = userData.Files.Keys.ToList();
|
|
|
|
|
|
foreach (string key in keys)
|
|
|
|
|
|
{
|
|
|
|
|
|
List<Rom> newroms = new List<Rom>();
|
|
|
|
|
|
foreach (Rom rom in userData.Files[key])
|
|
|
|
|
|
{
|
|
|
|
|
|
Rom newrom = rom;
|
|
|
|
|
|
string filename = inputs[newrom.Metadata.SystemID].Split('¬')[0];
|
|
|
|
|
|
string rootpath = inputs[newrom.Metadata.SystemID].Split('¬')[1];
|
2016-06-20 15:17:58 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
rootpath += (rootpath == "" ? "" : Path.DirectorySeparatorChar.ToString());
|
|
|
|
|
|
filename = filename.Remove(0, rootpath.Length);
|
|
|
|
|
|
newrom.Machine.Name = Path.GetDirectoryName(filename) + Path.DirectorySeparatorChar
|
|
|
|
|
|
+ Path.GetFileNameWithoutExtension(filename) + Path.DirectorySeparatorChar
|
|
|
|
|
|
+ newrom.Machine.Name;
|
|
|
|
|
|
newroms.Add(newrom);
|
|
|
|
|
|
}
|
|
|
|
|
|
userData.Files[key] = newroms;
|
|
|
|
|
|
}
|
2016-08-26 12:12:32 -07:00
|
|
|
|
}
|
2016-06-20 15:17:58 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
// Output a DAT only if there are roms
|
|
|
|
|
|
if (userData.Files.Count != 0)
|
2016-06-20 15:17:58 -07:00
|
|
|
|
{
|
2016-09-16 16:35:58 -07:00
|
|
|
|
WriteDatfile(userData, outDir, logger);
|
2016-09-12 15:29:07 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-09-12 15:27:31 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
#endregion
|
2016-09-12 15:27:31 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
#region Converting and Updating (Parallel)
|
2016-06-20 15:17:58 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Convert, update, and filter a DAT file (Parallel)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <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="outputFormat">Non-zero flag for output format, zero otherwise for default</param>
|
2016-09-16 16:35:58 -07:00
|
|
|
|
/// <param name="outDir">Optional param for output directory</param>
|
2016-09-12 15:29:07 -07:00
|
|
|
|
/// <param name="merge">True if input files should be merged into a single file, false otherwise</param>
|
|
|
|
|
|
/// <param name="diff">Non-zero flag for diffing mode, zero otherwise</param>
|
|
|
|
|
|
/// <param name="cascade">True if the diffed files should be cascade diffed, false if diffed files should be reverse cascaded, null otherwise</param>
|
|
|
|
|
|
/// <param name="inplace">True if the cascade-diffed files should overwrite their inputs, false otherwise</param>
|
|
|
|
|
|
/// <param name="skip">True if the first cascaded diff file should be skipped on output, 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="softlist">True to allow SL DATs to have game names used instead of descriptions, false otherwise (default)</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="romtype">Type of the rom to match</param>
|
|
|
|
|
|
/// <param name="sgt">Find roms greater than or equal to this size</param>
|
|
|
|
|
|
/// <param name="slt">Find roms less than or equal to this size</param>
|
|
|
|
|
|
/// <param name="seq">Find roms equal to this size</param>
|
|
|
|
|
|
/// <param name="crc">CRC of the rom to match (can use asterisk-partials)</param>
|
|
|
|
|
|
/// <param name="md5">MD5 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="trim">True if we are supposed to trim names to NTFS length, false otherwise</param>
|
|
|
|
|
|
/// <param name="single">True if all games should be replaced by '!', false otherwise</param>
|
|
|
|
|
|
/// <param name="root">String representing root directory to compare against for length calculation</param>
|
|
|
|
|
|
/// <param name="maxDegreeOfParallelism">Integer representing the maximum amount of parallelization to be used</param>
|
|
|
|
|
|
/// <param name="logger">Logging object for console and file output</param>
|
2016-09-16 16:35:58 -07:00
|
|
|
|
public static void Update(List<string> inputFileNames, Dat datdata, OutputFormat outputFormat, string outDir, bool merge,
|
2016-09-12 15:29:07 -07:00
|
|
|
|
DiffMode diff, bool? cascade, bool inplace, bool skip, bool bare, bool clean, bool softlist, string gamename, string romname, string romtype,
|
|
|
|
|
|
long sgt, long slt, long seq, string crc, string md5, string sha1, bool? nodump, bool trim, bool single, string root, int maxDegreeOfParallelism,
|
|
|
|
|
|
Logger logger)
|
|
|
|
|
|
{
|
|
|
|
|
|
// If we're in merging or diffing mode, use the full list of inputs
|
|
|
|
|
|
if (merge || diff != 0)
|
2016-06-20 15:17:58 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
// Make sure there are no folders in inputs
|
|
|
|
|
|
List<string> newInputFileNames = new List<string>();
|
|
|
|
|
|
foreach (string input in inputFileNames)
|
2016-06-20 15:17:58 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
if (Directory.Exists(input))
|
2016-06-20 15:17:58 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
foreach (string file in Directory.EnumerateFiles(input, "*", SearchOption.AllDirectories))
|
2016-06-20 15:17:58 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
try
|
2016-06-20 15:17:58 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
newInputFileNames.Add(Path.GetFullPath(file) + "¬" + Path.GetFullPath(input));
|
2016-06-20 15:17:58 -07:00
|
|
|
|
}
|
2016-09-12 15:29:07 -07:00
|
|
|
|
catch (PathTooLongException)
|
2016-06-20 15:17:58 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
logger.Warning("The path for " + file + " was too long");
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.Error(ex.ToString());
|
2016-06-20 15:17:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-09-12 15:29:07 -07:00
|
|
|
|
else if (File.Exists(input))
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
newInputFileNames.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());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-06-20 15:17:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
// If we're in inverse cascade, reverse the list
|
|
|
|
|
|
if (cascade == false)
|
|
|
|
|
|
{
|
|
|
|
|
|
newInputFileNames.Reverse();
|
|
|
|
|
|
}
|
2016-06-20 15:17:58 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
// Create a dictionary of all ROMs from the input DATs
|
|
|
|
|
|
Dat userData;
|
|
|
|
|
|
List<Dat> datHeaders = PopulateUserData(newInputFileNames, inplace, clean, softlist,
|
2016-09-16 16:35:58 -07:00
|
|
|
|
outDir, datdata, out userData, gamename, romname, romtype, sgt, slt, seq,
|
2016-09-12 15:29:07 -07:00
|
|
|
|
crc, md5, sha1, nodump, trim, single, root, maxDegreeOfParallelism, logger);
|
2016-06-20 15:17:58 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
// Modify the Dictionary if necessary and output the results
|
|
|
|
|
|
if (diff != 0 && cascade == null)
|
|
|
|
|
|
{
|
2016-09-16 16:35:58 -07:00
|
|
|
|
DiffNoCascade(diff, outDir, userData, newInputFileNames, logger);
|
2016-09-12 15:29:07 -07:00
|
|
|
|
}
|
|
|
|
|
|
// If we're in cascade and diff, output only cascaded diffs
|
|
|
|
|
|
else if (diff != 0 && cascade != null)
|
|
|
|
|
|
{
|
2016-09-16 16:35:58 -07:00
|
|
|
|
DiffCascade(outDir, inplace, userData, newInputFileNames, datHeaders, skip, logger);
|
2016-09-12 15:29:07 -07:00
|
|
|
|
}
|
|
|
|
|
|
// Output all entries with user-defined merge
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2016-09-16 16:35:58 -07:00
|
|
|
|
MergeNoDiff(outDir, userData, newInputFileNames, datHeaders, logger);
|
2016-09-12 15:29:07 -07:00
|
|
|
|
}
|
2016-08-26 13:44:05 -07:00
|
|
|
|
}
|
2016-09-12 15:29:07 -07:00
|
|
|
|
// Otherwise, loop through all of the inputs individually
|
|
|
|
|
|
else
|
2016-06-20 15:17:58 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
Parallel.ForEach(inputFileNames,
|
|
|
|
|
|
new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism },
|
|
|
|
|
|
inputFileName =>
|
2016-06-20 15:17:58 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
// Clean the input string
|
|
|
|
|
|
if (inputFileName != "")
|
|
|
|
|
|
{
|
|
|
|
|
|
inputFileName = Path.GetFullPath(inputFileName);
|
|
|
|
|
|
}
|
2016-08-26 13:44:05 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
if (File.Exists(inputFileName))
|
2016-08-26 13:44:05 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
Dat innerDatdata = (Dat)datdata.CloneHeader();
|
|
|
|
|
|
logger.User("Processing \"" + Path.GetFileName(inputFileName) + "\"");
|
2016-09-18 21:05:48 -07:00
|
|
|
|
Parse(inputFileName, 0, 0, ref innerDatdata, gamename, romname,
|
2016-09-12 15:29:07 -07:00
|
|
|
|
romtype, sgt, slt, seq, crc, md5, sha1, nodump, trim, single,
|
|
|
|
|
|
root, logger, true, clean, softlist, keepext: (innerDatdata.XSV != null));
|
|
|
|
|
|
|
|
|
|
|
|
// If we have roms, output them
|
|
|
|
|
|
if (innerDatdata.Files.Count != 0)
|
|
|
|
|
|
{
|
2016-09-16 16:35:58 -07:00
|
|
|
|
WriteDatfile(innerDatdata, (outDir == "" ? Path.GetDirectoryName(inputFileName) : outDir), logger, overwrite: (outDir != ""));
|
2016-09-12 15:29:07 -07:00
|
|
|
|
}
|
2016-08-26 13:44:05 -07:00
|
|
|
|
}
|
2016-09-12 15:29:07 -07:00
|
|
|
|
else if (Directory.Exists(inputFileName))
|
|
|
|
|
|
{
|
|
|
|
|
|
inputFileName = Path.GetFullPath(inputFileName) + Path.DirectorySeparatorChar;
|
|
|
|
|
|
|
|
|
|
|
|
Parallel.ForEach(Directory.EnumerateFiles(inputFileName, "*", SearchOption.AllDirectories),
|
|
|
|
|
|
new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism },
|
|
|
|
|
|
file =>
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.User("Processing \"" + Path.GetFullPath(file).Remove(0, inputFileName.Length) + "\"");
|
|
|
|
|
|
Dat innerDatdata = (Dat)datdata.Clone();
|
|
|
|
|
|
innerDatdata.Files = null;
|
2016-09-18 21:05:48 -07:00
|
|
|
|
Parse(file, 0, 0, ref innerDatdata, gamename, romname, romtype, sgt,
|
2016-09-12 15:29:07 -07:00
|
|
|
|
slt, seq, crc, md5, sha1, nodump, trim, single, root, logger, true, clean, keepext: (datdata.XSV != null));
|
|
|
|
|
|
|
|
|
|
|
|
// If we have roms, output them
|
|
|
|
|
|
if (innerDatdata.Files != null && innerDatdata.Files.Count != 0)
|
|
|
|
|
|
{
|
2016-09-16 16:35:58 -07:00
|
|
|
|
WriteDatfile(innerDatdata, (outDir == "" ? Path.GetDirectoryName(file) : outDir + Path.GetDirectoryName(file).Remove(0, inputFileName.Length - 1)), logger, overwrite: (outDir != ""));
|
2016-09-12 15:29:07 -07:00
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.Error("I'm sorry but " + inputFileName + " doesn't exist!");
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2016-06-20 15:17:58 -07:00
|
|
|
|
}
|
2016-09-12 15:29:07 -07:00
|
|
|
|
return;
|
2016-06-20 15:17:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2016-09-12 15:29:07 -07:00
|
|
|
|
/// Populate the user DatData object from the input files
|
2016-06-20 15:17:58 -07:00
|
|
|
|
/// </summary>
|
2016-09-12 15:29:07 -07:00
|
|
|
|
/// <param name="userData">Output user DatData object to output</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="romtype">Type of the rom to match</param>
|
|
|
|
|
|
/// <param name="sgt">Find roms greater than or equal to this size</param>
|
|
|
|
|
|
/// <param name="slt">Find roms less than or equal to this size</param>
|
|
|
|
|
|
/// <param name="seq">Find roms equal to this size</param>
|
|
|
|
|
|
/// <param name="crc">CRC of the rom to match (can use asterisk-partials)</param>
|
|
|
|
|
|
/// <param name="md5">MD5 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="trim">True if we are supposed to trim names to NTFS length, false otherwise</param>
|
|
|
|
|
|
/// <param name="single">True if all games should be replaced by '!', false otherwise</param>
|
|
|
|
|
|
/// <param name="root">String representing root directory to compare against for length calculation</param>
|
|
|
|
|
|
/// <param name="maxDegreeOfParallelism">Integer representing the maximum amount of parallelization to be used</param>
|
2016-06-20 16:23:55 -07:00
|
|
|
|
/// <param name="logger">Logging object for console and file output</param>
|
2016-09-12 15:29:07 -07:00
|
|
|
|
/// <returns>List of DatData objects representing headers</returns>
|
2016-09-16 16:35:58 -07:00
|
|
|
|
private static List<Dat> PopulateUserData(List<string> inputs, bool inplace, bool clean, bool softlist, string outDir,
|
2016-09-12 15:29:07 -07:00
|
|
|
|
Dat inputDat, out Dat userData, string gamename, string romname, string romtype, long sgt, long slt, long seq, string crc,
|
|
|
|
|
|
string md5, string sha1, bool? nodump, bool trim, bool single, string root, int maxDegreeOfParallelism, Logger logger)
|
2016-06-20 15:17:58 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
Dat[] datHeaders = new Dat[inputs.Count];
|
2016-06-20 15:17:58 -07:00
|
|
|
|
DateTime start = DateTime.Now;
|
2016-09-12 15:29:07 -07:00
|
|
|
|
logger.User("Processing individual DATs");
|
2016-09-12 15:27:31 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
userData = new Dat
|
2016-06-20 15:17:58 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
OutputFormat = (inputDat.OutputFormat != 0 ? inputDat.OutputFormat: 0),
|
|
|
|
|
|
Files = new Dictionary<string, List<Rom>>(),
|
|
|
|
|
|
MergeRoms = inputDat.MergeRoms,
|
|
|
|
|
|
};
|
2016-06-20 15:17:58 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
Parallel.For(0, inputs.Count, i =>
|
|
|
|
|
|
{
|
|
|
|
|
|
string input = inputs[i];
|
|
|
|
|
|
logger.User("Adding DAT: " + input.Split('¬')[0]);
|
|
|
|
|
|
datHeaders[i] = new Dat
|
2016-06-20 15:17:58 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
OutputFormat = (inputDat.OutputFormat != 0 ? inputDat.OutputFormat: 0),
|
|
|
|
|
|
Files = new Dictionary<string, List<Rom>>(),
|
|
|
|
|
|
MergeRoms = inputDat.MergeRoms,
|
|
|
|
|
|
};
|
2016-09-12 15:27:31 -07:00
|
|
|
|
|
2016-09-18 21:05:48 -07:00
|
|
|
|
Parse(input.Split('¬')[0], i, 0, ref datHeaders[i], gamename, romname, romtype, sgt, slt, seq,
|
2016-09-12 15:29:07 -07:00
|
|
|
|
crc, md5, sha1, nodump, trim, single, root, logger, true, clean, softlist);
|
2016-09-12 15:27:31 -07:00
|
|
|
|
});
|
|
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
logger.User("Processing complete in " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff"));
|
|
|
|
|
|
logger.User("Populating internal DAT");
|
|
|
|
|
|
for (int i = 0; i < inputs.Count; i++)
|
2016-06-20 15:17:58 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
foreach (string key in datHeaders[i].Files.Keys)
|
2016-06-20 15:17:58 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
if (userData.Files.ContainsKey(key))
|
2016-06-20 15:17:58 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
userData.Files[key].AddRange(datHeaders[i].Files[key]);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
userData.Files.Add(key, datHeaders[i].Files[key]);
|
2016-06-20 15:17:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-09-12 15:29:07 -07:00
|
|
|
|
datHeaders[i].Files = null;
|
2016-06-20 15:17:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
// Set the output values
|
|
|
|
|
|
Dictionary<string, List<Rom>> roms = userData.Files;
|
|
|
|
|
|
userData = (Dat)inputDat.CloneHeader();
|
|
|
|
|
|
userData.Files = roms;
|
2016-06-20 15:17:58 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
logger.User("Processing and populating complete in " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff"));
|
|
|
|
|
|
|
|
|
|
|
|
return datHeaders.ToList();
|
2016-06-20 15:17:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2016-09-12 15:29:07 -07:00
|
|
|
|
/// Output non-cascading diffs
|
2016-06-20 15:17:58 -07:00
|
|
|
|
/// </summary>
|
2016-09-12 15:29:07 -07:00
|
|
|
|
/// <param name="diff">Non-zero flag for diffing mode, zero otherwise</param>
|
2016-09-16 16:35:58 -07:00
|
|
|
|
/// <param name="outDir">Output directory to write the DATs to</param>
|
2016-06-20 15:17:58 -07:00
|
|
|
|
/// <param name="userData">Main DatData to draw information from</param>
|
2016-09-12 15:29:07 -07:00
|
|
|
|
/// <param name="inputs">List of inputs to write out from</param>
|
2016-06-20 16:23:55 -07:00
|
|
|
|
/// <param name="logger">Logging object for console and file output</param>
|
2016-09-16 16:35:58 -07:00
|
|
|
|
public static void DiffNoCascade(DiffMode diff, string outDir, Dat userData, List<string> inputs, Logger logger)
|
2016-06-20 15:17:58 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
DateTime start = DateTime.Now;
|
|
|
|
|
|
logger.User("Initializing all output DATs");
|
2016-06-20 15:17:58 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
// Default vars for use
|
|
|
|
|
|
string post = "";
|
|
|
|
|
|
Dat outerDiffData = new Dat();
|
|
|
|
|
|
Dat dupeData = new Dat();
|
|
|
|
|
|
|
|
|
|
|
|
// Don't have External dupes
|
|
|
|
|
|
if ((diff & DiffMode.NoDupes) != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
post = " (No Duplicates)";
|
|
|
|
|
|
outerDiffData = (Dat)userData.CloneHeader();
|
|
|
|
|
|
outerDiffData.FileName += post;
|
|
|
|
|
|
outerDiffData.Name += post;
|
|
|
|
|
|
outerDiffData.Description += post;
|
|
|
|
|
|
outerDiffData.Files = new Dictionary<string, List<Rom>>();
|
2016-06-20 15:17:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
// Have External dupes
|
|
|
|
|
|
if ((diff & DiffMode.Dupes) != 0)
|
2016-06-20 16:23:55 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
post = " (Duplicates)";
|
|
|
|
|
|
dupeData = (Dat)userData.CloneHeader();
|
|
|
|
|
|
dupeData.FileName += post;
|
|
|
|
|
|
dupeData.Name += post;
|
|
|
|
|
|
dupeData.Description += post;
|
|
|
|
|
|
dupeData.Files = new Dictionary<string, List<Rom>>();
|
2016-06-20 16:23:55 -07:00
|
|
|
|
}
|
2016-08-29 17:28:08 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
// Create a list of DatData objects representing individual output files
|
|
|
|
|
|
List<Dat> outDats = new List<Dat>();
|
2016-09-01 20:38:41 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
// Loop through each of the inputs and get or create a new DatData object
|
|
|
|
|
|
if ((diff & DiffMode.Individuals) != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
Dat[] outDatsArray = new Dat[inputs.Count];
|
2016-09-07 10:58:21 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
Parallel.For(0, inputs.Count, j =>
|
|
|
|
|
|
{
|
|
|
|
|
|
string innerpost = " (" + Path.GetFileNameWithoutExtension(inputs[j].Split('¬')[0]) + " Only)";
|
|
|
|
|
|
Dat diffData = (Dat)userData.CloneHeader();
|
|
|
|
|
|
diffData.FileName += innerpost;
|
|
|
|
|
|
diffData.Name += innerpost;
|
|
|
|
|
|
diffData.Description += innerpost;
|
|
|
|
|
|
diffData.Files = new Dictionary<string, List<Rom>>();
|
|
|
|
|
|
outDatsArray[j] = diffData;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
outDats = outDatsArray.ToList();
|
|
|
|
|
|
}
|
|
|
|
|
|
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.Files.Keys.ToList();
|
|
|
|
|
|
foreach (string key in keys)
|
2016-09-07 10:58:21 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
List<Rom> roms = RomTools.Merge(userData.Files[key], logger);
|
|
|
|
|
|
|
|
|
|
|
|
if (roms != null && roms.Count > 0)
|
2016-09-07 10:58:21 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
foreach (Rom rom in roms)
|
2016-09-07 10:58:21 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
// No duplicates
|
|
|
|
|
|
if ((diff & DiffMode.NoDupes) != 0 || (diff & DiffMode.Individuals) != 0)
|
2016-09-07 10:58:21 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
if (rom.Dupe < DupeType.ExternalHash)
|
2016-09-07 10:58:21 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
// Individual DATs that are output
|
|
|
|
|
|
if ((diff & DiffMode.Individuals) != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (outDats[rom.Metadata.SystemID].Files.ContainsKey(key))
|
|
|
|
|
|
{
|
|
|
|
|
|
outDats[rom.Metadata.SystemID].Files[key].Add(rom);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
List<Rom> tl = new List<Rom>();
|
|
|
|
|
|
tl.Add(rom);
|
|
|
|
|
|
outDats[rom.Metadata.SystemID].Files.Add(key, tl);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Merged no-duplicates DAT
|
|
|
|
|
|
if ((diff & DiffMode.NoDupes) != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
Rom newrom = rom;
|
|
|
|
|
|
newrom.Machine.Name += " (" + Path.GetFileNameWithoutExtension(inputs[newrom.Metadata.SystemID].Split('¬')[0]) + ")";
|
|
|
|
|
|
|
|
|
|
|
|
if (outerDiffData.Files.ContainsKey(key))
|
|
|
|
|
|
{
|
|
|
|
|
|
outerDiffData.Files[key].Add(newrom);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
List<Rom> tl = new List<Rom>();
|
|
|
|
|
|
tl.Add(rom);
|
|
|
|
|
|
outerDiffData.Files.Add(key, tl);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-09-07 10:58:21 -07:00
|
|
|
|
}
|
2016-09-12 15:29:07 -07:00
|
|
|
|
|
|
|
|
|
|
// Duplicates only
|
|
|
|
|
|
if ((diff & DiffMode.Dupes) != 0)
|
2016-09-07 10:58:21 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
if (rom.Dupe >= DupeType.ExternalHash)
|
|
|
|
|
|
{
|
|
|
|
|
|
Rom newrom = rom;
|
|
|
|
|
|
newrom.Machine.Name += " (" + Path.GetFileNameWithoutExtension(inputs[newrom.Metadata.SystemID].Split('¬')[0]) + ")";
|
|
|
|
|
|
|
|
|
|
|
|
if (dupeData.Files.ContainsKey(key))
|
|
|
|
|
|
{
|
|
|
|
|
|
dupeData.Files[key].Add(newrom);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
List<Rom> tl = new List<Rom>();
|
|
|
|
|
|
tl.Add(rom);
|
|
|
|
|
|
dupeData.Files.Add(key, tl);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-09-07 10:58:21 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-09-12 15:29:07 -07:00
|
|
|
|
}
|
|
|
|
|
|
logger.User("Populating complete in " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff"));
|
2016-09-07 10:58:21 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
// Finally, loop through and output each of the DATs
|
|
|
|
|
|
start = DateTime.Now;
|
|
|
|
|
|
logger.User("Outputting all created DATs");
|
2016-09-07 10:58:21 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
// Output the difflist (a-b)+(b-a) diff
|
|
|
|
|
|
if ((diff & DiffMode.NoDupes) != 0)
|
|
|
|
|
|
{
|
2016-09-16 16:35:58 -07:00
|
|
|
|
WriteDatfile(outerDiffData, outDir, logger);
|
2016-09-12 15:29:07 -07:00
|
|
|
|
}
|
2016-09-07 10:58:21 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
// Output the (ab) diff
|
|
|
|
|
|
if ((diff & DiffMode.Dupes) != 0)
|
|
|
|
|
|
{
|
2016-09-16 16:35:58 -07:00
|
|
|
|
WriteDatfile(dupeData, outDir, logger);
|
2016-09-07 10:58:21 -07:00
|
|
|
|
}
|
2016-09-12 15:29:07 -07:00
|
|
|
|
|
|
|
|
|
|
// Output the individual (a-b) DATs
|
|
|
|
|
|
if ((diff & DiffMode.Individuals) != 0)
|
2016-09-07 10:58:21 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
for (int j = 0; j < inputs.Count; j++)
|
2016-09-07 10:58:21 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
// If we have an output directory set, replace the path
|
2016-09-16 16:35:58 -07:00
|
|
|
|
string path = outDir + (Path.GetDirectoryName(inputs[j].Split('¬')[0]).Remove(0, inputs[j].Split('¬')[1].Length));
|
2016-09-07 10:58:21 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
// If we have more than 0 roms, output
|
|
|
|
|
|
if (outDats[j].Files.Count > 0)
|
2016-09-07 10:58:21 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
WriteDatfile(outDats[j], path, logger);
|
2016-09-07 10:58:21 -07:00
|
|
|
|
}
|
2016-09-12 15:29:07 -07:00
|
|
|
|
}
|
2016-09-07 10:58:21 -07:00
|
|
|
|
}
|
2016-09-12 15:29:07 -07:00
|
|
|
|
logger.User("Outputting complete in " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff"));
|
2016-09-07 10:58:21 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-08 21:44:49 -07:00
|
|
|
|
/// <summary>
|
2016-09-12 15:29:07 -07:00
|
|
|
|
/// Output cascading diffs
|
2016-09-08 21:44:49 -07:00
|
|
|
|
/// </summary>
|
2016-09-16 16:35:58 -07:00
|
|
|
|
/// <param name="outDir">Output directory to write the DATs to</param>
|
2016-09-12 15:29:07 -07:00
|
|
|
|
/// <param name="inplace">True if cascaded diffs are outputted in-place, false otherwise</param>
|
|
|
|
|
|
/// <param name="userData">Main DatData to draw information from</param>
|
|
|
|
|
|
/// <param name="inputs">List of inputs to write out from</param>
|
|
|
|
|
|
/// <param name="datHeaders">Dat headers used optionally</param>
|
|
|
|
|
|
/// <param name="skip">True if the first cascaded diff file should be skipped on output, false otherwise</param>
|
2016-09-08 21:44:49 -07:00
|
|
|
|
/// <param name="logger">Logging object for console and file output</param>
|
2016-09-16 16:35:58 -07:00
|
|
|
|
public static void DiffCascade(string outDir, bool inplace, Dat userData, List<string> inputs, List<Dat> datHeaders, bool skip, Logger logger)
|
2016-09-08 21:44:49 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
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
|
2016-09-08 21:44:49 -07:00
|
|
|
|
DateTime start = DateTime.Now;
|
2016-09-12 15:29:07 -07:00
|
|
|
|
logger.User("Initializing all output DATs");
|
2016-09-08 21:44:49 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
Dat[] outDatsArray = new Dat[inputs.Count];
|
2016-09-08 21:44:49 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
Parallel.For(0, inputs.Count, j =>
|
2016-09-08 21:44:49 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
string innerpost = " (" + Path.GetFileNameWithoutExtension(inputs[j].Split('¬')[0]) + " Only)";
|
|
|
|
|
|
Dat diffData;
|
|
|
|
|
|
|
|
|
|
|
|
// If we're in inplace mode, take the appropriate DatData object already stored
|
2016-09-16 16:35:58 -07:00
|
|
|
|
if (inplace || !String.IsNullOrEmpty(outDir))
|
2016-09-08 21:44:49 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
diffData = datHeaders[j];
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
diffData = (Dat)userData.CloneHeader();
|
|
|
|
|
|
diffData.FileName += post;
|
|
|
|
|
|
diffData.Name += post;
|
|
|
|
|
|
diffData.Description += post;
|
|
|
|
|
|
}
|
|
|
|
|
|
diffData.Files = new Dictionary<string, List<Rom>>();
|
2016-09-08 21:44:49 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
outDatsArray[j] = diffData;
|
2016-09-08 21:44:49 -07:00
|
|
|
|
});
|
|
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
outDats = outDatsArray.ToList();
|
|
|
|
|
|
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.Files.Keys.ToList();
|
|
|
|
|
|
|
|
|
|
|
|
foreach (string key in keys)
|
2016-09-08 21:44:49 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
List<Rom> roms = RomTools.Merge(userData.Files[key], logger);
|
|
|
|
|
|
|
|
|
|
|
|
if (roms != null && roms.Count > 0)
|
2016-09-08 21:44:49 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
foreach (Rom rom in roms)
|
2016-09-08 21:44:49 -07:00
|
|
|
|
{
|
2016-09-12 15:29:07 -07:00
|
|
|
|
if (outDats[rom.Metadata.SystemID].Files.ContainsKey(key))
|
|
|
|
|
|
{
|
|
|
|
|
|
outDats[rom.Metadata.SystemID].Files[key].Add(rom);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
List<Rom> tl = new List<Rom>();
|
|
|
|
|
|
tl.Add(rom);
|
|
|
|
|
|
outDats[rom.Metadata.SystemID].Files.Add(key, tl);
|
|
|
|
|
|
}
|
2016-09-08 21:44:49 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-09-12 15:29:07 -07:00
|
|
|
|
logger.User("Populating complete in " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff"));
|
2016-09-08 21:44:49 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
// Finally, loop through and output each of the DATs
|
|
|
|
|
|
start = DateTime.Now;
|
|
|
|
|
|
logger.User("Outputting all created DATs");
|
|
|
|
|
|
for (int j = (skip ? 1 : 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]);
|
|
|
|
|
|
}
|
2016-09-16 16:35:58 -07:00
|
|
|
|
else if (!String.IsNullOrEmpty(outDir))
|
2016-09-12 15:29:07 -07:00
|
|
|
|
{
|
2016-09-16 16:35:58 -07:00
|
|
|
|
path = outDir + (Path.GetDirectoryName(inputs[j].Split('¬')[0]).Remove(0, inputs[j].Split('¬')[1].Length));
|
2016-09-12 15:29:07 -07:00
|
|
|
|
}
|
2016-09-08 21:44:49 -07:00
|
|
|
|
|
2016-09-12 15:29:07 -07:00
|
|
|
|
// If we have more than 0 roms, output
|
|
|
|
|
|
if (outDats[j].Files.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
WriteDatfile(outDats[j], path, logger);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
logger.User("Outputting complete in " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff"));
|
2016-09-08 21:44:49 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-07 10:58:21 -07:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
2016-09-01 20:38:41 -07:00
|
|
|
|
#region DAT Writing
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Create and open an output file for writing direct from a dictionary
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="datdata">All information for creating the datfile header</param>
|
|
|
|
|
|
/// <param name="outDir">Set the output directory</param>
|
|
|
|
|
|
/// <param name="logger">Logger object for console and/or file output</param>
|
|
|
|
|
|
/// <param name="norename">True if games should only be compared on game and file name (default), false if system and source are counted</param>
|
|
|
|
|
|
/// <param name="stats">True if DAT statistics should be output on write, false otherwise (default)</param>
|
|
|
|
|
|
/// <param name="ignoreblanks">True if blank roms should be skipped on output, false otherwise (default)</param>
|
2016-09-09 15:37:15 -07:00
|
|
|
|
/// <param name="overwrite">True if files should be overwritten (default), false if they should be renamed instead</param>
|
2016-09-01 20:38:41 -07:00
|
|
|
|
/// <returns>True if the DAT was written correctly, false otherwise</returns>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// The following features have been requested for file output:
|
|
|
|
|
|
/// - Have the ability to strip special (non-ASCII) characters from rom information
|
|
|
|
|
|
/// </remarks>
|
2016-09-09 15:37:15 -07:00
|
|
|
|
public static bool WriteDatfile(Dat datdata, string outDir, Logger logger, bool norename = true, bool stats = false, bool ignoreblanks = false, bool overwrite = true)
|
2016-09-01 20:38:41 -07:00
|
|
|
|
{
|
2016-09-06 20:47:21 -07:00
|
|
|
|
// If there's nothing there, abort
|
|
|
|
|
|
if (datdata.Files == null || datdata.Files.Count == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-07 10:31:57 -07:00
|
|
|
|
// If output directory is empty, use the current folder
|
|
|
|
|
|
if (outDir.Trim() == "")
|
2016-09-01 20:38:41 -07:00
|
|
|
|
{
|
2016-09-07 10:31:57 -07:00
|
|
|
|
outDir = Environment.CurrentDirectory;
|
2016-09-01 20:38:41 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-07 10:31:57 -07:00
|
|
|
|
// Create the output directory if it doesn't already exist
|
|
|
|
|
|
if (!Directory.Exists(outDir))
|
2016-09-01 20:38:41 -07:00
|
|
|
|
{
|
2016-09-07 10:31:57 -07:00
|
|
|
|
Directory.CreateDirectory(outDir);
|
2016-09-01 20:38:41 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-07 10:31:57 -07:00
|
|
|
|
// If the DAT has no output format, default to XML
|
2016-09-09 15:54:10 -07:00
|
|
|
|
if (datdata.OutputFormat == 0)
|
2016-09-01 20:38:41 -07:00
|
|
|
|
{
|
2016-09-09 15:54:10 -07:00
|
|
|
|
datdata.OutputFormat = OutputFormat.Xml;
|
2016-09-01 20:38:41 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Make sure that the three essential fields are filled in
|
|
|
|
|
|
if (String.IsNullOrEmpty(datdata.FileName) && String.IsNullOrEmpty(datdata.Name) && String.IsNullOrEmpty(datdata.Description))
|
|
|
|
|
|
{
|
|
|
|
|
|
datdata.FileName = datdata.Name = datdata.Description = "Default";
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (String.IsNullOrEmpty(datdata.FileName) && String.IsNullOrEmpty(datdata.Name) && !String.IsNullOrEmpty(datdata.Description))
|
|
|
|
|
|
{
|
|
|
|
|
|
datdata.FileName = datdata.Name = datdata.Description;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (String.IsNullOrEmpty(datdata.FileName) && !String.IsNullOrEmpty(datdata.Name) && String.IsNullOrEmpty(datdata.Description))
|
|
|
|
|
|
{
|
|
|
|
|
|
datdata.FileName = datdata.Description = datdata.Name;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (String.IsNullOrEmpty(datdata.FileName) && !String.IsNullOrEmpty(datdata.Name) && !String.IsNullOrEmpty(datdata.Description))
|
|
|
|
|
|
{
|
|
|
|
|
|
datdata.FileName = datdata.Description;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (!String.IsNullOrEmpty(datdata.FileName) && String.IsNullOrEmpty(datdata.Name) && String.IsNullOrEmpty(datdata.Description))
|
|
|
|
|
|
{
|
|
|
|
|
|
datdata.Name = datdata.Description = datdata.FileName;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (!String.IsNullOrEmpty(datdata.FileName) && String.IsNullOrEmpty(datdata.Name) && !String.IsNullOrEmpty(datdata.Description))
|
|
|
|
|
|
{
|
|
|
|
|
|
datdata.Name = datdata.Description;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (!String.IsNullOrEmpty(datdata.FileName) && !String.IsNullOrEmpty(datdata.Name) && String.IsNullOrEmpty(datdata.Description))
|
|
|
|
|
|
{
|
|
|
|
|
|
datdata.Description = datdata.Name;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (!String.IsNullOrEmpty(datdata.FileName) && !String.IsNullOrEmpty(datdata.Name) && !String.IsNullOrEmpty(datdata.Description))
|
|
|
|
|
|
{
|
|
|
|
|
|
// Nothing is needed
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-07 10:31:57 -07:00
|
|
|
|
// Output initial statistics, for kicks
|
|
|
|
|
|
if (stats)
|
|
|
|
|
|
{
|
|
|
|
|
|
Stats.OutputStats(datdata, logger, (datdata.RomCount + datdata.DiskCount == 0));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Bucket roms by game name and optionally dedupe
|
2016-09-07 15:32:55 -07:00
|
|
|
|
SortedDictionary<string, List<Rom>> sortable = BucketByGame(datdata.Files, datdata.MergeRoms, norename, logger);
|
2016-09-07 10:31:57 -07:00
|
|
|
|
|
2016-09-01 20:38:41 -07:00
|
|
|
|
// Get the outfile name
|
2016-09-09 15:54:10 -07:00
|
|
|
|
Dictionary<OutputFormat, string> outfiles = Style.CreateOutfileNames(outDir, datdata, overwrite);
|
2016-09-01 20:38:41 -07:00
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2016-09-09 15:54:10 -07:00
|
|
|
|
foreach (OutputFormat outputFormat in outfiles.Keys)
|
2016-09-09 15:25:37 -07:00
|
|
|
|
{
|
2016-09-09 15:54:10 -07:00
|
|
|
|
string outfile = outfiles[outputFormat];
|
2016-09-01 20:38:41 -07:00
|
|
|
|
|
2016-09-09 15:25:37 -07:00
|
|
|
|
logger.User("Opening file for writing: " + outfile);
|
|
|
|
|
|
FileStream fs = File.Create(outfile);
|
|
|
|
|
|
StreamWriter sw = new StreamWriter(fs, Encoding.UTF8);
|
2016-09-01 20:38:41 -07:00
|
|
|
|
|
2016-09-09 15:25:37 -07:00
|
|
|
|
// Write out the header
|
2016-09-09 15:54:10 -07:00
|
|
|
|
WriteHeader(sw, outputFormat, datdata, logger);
|
2016-09-07 13:59:25 -07:00
|
|
|
|
|
2016-09-09 15:25:37 -07:00
|
|
|
|
// Write out each of the machines and roms
|
|
|
|
|
|
int depth = 2, last = -1;
|
|
|
|
|
|
string lastgame = null;
|
|
|
|
|
|
List<string> splitpath = new List<string>();
|
2016-09-07 13:59:25 -07:00
|
|
|
|
|
2016-09-09 15:25:37 -07:00
|
|
|
|
// Get a properly sorted set of keys
|
|
|
|
|
|
List<string> keys = sortable.Keys.ToList();
|
|
|
|
|
|
keys.Sort(Style.CompareNumeric);
|
2016-09-07 12:39:09 -07:00
|
|
|
|
|
2016-09-09 15:25:37 -07:00
|
|
|
|
foreach (string key in keys)
|
2016-09-01 20:38:41 -07:00
|
|
|
|
{
|
2016-09-09 15:25:37 -07:00
|
|
|
|
List<Rom> roms = sortable[key];
|
2016-09-01 20:38:41 -07:00
|
|
|
|
|
2016-09-09 15:25:37 -07:00
|
|
|
|
for (int index = 0; index < roms.Count; index++)
|
2016-09-01 20:38:41 -07:00
|
|
|
|
{
|
2016-09-09 15:25:37 -07:00
|
|
|
|
Rom rom = roms[index];
|
2016-09-18 13:03:51 -07:00
|
|
|
|
|
|
|
|
|
|
// There are apparently times when a null rom can skip by, skip them
|
|
|
|
|
|
if (rom.Name == null || rom.Machine.Name == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.Warning("Null rom found!");
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-09 15:25:37 -07:00
|
|
|
|
List<string> newsplit = rom.Machine.Name.Split('\\').ToList();
|
2016-09-01 20:38:41 -07:00
|
|
|
|
|
2016-09-09 15:25:37 -07:00
|
|
|
|
// If we have a different game and we're not at the start of the list, output the end of last item
|
|
|
|
|
|
if (lastgame != null && lastgame.ToLowerInvariant() != rom.Machine.Name.ToLowerInvariant())
|
|
|
|
|
|
{
|
2016-09-09 15:54:10 -07:00
|
|
|
|
depth = WriteEndGame(sw, outputFormat, rom, splitpath, newsplit, lastgame, depth, out last, logger);
|
2016-09-09 15:25:37 -07:00
|
|
|
|
}
|
2016-09-01 20:38:41 -07:00
|
|
|
|
|
2016-09-09 15:25:37 -07:00
|
|
|
|
// If we have a new game, output the beginning of the new item
|
|
|
|
|
|
if (lastgame == null || lastgame.ToLowerInvariant() != rom.Machine.Name.ToLowerInvariant())
|
2016-09-01 20:38:41 -07:00
|
|
|
|
{
|
2016-09-09 15:54:10 -07:00
|
|
|
|
depth = WriteStartGame(sw, outputFormat, rom, newsplit, lastgame, depth, last, logger);
|
2016-09-01 20:38:41 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-09 15:25:37 -07:00
|
|
|
|
// If we have a "null" game (created by DATFromDir or something similar), log it to file
|
|
|
|
|
|
if (rom.HashData.Size == -1 && rom.HashData.CRC == "null" && rom.HashData.MD5 == "null" && rom.HashData.SHA1 == "null")
|
2016-09-01 20:38:41 -07:00
|
|
|
|
{
|
2016-09-09 15:25:37 -07:00
|
|
|
|
logger.Log("Empty folder found: " + rom.Machine.Name);
|
|
|
|
|
|
|
|
|
|
|
|
// If we're in a mode that doesn't allow for actual empty folders, add the blank info
|
2016-09-09 15:54:10 -07:00
|
|
|
|
if (outputFormat != OutputFormat.SabreDat && outputFormat != OutputFormat.MissFile)
|
2016-09-09 15:25:37 -07:00
|
|
|
|
{
|
|
|
|
|
|
rom.Name = (rom.Name == "null" ? "-" : rom.Name);
|
|
|
|
|
|
rom.HashData.Size = Constants.SizeZero;
|
|
|
|
|
|
rom.HashData.CRC = Constants.CRCZero;
|
|
|
|
|
|
rom.HashData.MD5 = Constants.MD5Zero;
|
|
|
|
|
|
rom.HashData.SHA1 = Constants.SHA1Zero;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Otherwise, set the new path and such, write out, and continue
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
splitpath = newsplit;
|
|
|
|
|
|
lastgame = rom.Machine.Name;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2016-09-01 20:38:41 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-09 15:25:37 -07:00
|
|
|
|
// Now, output the rom data
|
2016-09-09 15:54:10 -07:00
|
|
|
|
WriteRomData(sw, outputFormat, rom, lastgame, datdata, depth, logger, ignoreblanks);
|
2016-09-01 20:38:41 -07:00
|
|
|
|
|
2016-09-09 15:25:37 -07:00
|
|
|
|
// Set the new data to compare against
|
|
|
|
|
|
splitpath = newsplit;
|
|
|
|
|
|
lastgame = rom.Machine.Name;
|
|
|
|
|
|
}
|
2016-09-01 20:38:41 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-09 15:25:37 -07:00
|
|
|
|
// Write the file footer out
|
2016-09-09 15:54:10 -07:00
|
|
|
|
WriteFooter(sw, outputFormat, datdata, depth, logger);
|
2016-09-01 20:38:41 -07:00
|
|
|
|
|
2016-09-09 15:25:37 -07:00
|
|
|
|
logger.Log("File written!" + Environment.NewLine);
|
|
|
|
|
|
sw.Close();
|
|
|
|
|
|
fs.Close();
|
|
|
|
|
|
}
|
2016-09-01 20:38:41 -07:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.Error(ex.ToString());
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Write out DAT header using the supplied StreamWriter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="sw">StreamWriter to output to</param>
|
2016-09-09 15:54:10 -07:00
|
|
|
|
/// <param name="outputFormat">Output format to write to</param>
|
2016-09-01 20:38:41 -07:00
|
|
|
|
/// <param name="datdata">DatData object representing DAT information</param>
|
|
|
|
|
|
/// <param name="logger">Logger object for file and console output</param>
|
|
|
|
|
|
/// <returns>True if the data was written, false on error</returns>
|
2016-09-09 15:54:10 -07:00
|
|
|
|
public static bool WriteHeader(StreamWriter sw, OutputFormat outputFormat, Dat datdata, Logger logger)
|
2016-09-01 20:38:41 -07:00
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
string header = "";
|
2016-09-09 15:54:10 -07:00
|
|
|
|
switch (outputFormat)
|
2016-09-01 20:38:41 -07:00
|
|
|
|
{
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.ClrMamePro:
|
2016-09-01 20:38:41 -07:00
|
|
|
|
header = "clrmamepro (\n" +
|
|
|
|
|
|
"\tname \"" + datdata.Name + "\"\n" +
|
|
|
|
|
|
"\tdescription \"" + datdata.Description + "\"\n" +
|
|
|
|
|
|
"\tcategory \"" + datdata.Category + "\"\n" +
|
|
|
|
|
|
"\tversion \"" + datdata.Version + "\"\n" +
|
|
|
|
|
|
"\tdate \"" + datdata.Date + "\"\n" +
|
|
|
|
|
|
"\tauthor \"" + datdata.Author + "\"\n" +
|
|
|
|
|
|
"\temail \"" + datdata.Email + "\"\n" +
|
|
|
|
|
|
"\thomepage \"" + datdata.Homepage + "\"\n" +
|
|
|
|
|
|
"\turl \"" + datdata.Url + "\"\n" +
|
|
|
|
|
|
"\tcomment \"" + datdata.Comment + "\"\n" +
|
|
|
|
|
|
(datdata.ForcePacking == ForcePacking.Unzip ? "\tforcezipping no\n" : "") +
|
2016-09-12 14:33:24 -07:00
|
|
|
|
(datdata.ForcePacking == ForcePacking.Zip ? "\tforcezipping yes\n" : "") +
|
|
|
|
|
|
(datdata.ForceMerging == ForceMerging.Full ? "\tforcemerging full\n" : "") +
|
|
|
|
|
|
(datdata.ForceMerging == ForceMerging.Split ? "\tforcemerging split\n" : "") +
|
2016-09-01 20:38:41 -07:00
|
|
|
|
")\n";
|
|
|
|
|
|
break;
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.MissFile:
|
2016-09-01 20:38:41 -07:00
|
|
|
|
if (datdata.XSV == true)
|
|
|
|
|
|
{
|
|
|
|
|
|
header = "\"File Name\"\t\"Internal Name\"\t\"Description\"\t\"Game Name\"\t\"Game Description\"\t\"Type\"\t\"" +
|
|
|
|
|
|
"Rom Name\"\t\"Disk Name\"\t\"Size\"\t\"CRC\"\t\"MD5\"\t\"SHA1\"\t\"Nodump\"\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (datdata.XSV == false)
|
|
|
|
|
|
{
|
|
|
|
|
|
header = "\"File Name\",\"Internal Name\",\"Description\",\"Game Name\",\"Game Description\",\"Type\",\"" +
|
|
|
|
|
|
"Rom Name\",\"Disk Name\",\"Size\",\"CRC\",\"MD5\",\"SHA1\",\"Nodump\"\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.RomCenter:
|
2016-09-01 20:38:41 -07:00
|
|
|
|
header = "[CREDITS]\n" +
|
|
|
|
|
|
"author=" + datdata.Author + "\n" +
|
|
|
|
|
|
"version=" + datdata.Version + "\n" +
|
|
|
|
|
|
"comment=" + datdata.Comment + "\n" +
|
|
|
|
|
|
"[DAT]\n" +
|
|
|
|
|
|
"version=2.50\n" +
|
|
|
|
|
|
"split=" + (datdata.ForceMerging == ForceMerging.Split ? "1" : "0") + "\n" +
|
|
|
|
|
|
"merge=" + (datdata.ForceMerging == ForceMerging.Full ? "1" : "0") + "\n" +
|
|
|
|
|
|
"[EMULATOR]\n" +
|
|
|
|
|
|
"refname=" + datdata.Name + "\n" +
|
|
|
|
|
|
"version=" + datdata.Description + "\n" +
|
|
|
|
|
|
"[GAMES]\n";
|
|
|
|
|
|
break;
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.SabreDat:
|
2016-09-01 20:38:41 -07:00
|
|
|
|
header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
|
|
|
|
|
|
"<!DOCTYPE datafile PUBLIC \"-//Logiqx//DTD ROM Management Datafile//EN\" \"http://www.logiqx.com/Dats/datafile.dtd\">\n\n" +
|
|
|
|
|
|
"<datafile>\n" +
|
|
|
|
|
|
"\t<header>\n" +
|
|
|
|
|
|
"\t\t<name>" + HttpUtility.HtmlEncode(datdata.Name) + "</name>\n" +
|
|
|
|
|
|
"\t\t<description>" + HttpUtility.HtmlEncode(datdata.Description) + "</description>\n" +
|
2016-09-14 12:51:18 -07:00
|
|
|
|
(!String.IsNullOrEmpty(datdata.RootDir) ? "\t\t<rootdir>" + HttpUtility.HtmlEncode(datdata.RootDir) + "</rootdir>\n" : "") +
|
|
|
|
|
|
(!String.IsNullOrEmpty(datdata.Category) ? "\t\t<category>" + HttpUtility.HtmlEncode(datdata.Category) + "</category>\n" : "") +
|
2016-09-01 20:38:41 -07:00
|
|
|
|
"\t\t<version>" + HttpUtility.HtmlEncode(datdata.Version) + "</version>\n" +
|
2016-09-14 12:51:18 -07:00
|
|
|
|
(!String.IsNullOrEmpty(datdata.Date) ? "\t\t<date>" + HttpUtility.HtmlEncode(datdata.Date) + "</date>\n" : "") +
|
2016-09-01 20:38:41 -07:00
|
|
|
|
"\t\t<author>" + HttpUtility.HtmlEncode(datdata.Author) + "</author>\n" +
|
2016-09-14 12:51:18 -07:00
|
|
|
|
(!String.IsNullOrEmpty(datdata.Comment) ? "\t\t<comment>" + HttpUtility.HtmlEncode(datdata.Comment) + "</comment>\n" : "") +
|
|
|
|
|
|
(!String.IsNullOrEmpty(datdata.Type) || datdata.ForcePacking != ForcePacking.None || datdata.ForceMerging != ForceMerging.None || datdata.ForceNodump != ForceNodump.None ?
|
2016-09-01 20:38:41 -07:00
|
|
|
|
"\t\t<flags>\n" +
|
2016-09-14 12:51:18 -07:00
|
|
|
|
(!String.IsNullOrEmpty(datdata.Type) ? "\t\t\t<flag name=\"type\" value=\"" + HttpUtility.HtmlEncode(datdata.Type) + "\"/>\n" : "") +
|
|
|
|
|
|
(datdata.ForcePacking == ForcePacking.Unzip ? "\t\t\t<flag name=\"forcepacking\" value=\"unzip\"/>\n" : "") +
|
|
|
|
|
|
(datdata.ForcePacking == ForcePacking.Zip ? "\t\t\t<flag name=\"forcepacking\" value=\"zip\"/>\n" : "") +
|
|
|
|
|
|
(datdata.ForceMerging == ForceMerging.Full ? "\t\t\t<flag name=\"forcemerging\" value=\"full\"/>\n" : "") +
|
|
|
|
|
|
(datdata.ForceMerging == ForceMerging.Split ? "\t\t\t<flag name=\"forcemerging\" value=\"split\"/>\n" : "") +
|
|
|
|
|
|
(datdata.ForceNodump == ForceNodump.Ignore ? "\t\t\t<flag name=\"forcenodump\" value=\"ignore\"/>\n" : "") +
|
|
|
|
|
|
(datdata.ForceNodump == ForceNodump.Obsolete ? "\t\t\t<flag name=\"forcenodump\" value=\"obsolete\"/>\n" : "") +
|
|
|
|
|
|
(datdata.ForceNodump == ForceNodump.Required ? "\t\t\t<flag name=\"forcenodump\" value=\"required\"/>\n" : "") +
|
|
|
|
|
|
"\t\t</flags>\n"
|
|
|
|
|
|
: "") +
|
2016-09-01 20:38:41 -07:00
|
|
|
|
"\t</header>\n" +
|
|
|
|
|
|
"\t<data>\n";
|
|
|
|
|
|
break;
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.Xml:
|
2016-09-01 20:38:41 -07:00
|
|
|
|
header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
|
|
|
|
|
|
"<!DOCTYPE datafile PUBLIC \"-//Logiqx//DTD ROM Management Datafile//EN\" \"http://www.logiqx.com/Dats/datafile.dtd\">\n\n" +
|
|
|
|
|
|
"<datafile>\n" +
|
|
|
|
|
|
"\t<header>\n" +
|
|
|
|
|
|
"\t\t<name>" + HttpUtility.HtmlEncode(datdata.Name) + "</name>\n" +
|
|
|
|
|
|
"\t\t<description>" + HttpUtility.HtmlEncode(datdata.Description) + "</description>\n" +
|
2016-09-14 12:45:53 -07:00
|
|
|
|
(!String.IsNullOrEmpty(datdata.RootDir) ? "\t\t<rootdir>" + HttpUtility.HtmlEncode(datdata.RootDir) + "</rootdir>\n" : "") +
|
|
|
|
|
|
(!String.IsNullOrEmpty(datdata.Category) ? "\t\t<category>" + HttpUtility.HtmlEncode(datdata.Category) + "</category>\n" : "") +
|
2016-09-01 20:38:41 -07:00
|
|
|
|
"\t\t<version>" + HttpUtility.HtmlEncode(datdata.Version) + "</version>\n" +
|
2016-09-14 12:45:53 -07:00
|
|
|
|
(!String.IsNullOrEmpty(datdata.Date) ? "\t\t<date>" + HttpUtility.HtmlEncode(datdata.Date) + "</date>\n" : "") +
|
2016-09-01 20:38:41 -07:00
|
|
|
|
"\t\t<author>" + HttpUtility.HtmlEncode(datdata.Author) + "</author>\n" +
|
2016-09-14 12:45:53 -07:00
|
|
|
|
(!String.IsNullOrEmpty(datdata.Email) ? "\t\t<email>" + HttpUtility.HtmlEncode(datdata.Email) + "</email>\n" : "") +
|
|
|
|
|
|
(!String.IsNullOrEmpty(datdata.Homepage) ? "\t\t<homepage>" + HttpUtility.HtmlEncode(datdata.Homepage) + "</homepage>\n" : "") +
|
|
|
|
|
|
(!String.IsNullOrEmpty(datdata.Url) ? "\t\t<url>" + HttpUtility.HtmlEncode(datdata.Url) + "</url>\n" : "") +
|
|
|
|
|
|
(!String.IsNullOrEmpty(datdata.Comment) ? "\t\t<comment>" + HttpUtility.HtmlEncode(datdata.Comment) + "</comment>\n" : "") +
|
2016-09-14 12:16:34 -07:00
|
|
|
|
(!String.IsNullOrEmpty(datdata.Type) ? "\t\t<type>" + HttpUtility.HtmlEncode(datdata.Type) + "</type>\n" : "") +
|
2016-09-12 14:33:24 -07:00
|
|
|
|
(datdata.ForcePacking != ForcePacking.None || datdata.ForceMerging != ForceMerging.None || datdata.ForceNodump != ForceNodump.None ?
|
|
|
|
|
|
"\t\t<clrmamepro" +
|
|
|
|
|
|
(datdata.ForcePacking == ForcePacking.Unzip ? " forcepacking=\"unzip\"" : "") +
|
|
|
|
|
|
(datdata.ForcePacking == ForcePacking.Zip ? " forcepacking=\"zip\"" : "") +
|
|
|
|
|
|
(datdata.ForceMerging == ForceMerging.Full ? " forcemerging=\"full\"" : "") +
|
|
|
|
|
|
(datdata.ForceMerging == ForceMerging.Split ? " forcemerging=\"split\"" : "") +
|
|
|
|
|
|
(datdata.ForceNodump == ForceNodump.Ignore ? " forcenodump=\"ignore\"" : "") +
|
2016-09-14 12:51:18 -07:00
|
|
|
|
(datdata.ForceNodump == ForceNodump.Obsolete ? " forcenodump=\"obsolete\"" : "") +
|
2016-09-12 14:33:24 -07:00
|
|
|
|
(datdata.ForceNodump == ForceNodump.Required ? " forcenodump=\"required\"" : "") +
|
|
|
|
|
|
" />\n"
|
|
|
|
|
|
: "") +
|
2016-09-01 20:38:41 -07:00
|
|
|
|
"\t</header>\n";
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Write the header out
|
|
|
|
|
|
sw.Write(header);
|
2016-09-18 13:03:51 -07:00
|
|
|
|
sw.Flush();
|
2016-09-01 20:38:41 -07:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.Error(ex.ToString());
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Write out Game start using the supplied StreamWriter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="sw">StreamWriter to output to</param>
|
2016-09-09 15:54:10 -07:00
|
|
|
|
/// <param name="outputFormat">Output format to write to</param>
|
2016-09-01 20:38:41 -07:00
|
|
|
|
/// <param name="rom">RomData object to be output</param>
|
|
|
|
|
|
/// <param name="newsplit">Split path representing the parent game (SabreDAT only)</param>
|
|
|
|
|
|
/// <param name="lastgame">The name of the last game to be output</param>
|
|
|
|
|
|
/// <param name="depth">Current depth to output file at (SabreDAT only)</param>
|
|
|
|
|
|
/// <param name="last">Last known depth to cycle back from (SabreDAT only)</param>
|
|
|
|
|
|
/// <param name="logger">Logger object for file and console output</param>
|
|
|
|
|
|
/// <returns>The new depth of the tag</returns>
|
2016-09-09 15:54:10 -07:00
|
|
|
|
public static int WriteStartGame(StreamWriter sw, OutputFormat outputFormat, Rom rom, List<string> newsplit, string lastgame, int depth, int last, Logger logger)
|
2016-09-01 20:38:41 -07:00
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// No game should start with a path separator
|
|
|
|
|
|
if (rom.Machine.Name.StartsWith(Path.DirectorySeparatorChar.ToString()))
|
|
|
|
|
|
{
|
|
|
|
|
|
rom.Machine.Name = rom.Machine.Name.Substring(1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string state = "";
|
2016-09-09 15:54:10 -07:00
|
|
|
|
switch (outputFormat)
|
2016-09-01 20:38:41 -07:00
|
|
|
|
{
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.ClrMamePro:
|
2016-09-01 20:38:41 -07:00
|
|
|
|
state += "game (\n\tname \"" + rom.Machine.Name + "\"\n" +
|
2016-09-12 23:04:28 -07:00
|
|
|
|
(String.IsNullOrEmpty(rom.Machine.RomOf) ? "" : "\tromof \"" + rom.Machine.RomOf + "\"\n") +
|
|
|
|
|
|
(String.IsNullOrEmpty(rom.Machine.CloneOf) ? "" : "\tcloneof \"" + rom.Machine.CloneOf + "\"\n") +
|
|
|
|
|
|
"\tdescription \"" + (String.IsNullOrEmpty(rom.Machine.Description) ? rom.Machine.Name : rom.Machine.Description) + "\"\n" +
|
|
|
|
|
|
(String.IsNullOrEmpty(rom.Machine.Year) ? "" : "\tyear " + rom.Machine.Year + "\n") +
|
|
|
|
|
|
(String.IsNullOrEmpty(rom.Machine.Manufacturer) ? "" : "\tmanufacturer \"" + rom.Machine.Manufacturer + "\"\n");
|
|
|
|
|
|
|
2016-09-01 20:38:41 -07:00
|
|
|
|
break;
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.SabreDat:
|
2016-09-01 20:38:41 -07:00
|
|
|
|
for (int i = (last == -1 ? 0 : last); i < newsplit.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int j = 0; j < depth - last + i - (lastgame == null ? 1 : 0); j++)
|
|
|
|
|
|
{
|
|
|
|
|
|
state += "\t";
|
|
|
|
|
|
}
|
|
|
|
|
|
state += "<directory name=\"" + HttpUtility.HtmlEncode(newsplit[i]) + "\" description=\"" +
|
|
|
|
|
|
HttpUtility.HtmlEncode(newsplit[i]) + "\">\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
depth = depth - (last == -1 ? 0 : last) + newsplit.Count;
|
|
|
|
|
|
break;
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.Xml:
|
2016-09-12 23:04:28 -07:00
|
|
|
|
state += "\t<machine name=\"" + HttpUtility.HtmlEncode(rom.Machine.Name) + "\"" +
|
|
|
|
|
|
(rom.Machine.IsBios ? " isbios=\"yes\"" : "") +
|
|
|
|
|
|
(String.IsNullOrEmpty(rom.Machine.CloneOf) ? "" : " cloneof=\"" + HttpUtility.HtmlEncode(rom.Machine.CloneOf) + "\"") +
|
|
|
|
|
|
(String.IsNullOrEmpty(rom.Machine.RomOf) ? "" : " romof=\"" + HttpUtility.HtmlEncode(rom.Machine.RomOf) + "\"") +
|
2016-09-12 23:05:45 -07:00
|
|
|
|
(String.IsNullOrEmpty(rom.Machine.SampleOf) ? "" : " sampleof=\"" + HttpUtility.HtmlEncode(rom.Machine.SampleOf) + "\"") +
|
2016-09-12 23:04:28 -07:00
|
|
|
|
">\n" +
|
|
|
|
|
|
(String.IsNullOrEmpty(rom.Machine.Comment) ? "" : "\t\t<comment>" + HttpUtility.HtmlEncode(rom.Machine.Comment) + "</comment>\n") +
|
|
|
|
|
|
"\t\t<description>" + HttpUtility.HtmlEncode((String.IsNullOrEmpty(rom.Machine.Description) ? rom.Machine.Name : rom.Machine.Description)) + "</description>\n" +
|
|
|
|
|
|
(String.IsNullOrEmpty(rom.Machine.Year) ? "" : "\t\t<year>" + HttpUtility.HtmlEncode(rom.Machine.Year) + "</year>\n") +
|
|
|
|
|
|
(String.IsNullOrEmpty(rom.Machine.Manufacturer) ? "" : "\t\t<manufacturer>" + HttpUtility.HtmlEncode(rom.Machine.Manufacturer) + "</manufacturer>\n");
|
2016-09-01 20:38:41 -07:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sw.Write(state);
|
2016-09-18 13:03:51 -07:00
|
|
|
|
sw.Flush();
|
2016-09-01 20:38:41 -07:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.Error(ex.ToString());
|
|
|
|
|
|
return depth;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return depth;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Write out Game start using the supplied StreamWriter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="sw">StreamWriter to output to</param>
|
2016-09-09 15:54:10 -07:00
|
|
|
|
/// <param name="outputFormat">Output format to write to</param>
|
2016-09-01 20:38:41 -07:00
|
|
|
|
/// <param name="rom">RomData object to be output</param>
|
|
|
|
|
|
/// <param name="splitpath">Split path representing last kwown parent game (SabreDAT only)</param>
|
|
|
|
|
|
/// <param name="newsplit">Split path representing the parent game (SabreDAT only)</param>
|
|
|
|
|
|
/// <param name="lastgame">The name of the last game to be output</param>
|
|
|
|
|
|
/// <param name="depth">Current depth to output file at (SabreDAT only)</param>
|
|
|
|
|
|
/// <param name="last">Last known depth to cycle back from (SabreDAT only)</param>
|
|
|
|
|
|
/// <param name="logger">Logger object for file and console output</param>
|
|
|
|
|
|
/// <returns>The new depth of the tag</returns>
|
2016-09-09 15:54:10 -07:00
|
|
|
|
public static int WriteEndGame(StreamWriter sw, OutputFormat outputFormat, Rom rom, List<string> splitpath, List<string> newsplit, string lastgame, int depth, out int last, Logger logger)
|
2016-09-01 20:38:41 -07:00
|
|
|
|
{
|
|
|
|
|
|
last = 0;
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
string state = "";
|
|
|
|
|
|
|
2016-09-09 15:54:10 -07:00
|
|
|
|
switch (outputFormat)
|
2016-09-01 20:38:41 -07:00
|
|
|
|
{
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.ClrMamePro:
|
2016-09-12 23:04:28 -07:00
|
|
|
|
state += (String.IsNullOrEmpty(rom.Machine.SampleOf) ? "" : "\tsampleof \"" + rom.Machine.SampleOf + "\"\n") + ")\n";
|
2016-09-01 20:38:41 -07:00
|
|
|
|
break;
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.SabreDat:
|
2016-09-01 20:38:41 -07:00
|
|
|
|
if (splitpath != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = 0; i < newsplit.Count && i < splitpath.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Always keep track of the last seen item
|
|
|
|
|
|
last = i;
|
|
|
|
|
|
|
|
|
|
|
|
// If we find a difference, break
|
|
|
|
|
|
if (newsplit[i] != splitpath[i])
|
|
|
|
|
|
{
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Now that we have the last known position, take down all open folders
|
|
|
|
|
|
for (int i = depth - 1; i > last + 1; i--)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Print out the number of tabs and the end folder
|
|
|
|
|
|
for (int j = 0; j < i; j++)
|
|
|
|
|
|
{
|
|
|
|
|
|
state += "\t";
|
|
|
|
|
|
}
|
|
|
|
|
|
state += "</directory>\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Reset the current depth
|
|
|
|
|
|
depth = 2 + last;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.Xml:
|
2016-09-01 20:38:41 -07:00
|
|
|
|
state += "\t</machine>\n";
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sw.Write(state);
|
2016-09-18 13:03:51 -07:00
|
|
|
|
sw.Flush();
|
2016-09-01 20:38:41 -07:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.Error(ex.ToString());
|
|
|
|
|
|
return depth;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return depth;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Write out RomData using the supplied StreamWriter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="sw">StreamWriter to output to</param>
|
2016-09-09 15:54:10 -07:00
|
|
|
|
/// <param name="outputFormat">Output format to write to</param>
|
2016-09-01 20:38:41 -07:00
|
|
|
|
/// <param name="rom">RomData object to be output</param>
|
|
|
|
|
|
/// <param name="lastgame">The name of the last game to be output</param>
|
|
|
|
|
|
/// <param name="datdata">DatData object representing DAT information</param>
|
|
|
|
|
|
/// <param name="depth">Current depth to output file at (SabreDAT only)</param>
|
|
|
|
|
|
/// <param name="logger">Logger object for file and console output</param>
|
|
|
|
|
|
/// <param name="ignoreblanks">True if blank roms should be skipped on output, false otherwise (default)</param>
|
|
|
|
|
|
/// <returns>True if the data was written, false on error</returns>
|
2016-09-09 15:54:10 -07:00
|
|
|
|
public static bool WriteRomData(StreamWriter sw, OutputFormat outputFormat, Rom rom, string lastgame, Dat datdata, int depth, Logger logger, bool ignoreblanks = false)
|
2016-09-01 20:38:41 -07:00
|
|
|
|
{
|
|
|
|
|
|
// If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
|
|
|
|
|
|
if (ignoreblanks && (rom.HashData.Size == 0 || rom.HashData.Size == -1))
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
string state = "";
|
2016-09-09 15:54:10 -07:00
|
|
|
|
switch (outputFormat)
|
2016-09-01 20:38:41 -07:00
|
|
|
|
{
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.ClrMamePro:
|
2016-09-01 20:38:41 -07:00
|
|
|
|
state += "\t" + rom.Type.ToString().ToLowerInvariant() + " ( name \"" + rom.Name + "\"" +
|
|
|
|
|
|
(rom.HashData.Size != -1 ? " size " + rom.HashData.Size : "") +
|
|
|
|
|
|
(!String.IsNullOrEmpty(rom.HashData.CRC) ? " crc " + rom.HashData.CRC.ToLowerInvariant() : "") +
|
|
|
|
|
|
(!String.IsNullOrEmpty(rom.HashData.MD5) ? " md5 " + rom.HashData.MD5.ToLowerInvariant() : "") +
|
|
|
|
|
|
(!String.IsNullOrEmpty(rom.HashData.SHA1) ? " sha1 " + rom.HashData.SHA1.ToLowerInvariant() : "") +
|
|
|
|
|
|
(!String.IsNullOrEmpty(rom.Date) ? " date \"" + rom.Date + "\"" : "") +
|
|
|
|
|
|
(rom.Nodump ? " flags nodump" : "") +
|
|
|
|
|
|
" )\n";
|
|
|
|
|
|
break;
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.MissFile:
|
2016-09-01 20:38:41 -07:00
|
|
|
|
string pre = datdata.Prefix + (datdata.Quotes ? "\"" : "");
|
|
|
|
|
|
string post = (datdata.Quotes ? "\"" : "") + datdata.Postfix;
|
|
|
|
|
|
|
|
|
|
|
|
// Check for special strings in prefix and postfix
|
2016-09-12 14:52:46 -07:00
|
|
|
|
pre = pre
|
|
|
|
|
|
.Replace("%game%", rom.Machine.Name)
|
|
|
|
|
|
.Replace("%name%", rom.Name)
|
|
|
|
|
|
.Replace("%crc%", rom.HashData.CRC)
|
|
|
|
|
|
.Replace("%md5%", rom.HashData.MD5)
|
|
|
|
|
|
.Replace("%sha1%", rom.HashData.SHA1)
|
|
|
|
|
|
.Replace("%size%", rom.HashData.Size.ToString());
|
|
|
|
|
|
post = post
|
|
|
|
|
|
.Replace("%game%", rom.Machine.Name)
|
|
|
|
|
|
.Replace("%name%", rom.Name)
|
|
|
|
|
|
.Replace("%crc%", rom.HashData.CRC)
|
|
|
|
|
|
.Replace("%md5%", rom.HashData.MD5)
|
|
|
|
|
|
.Replace("%sha1%", rom.HashData.SHA1)
|
|
|
|
|
|
.Replace("%size%", rom.HashData.Size.ToString());
|
2016-09-01 20:38:41 -07:00
|
|
|
|
|
|
|
|
|
|
// If we're in Romba mode, the state is consistent
|
|
|
|
|
|
if (datdata.Romba)
|
|
|
|
|
|
{
|
|
|
|
|
|
// We can only write out if there's a SHA-1
|
|
|
|
|
|
if (rom.HashData.SHA1 != "")
|
|
|
|
|
|
{
|
|
|
|
|
|
string name = rom.HashData.SHA1.Substring(0, 2) + "/" + rom.HashData.SHA1.Substring(2, 2) + "/" + rom.HashData.SHA1.Substring(4, 2) + "/" +
|
|
|
|
|
|
rom.HashData.SHA1.Substring(6, 2) + "/" + rom.HashData.SHA1 + ".gz";
|
|
|
|
|
|
state += pre + name + post + "\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// If we're in TSV mode, similarly the state is consistent
|
|
|
|
|
|
else if (datdata.XSV == true)
|
|
|
|
|
|
{
|
|
|
|
|
|
string inline = "\"" + datdata.FileName + "\"\t\"" + datdata.Name + "\"\t\"" + datdata.Description + "\"\t\"" + rom.Machine + "\"\t\"" + rom.Machine + "\"\t\"" +
|
|
|
|
|
|
rom.Type.ToString().ToLowerInvariant() + "\"\t\"" + (rom.Type == ItemType.Rom ? rom.Name : "") + "\"\t\"" + (rom.Type == ItemType.Disk ? rom.Name : "") + "\"\t\"" + rom.HashData.Size + "\"\t\"" +
|
|
|
|
|
|
rom.HashData.CRC + "\"\t\"" + rom.HashData.MD5 + "\"\t\"" + rom.HashData.SHA1 + "\"\t" + (rom.Nodump ? "\"Nodump\"" : "\"\"");
|
|
|
|
|
|
state += pre + inline + post + "\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
// If we're in CSV mode, similarly the state is consistent
|
|
|
|
|
|
else if (datdata.XSV == false)
|
|
|
|
|
|
{
|
|
|
|
|
|
string inline = "\"" + datdata.FileName + "\",\"" + datdata.Name + "\",\"" + datdata.Description + "\",\"" + rom.Machine + "\",\"" + rom.Machine + "\",\"" +
|
|
|
|
|
|
rom.Type.ToString().ToLowerInvariant() + "\",\"" + (rom.Type == ItemType.Rom ? rom.Name : "") + "\",\"" + (rom.Type == ItemType.Disk ? rom.Name : "") + "\",\"" + rom.HashData.Size + "\",\"" +
|
|
|
|
|
|
rom.HashData.CRC + "\",\"" + rom.HashData.MD5 + "\",\"" + rom.HashData.SHA1 + "\"," + (rom.Nodump ? "\"Nodump\"" : "\"\"");
|
|
|
|
|
|
state += pre + inline + post + "\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
// Otherwise, use any flags
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
string name = (datdata.UseGame ? rom.Machine.Name : rom.Name);
|
2016-09-12 14:52:46 -07:00
|
|
|
|
if (datdata.RepExt != "" || datdata.RemExt)
|
2016-09-01 20:38:41 -07:00
|
|
|
|
{
|
2016-09-12 14:52:46 -07:00
|
|
|
|
if (datdata.RemExt)
|
|
|
|
|
|
{
|
|
|
|
|
|
datdata.RepExt = "";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-01 20:38:41 -07:00
|
|
|
|
string dir = Path.GetDirectoryName(name);
|
|
|
|
|
|
dir = (dir.StartsWith(Path.DirectorySeparatorChar.ToString()) ? dir.Remove(0, 1) : dir);
|
|
|
|
|
|
name = Path.Combine(dir, Path.GetFileNameWithoutExtension(name) + datdata.RepExt);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (datdata.AddExt != "")
|
|
|
|
|
|
{
|
|
|
|
|
|
name += datdata.AddExt;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!datdata.UseGame && datdata.GameName)
|
|
|
|
|
|
{
|
|
|
|
|
|
name = Path.Combine(rom.Machine.Name, name);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (datdata.UseGame && rom.Machine.Name != lastgame)
|
|
|
|
|
|
{
|
|
|
|
|
|
state += pre + name + post + "\n";
|
|
|
|
|
|
lastgame = rom.Machine.Name;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (!datdata.UseGame)
|
|
|
|
|
|
{
|
|
|
|
|
|
state += pre + name + post + "\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.RedumpMD5:
|
2016-09-09 14:06:47 -07:00
|
|
|
|
state += rom.HashData.MD5 + " *" + rom.Name + "\n";
|
|
|
|
|
|
break;
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.RedumpSFV:
|
2016-09-09 14:06:47 -07:00
|
|
|
|
state += rom.Name + " " + rom.HashData.CRC + "\n";
|
|
|
|
|
|
break;
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.RedumpSHA1:
|
2016-09-09 14:06:47 -07:00
|
|
|
|
state += rom.HashData.SHA1 + " *" + rom.Name + "\n";
|
|
|
|
|
|
break;
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.RomCenter:
|
2016-09-13 10:48:45 -07:00
|
|
|
|
state += "¬" + (String.IsNullOrEmpty(rom.Machine.CloneOf) ? "" : HttpUtility.HtmlEncode(rom.Machine.CloneOf)) +
|
|
|
|
|
|
"¬" + (String.IsNullOrEmpty(rom.Machine.CloneOf) ? "" : HttpUtility.HtmlEncode(rom.Machine.CloneOf)) +
|
|
|
|
|
|
"¬" + HttpUtility.HtmlEncode(rom.Machine.Name) +
|
2016-09-01 20:38:41 -07:00
|
|
|
|
"¬" + HttpUtility.HtmlEncode((String.IsNullOrEmpty(rom.Machine.Description) ? rom.Machine.Name : rom.Machine.Description)) +
|
|
|
|
|
|
"¬" + HttpUtility.HtmlEncode(rom.Name) +
|
|
|
|
|
|
"¬" + rom.HashData.CRC.ToLowerInvariant() +
|
|
|
|
|
|
"¬" + (rom.HashData.Size != -1 ? rom.HashData.Size.ToString() : "") + "¬¬¬\n";
|
|
|
|
|
|
break;
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.SabreDat:
|
2016-09-01 20:38:41 -07:00
|
|
|
|
string prefix = "";
|
|
|
|
|
|
for (int i = 0; i < depth; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
prefix += "\t";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
state += prefix;
|
|
|
|
|
|
state += "<file type=\"" + rom.Type.ToString().ToLowerInvariant() + "\" name=\"" + HttpUtility.HtmlEncode(rom.Name) + "\"" +
|
|
|
|
|
|
(rom.HashData.Size != -1 ? " size=\"" + rom.HashData.Size + "\"" : "") +
|
|
|
|
|
|
(!String.IsNullOrEmpty(rom.HashData.CRC) ? " crc=\"" + rom.HashData.CRC.ToLowerInvariant() + "\"" : "") +
|
|
|
|
|
|
(!String.IsNullOrEmpty(rom.HashData.MD5) ? " md5=\"" + rom.HashData.MD5.ToLowerInvariant() + "\"" : "") +
|
|
|
|
|
|
(!String.IsNullOrEmpty(rom.HashData.SHA1) ? " sha1=\"" + rom.HashData.SHA1.ToLowerInvariant() + "\"" : "") +
|
|
|
|
|
|
(!String.IsNullOrEmpty(rom.Date) ? " date=\"" + rom.Date + "\"" : "") +
|
|
|
|
|
|
(rom.Nodump ? prefix + "/>\n" + prefix + "\t<flags>\n" +
|
|
|
|
|
|
prefix + "\t\t<flag name=\"status\" value=\"nodump\"/>\n" +
|
|
|
|
|
|
prefix + "\t</flags>\n" +
|
|
|
|
|
|
prefix + "</file>\n" :
|
|
|
|
|
|
"/>\n");
|
|
|
|
|
|
break;
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.Xml:
|
2016-09-01 20:38:41 -07:00
|
|
|
|
state += "\t\t<" + rom.Type.ToString().ToLowerInvariant() + " name=\"" + HttpUtility.HtmlEncode(rom.Name) + "\"" +
|
2016-09-13 11:02:02 -07:00
|
|
|
|
(rom.Type == ItemType.Rom && rom.HashData.Size != -1 ? " size=\"" + rom.HashData.Size + "\"" : "") +
|
2016-09-01 20:38:41 -07:00
|
|
|
|
(!String.IsNullOrEmpty(rom.HashData.CRC) ? " crc=\"" + rom.HashData.CRC.ToLowerInvariant() + "\"" : "") +
|
|
|
|
|
|
(!String.IsNullOrEmpty(rom.HashData.MD5) ? " md5=\"" + rom.HashData.MD5.ToLowerInvariant() + "\"" : "") +
|
|
|
|
|
|
(!String.IsNullOrEmpty(rom.HashData.SHA1) ? " sha1=\"" + rom.HashData.SHA1.ToLowerInvariant() + "\"" : "") +
|
|
|
|
|
|
(!String.IsNullOrEmpty(rom.Date) ? " date=\"" + rom.Date + "\"" : "") +
|
|
|
|
|
|
(rom.Nodump ? " status=\"nodump\"" : "") +
|
|
|
|
|
|
"/>\n";
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sw.Write(state);
|
2016-09-18 13:03:51 -07:00
|
|
|
|
sw.Flush();
|
2016-09-01 20:38:41 -07:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.Error(ex.ToString());
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Write out DAT footer using the supplied StreamWriter
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="sw">StreamWriter to output to</param>
|
|
|
|
|
|
/// <param name="datdata">DatData object representing DAT information</param>
|
|
|
|
|
|
/// <param name="depth">Current depth to output file at (SabreDAT only)</param>
|
|
|
|
|
|
/// <param name="logger">Logger object for file and console output</param>
|
|
|
|
|
|
/// <returns>True if the data was written, false on error</returns>
|
2016-09-09 15:54:10 -07:00
|
|
|
|
public static bool WriteFooter(StreamWriter sw, OutputFormat outputFormat, Dat datdata, int depth, Logger logger)
|
2016-09-01 20:38:41 -07:00
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
string footer = "";
|
|
|
|
|
|
|
|
|
|
|
|
// If we have roms, output the full footer
|
|
|
|
|
|
if (datdata.Files != null && datdata.Files.Count > 0)
|
|
|
|
|
|
{
|
2016-09-09 15:54:10 -07:00
|
|
|
|
switch (outputFormat)
|
2016-09-01 20:38:41 -07:00
|
|
|
|
{
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.ClrMamePro:
|
2016-09-01 20:38:41 -07:00
|
|
|
|
footer = ")";
|
|
|
|
|
|
break;
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.SabreDat:
|
2016-09-01 20:38:41 -07:00
|
|
|
|
for (int i = depth - 1; i >= 2; i--)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Print out the number of tabs and the end folder
|
|
|
|
|
|
for (int j = 0; j < i; j++)
|
|
|
|
|
|
{
|
|
|
|
|
|
footer += "\t";
|
|
|
|
|
|
}
|
|
|
|
|
|
footer += "</directory>\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
footer += "\t</data>\n</datafile>";
|
|
|
|
|
|
break;
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.Xml:
|
2016-09-01 20:38:41 -07:00
|
|
|
|
footer = "\t</machine>\n</datafile>";
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Otherwise, output the abbreviated form
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2016-09-09 15:54:10 -07:00
|
|
|
|
switch (outputFormat)
|
2016-09-01 20:38:41 -07:00
|
|
|
|
{
|
2016-09-09 15:54:10 -07:00
|
|
|
|
case OutputFormat.SabreDat:
|
|
|
|
|
|
case OutputFormat.Xml:
|
2016-09-01 20:38:41 -07:00
|
|
|
|
footer = "</datafile>";
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Write the footer out
|
|
|
|
|
|
sw.Write(footer);
|
2016-09-18 13:03:51 -07:00
|
|
|
|
sw.Flush();
|
2016-09-01 20:38:41 -07:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.Error(ex.ToString());
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
2016-09-06 17:20:16 -07:00
|
|
|
|
|
|
|
|
|
|
#region DAT Splitting
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Split a DAT by input extensions
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="filename">Name of the file to be split</param>
|
2016-09-16 16:35:58 -07:00
|
|
|
|
/// <param name="outDir">Name of the directory to write the DATs out to</param>
|
2016-09-06 17:20:16 -07:00
|
|
|
|
/// <param name="basepath">Parent path for replacement</param>
|
|
|
|
|
|
/// <param name="extA">List of extensions to split on (first DAT)</param>
|
|
|
|
|
|
/// <param name="extB">List of extensions to split on (second DAT)</param>
|
|
|
|
|
|
/// <param name="logger">Logger object for console and file writing</param>
|
|
|
|
|
|
/// <returns>True if split succeeded, false otherwise</returns>
|
2016-09-16 16:35:58 -07:00
|
|
|
|
public static bool SplitByExt(string filename, string outDir, string basepath, List<string> extA, List<string> extB, Logger logger)
|
2016-09-06 17:20:16 -07:00
|
|
|
|
{
|
|
|
|
|
|
// Make sure all of the extensions have a dot at the beginning
|
|
|
|
|
|
List<string> newExtA = new List<string>();
|
|
|
|
|
|
foreach (string s in extA)
|
|
|
|
|
|
{
|
|
|
|
|
|
newExtA.Add((s.StartsWith(".") ? s : "." + s).ToUpperInvariant());
|
|
|
|
|
|
}
|
|
|
|
|
|
string newExtAString = string.Join(",", newExtA);
|
|
|
|
|
|
|
|
|
|
|
|
List<string> newExtB = new List<string>();
|
|
|
|
|
|
foreach (string s in extB)
|
|
|
|
|
|
{
|
|
|
|
|
|
newExtB.Add((s.StartsWith(".") ? s : "." + s).ToUpperInvariant());
|
|
|
|
|
|
}
|
|
|
|
|
|
string newExtBString = string.Join(",", newExtB);
|
|
|
|
|
|
|
2016-09-06 20:57:03 -07:00
|
|
|
|
// Get the file format
|
2016-09-09 15:54:10 -07:00
|
|
|
|
OutputFormat outputFormat = GetOutputFormat(filename, logger);
|
|
|
|
|
|
if (outputFormat == 0)
|
2016-09-06 20:57:03 -07:00
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Get the file data to be split
|
2016-09-06 17:20:16 -07:00
|
|
|
|
Dat datdata = new Dat();
|
2016-09-18 21:05:48 -07:00
|
|
|
|
Parse(filename, 0, 0, ref datdata, logger, softlist:true);
|
2016-09-06 17:20:16 -07:00
|
|
|
|
|
|
|
|
|
|
// Set all of the appropriate outputs for each of the subsets
|
|
|
|
|
|
Dat datdataA = new Dat
|
|
|
|
|
|
{
|
|
|
|
|
|
FileName = datdata.FileName + " (" + newExtAString + ")",
|
|
|
|
|
|
Name = datdata.Name + " (" + newExtAString + ")",
|
|
|
|
|
|
Description = datdata.Description + " (" + newExtAString + ")",
|
|
|
|
|
|
Category = datdata.Category,
|
|
|
|
|
|
Version = datdata.Version,
|
|
|
|
|
|
Date = datdata.Date,
|
|
|
|
|
|
Author = datdata.Author,
|
|
|
|
|
|
Email = datdata.Email,
|
|
|
|
|
|
Homepage = datdata.Homepage,
|
|
|
|
|
|
Url = datdata.Url,
|
|
|
|
|
|
Comment = datdata.Comment,
|
|
|
|
|
|
Files = new Dictionary<string, List<Rom>>(),
|
2016-09-09 15:54:10 -07:00
|
|
|
|
OutputFormat = outputFormat,
|
2016-09-06 17:20:16 -07:00
|
|
|
|
};
|
|
|
|
|
|
Dat datdataB = new Dat
|
|
|
|
|
|
{
|
|
|
|
|
|
FileName = datdata.FileName + " (" + newExtBString + ")",
|
|
|
|
|
|
Name = datdata.Name + " (" + newExtBString + ")",
|
|
|
|
|
|
Description = datdata.Description + " (" + newExtBString + ")",
|
|
|
|
|
|
Category = datdata.Category,
|
|
|
|
|
|
Version = datdata.Version,
|
|
|
|
|
|
Date = datdata.Date,
|
|
|
|
|
|
Author = datdata.Author,
|
|
|
|
|
|
Email = datdata.Email,
|
|
|
|
|
|
Homepage = datdata.Homepage,
|
|
|
|
|
|
Url = datdata.Url,
|
|
|
|
|
|
Comment = datdata.Comment,
|
|
|
|
|
|
Files = new Dictionary<string, List<Rom>>(),
|
2016-09-09 15:54:10 -07:00
|
|
|
|
OutputFormat = outputFormat,
|
2016-09-06 17:20:16 -07:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// If roms is empty, return false
|
|
|
|
|
|
if (datdata.Files.Count == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Now separate the roms accordingly
|
|
|
|
|
|
foreach (string key in datdata.Files.Keys)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (Rom rom in datdata.Files[key])
|
|
|
|
|
|
{
|
|
|
|
|
|
if (newExtA.Contains(Path.GetExtension(rom.Name.ToUpperInvariant())))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (datdataA.Files.ContainsKey(key))
|
|
|
|
|
|
{
|
|
|
|
|
|
datdataA.Files[key].Add(rom);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
List<Rom> temp = new List<Rom>();
|
|
|
|
|
|
temp.Add(rom);
|
|
|
|
|
|
datdataA.Files.Add(key, temp);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (newExtB.Contains(Path.GetExtension(rom.Name.ToUpperInvariant())))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (datdataB.Files.ContainsKey(key))
|
|
|
|
|
|
{
|
|
|
|
|
|
datdataB.Files[key].Add(rom);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
List<Rom> temp = new List<Rom>();
|
|
|
|
|
|
temp.Add(rom);
|
|
|
|
|
|
datdataB.Files.Add(key, temp);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
if (datdataA.Files.ContainsKey(key))
|
|
|
|
|
|
{
|
|
|
|
|
|
datdataA.Files[key].Add(rom);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
List<Rom> temp = new List<Rom>();
|
|
|
|
|
|
temp.Add(rom);
|
|
|
|
|
|
datdataA.Files.Add(key, temp);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (datdataB.Files.ContainsKey(key))
|
|
|
|
|
|
{
|
|
|
|
|
|
datdataB.Files[key].Add(rom);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
List<Rom> temp = new List<Rom>();
|
|
|
|
|
|
temp.Add(rom);
|
|
|
|
|
|
datdataB.Files.Add(key, temp);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Get the output directory
|
2016-09-16 16:35:58 -07:00
|
|
|
|
if (outDir != "")
|
2016-09-06 17:20:16 -07:00
|
|
|
|
{
|
2016-09-16 16:35:58 -07:00
|
|
|
|
outDir = outDir + Path.GetDirectoryName(filename).Remove(0, basepath.Length - 1);
|
2016-09-06 17:20:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2016-09-16 16:35:58 -07:00
|
|
|
|
outDir = Path.GetDirectoryName(filename);
|
2016-09-06 17:20:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Then write out both files
|
2016-09-16 16:35:58 -07:00
|
|
|
|
bool success = WriteDatfile(datdataA, outDir, logger);
|
|
|
|
|
|
success &= WriteDatfile(datdataB, outDir, logger);
|
2016-09-06 17:20:16 -07:00
|
|
|
|
|
|
|
|
|
|
return success;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Split a DAT by best available hashes
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="filename">Name of the file to be split</param>
|
2016-09-16 16:35:58 -07:00
|
|
|
|
/// <param name="outDir">Name of the directory to write the DATs out to</param>
|
2016-09-06 17:20:16 -07:00
|
|
|
|
/// <param name="basepath">Parent path for replacement</param>
|
|
|
|
|
|
/// <param name="logger">Logger object for console and file writing</param>
|
|
|
|
|
|
/// <returns>True if split succeeded, false otherwise</returns>
|
2016-09-16 16:35:58 -07:00
|
|
|
|
public static bool SplitByHash(string filename, string outDir, string basepath, Logger logger)
|
2016-09-06 17:20:16 -07:00
|
|
|
|
{
|
|
|
|
|
|
// Sanitize the basepath to be more predictable
|
|
|
|
|
|
basepath = (basepath.EndsWith(Path.DirectorySeparatorChar.ToString()) ? basepath : basepath + Path.DirectorySeparatorChar);
|
|
|
|
|
|
|
2016-09-06 20:57:03 -07:00
|
|
|
|
// Get the file format
|
2016-09-09 15:54:10 -07:00
|
|
|
|
OutputFormat outputFormat = GetOutputFormat(filename, logger);
|
|
|
|
|
|
if (outputFormat == 0)
|
2016-09-06 20:57:03 -07:00
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-06 17:20:16 -07:00
|
|
|
|
// Get the file data to be split
|
|
|
|
|
|
Dat datdata = new Dat();
|
2016-09-18 21:05:48 -07:00
|
|
|
|
Parse(filename, 0, 0, ref datdata, logger, true, softlist:true);
|
2016-09-06 17:20:16 -07:00
|
|
|
|
|
|
|
|
|
|
// Create each of the respective output DATs
|
|
|
|
|
|
logger.User("Creating and populating new DATs");
|
|
|
|
|
|
Dat nodump = new Dat
|
|
|
|
|
|
{
|
|
|
|
|
|
FileName = datdata.FileName + " (Nodump)",
|
|
|
|
|
|
Name = datdata.Name + " (Nodump)",
|
|
|
|
|
|
Description = datdata.Description + " (Nodump)",
|
|
|
|
|
|
Category = datdata.Category,
|
|
|
|
|
|
Version = datdata.Version,
|
|
|
|
|
|
Date = datdata.Date,
|
|
|
|
|
|
Author = datdata.Author,
|
|
|
|
|
|
Email = datdata.Email,
|
|
|
|
|
|
Homepage = datdata.Homepage,
|
|
|
|
|
|
Url = datdata.Url,
|
|
|
|
|
|
Comment = datdata.Comment,
|
|
|
|
|
|
Header = datdata.Header,
|
|
|
|
|
|
Type = datdata.Type,
|
|
|
|
|
|
ForceMerging = datdata.ForceMerging,
|
|
|
|
|
|
ForceNodump = datdata.ForceNodump,
|
|
|
|
|
|
ForcePacking = datdata.ForcePacking,
|
2016-09-09 15:54:10 -07:00
|
|
|
|
OutputFormat = outputFormat,
|
2016-09-06 17:20:16 -07:00
|
|
|
|
MergeRoms = datdata.MergeRoms,
|
|
|
|
|
|
Files = new Dictionary<string, List<Rom>>(),
|
|
|
|
|
|
};
|
|
|
|
|
|
Dat sha1 = new Dat
|
|
|
|
|
|
{
|
|
|
|
|
|
FileName = datdata.FileName + " (SHA-1)",
|
|
|
|
|
|
Name = datdata.Name + " (SHA-1)",
|
|
|
|
|
|
Description = datdata.Description + " (SHA-1)",
|
|
|
|
|
|
Category = datdata.Category,
|
|
|
|
|
|
Version = datdata.Version,
|
|
|
|
|
|
Date = datdata.Date,
|
|
|
|
|
|
Author = datdata.Author,
|
|
|
|
|
|
Email = datdata.Email,
|
|
|
|
|
|
Homepage = datdata.Homepage,
|
|
|
|
|
|
Url = datdata.Url,
|
|
|
|
|
|
Comment = datdata.Comment,
|
|
|
|
|
|
Header = datdata.Header,
|
|
|
|
|
|
Type = datdata.Type,
|
|
|
|
|
|
ForceMerging = datdata.ForceMerging,
|
|
|
|
|
|
ForceNodump = datdata.ForceNodump,
|
|
|
|
|
|
ForcePacking = datdata.ForcePacking,
|
2016-09-09 15:54:10 -07:00
|
|
|
|
OutputFormat = outputFormat,
|
2016-09-06 17:20:16 -07:00
|
|
|
|
MergeRoms = datdata.MergeRoms,
|
|
|
|
|
|
Files = new Dictionary<string, List<Rom>>(),
|
|
|
|
|
|
};
|
|
|
|
|
|
Dat md5 = new Dat
|
|
|
|
|
|
{
|
|
|
|
|
|
FileName = datdata.FileName + " (MD5)",
|
|
|
|
|
|
Name = datdata.Name + " (MD5)",
|
|
|
|
|
|
Description = datdata.Description + " (MD5)",
|
|
|
|
|
|
Category = datdata.Category,
|
|
|
|
|
|
Version = datdata.Version,
|
|
|
|
|
|
Date = datdata.Date,
|
|
|
|
|
|
Author = datdata.Author,
|
|
|
|
|
|
Email = datdata.Email,
|
|
|
|
|
|
Homepage = datdata.Homepage,
|
|
|
|
|
|
Url = datdata.Url,
|
|
|
|
|
|
Comment = datdata.Comment,
|
|
|
|
|
|
Header = datdata.Header,
|
|
|
|
|
|
Type = datdata.Type,
|
|
|
|
|
|
ForceMerging = datdata.ForceMerging,
|
|
|
|
|
|
ForceNodump = datdata.ForceNodump,
|
|
|
|
|
|
ForcePacking = datdata.ForcePacking,
|
2016-09-09 15:54:10 -07:00
|
|
|
|
OutputFormat = outputFormat,
|
2016-09-06 17:20:16 -07:00
|
|
|
|
MergeRoms = datdata.MergeRoms,
|
|
|
|
|
|
Files = new Dictionary<string, List<Rom>>(),
|
|
|
|
|
|
};
|
|
|
|
|
|
Dat crc = new Dat
|
|
|
|
|
|
{
|
|
|
|
|
|
FileName = datdata.FileName + " (CRC)",
|
|
|
|
|
|
Name = datdata.Name + " (CRC)",
|
|
|
|
|
|
Description = datdata.Description + " (CRC)",
|
|
|
|
|
|
Category = datdata.Category,
|
|
|
|
|
|
Version = datdata.Version,
|
|
|
|
|
|
Date = datdata.Date,
|
|
|
|
|
|
Author = datdata.Author,
|
|
|
|
|
|
Email = datdata.Email,
|
|
|
|
|
|
Homepage = datdata.Homepage,
|
|
|
|
|
|
Url = datdata.Url,
|
|
|
|
|
|
Comment = datdata.Comment,
|
|
|
|
|
|
Header = datdata.Header,
|
|
|
|
|
|
Type = datdata.Type,
|
|
|
|
|
|
ForceMerging = datdata.ForceMerging,
|
|
|
|
|
|
ForceNodump = datdata.ForceNodump,
|
|
|
|
|
|
ForcePacking = datdata.ForcePacking,
|
2016-09-09 15:54:10 -07:00
|
|
|
|
OutputFormat = outputFormat,
|
2016-09-06 17:20:16 -07:00
|
|
|
|
MergeRoms = datdata.MergeRoms,
|
|
|
|
|
|
Files = new Dictionary<string, List<Rom>>(),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Now populate each of the DAT objects in turn
|
|
|
|
|
|
List<string> keys = datdata.Files.Keys.ToList();
|
|
|
|
|
|
foreach (string key in keys)
|
|
|
|
|
|
{
|
|
|
|
|
|
List<Rom> roms = datdata.Files[key];
|
|
|
|
|
|
foreach (Rom rom in roms)
|
|
|
|
|
|
{
|
|
|
|
|
|
// If the file is a nodump
|
|
|
|
|
|
if (rom.Nodump)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (nodump.Files.ContainsKey(key))
|
|
|
|
|
|
{
|
|
|
|
|
|
nodump.Files[key].Add(rom);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
List<Rom> temp = new List<Rom>();
|
|
|
|
|
|
temp.Add(rom);
|
|
|
|
|
|
nodump.Files.Add(key, temp);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// If the file has a SHA-1
|
|
|
|
|
|
else if (rom.HashData.SHA1 != null && rom.HashData.SHA1 != "")
|
|
|
|
|
|
{
|
|
|
|
|
|
if (sha1.Files.ContainsKey(key))
|
|
|
|
|
|
{
|
|
|
|
|
|
sha1.Files[key].Add(rom);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
List<Rom> temp = new List<Rom>();
|
|
|
|
|
|
temp.Add(rom);
|
|
|
|
|
|
sha1.Files.Add(key, temp);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// If the file has no SHA-1 but has an MD5
|
|
|
|
|
|
else if (rom.HashData.MD5 != null && rom.HashData.MD5 != "")
|
|
|
|
|
|
{
|
|
|
|
|
|
if (md5.Files.ContainsKey(key))
|
|
|
|
|
|
{
|
|
|
|
|
|
md5.Files[key].Add(rom);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
List<Rom> temp = new List<Rom>();
|
|
|
|
|
|
temp.Add(rom);
|
|
|
|
|
|
md5.Files.Add(key, temp);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// All other cases
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
if (crc.Files.ContainsKey(key))
|
|
|
|
|
|
{
|
|
|
|
|
|
crc.Files[key].Add(rom);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
List<Rom> temp = new List<Rom>();
|
|
|
|
|
|
temp.Add(rom);
|
|
|
|
|
|
crc.Files.Add(key, temp);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Get the output directory
|
2016-09-16 16:35:58 -07:00
|
|
|
|
if (outDir != "")
|
2016-09-06 17:20:16 -07:00
|
|
|
|
{
|
2016-09-16 16:35:58 -07:00
|
|
|
|
outDir = outDir + Path.GetDirectoryName(filename).Remove(0, basepath.Length - 1);
|
2016-09-06 17:20:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2016-09-16 16:35:58 -07:00
|
|
|
|
outDir = Path.GetDirectoryName(filename);
|
2016-09-06 17:20:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Now, output all of the files to the output directory
|
|
|
|
|
|
logger.User("DAT information created, outputting new files");
|
|
|
|
|
|
bool success = true;
|
|
|
|
|
|
if (nodump.Files.Count > 0)
|
|
|
|
|
|
{
|
2016-09-16 16:35:58 -07:00
|
|
|
|
success &= WriteDatfile(nodump, outDir, logger);
|
2016-09-06 17:20:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
if (sha1.Files.Count > 0)
|
|
|
|
|
|
{
|
2016-09-16 16:35:58 -07:00
|
|
|
|
success &= WriteDatfile(sha1, outDir, logger);
|
2016-09-06 17:20:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
if (md5.Files.Count > 0)
|
|
|
|
|
|
{
|
2016-09-16 16:35:58 -07:00
|
|
|
|
success &= WriteDatfile(md5, outDir, logger);
|
2016-09-06 17:20:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
if (crc.Files.Count > 0)
|
|
|
|
|
|
{
|
2016-09-16 16:35:58 -07:00
|
|
|
|
success &= WriteDatfile(crc, outDir, logger);
|
2016-09-06 17:20:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return success;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Split a DAT by type of Rom
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="filename">Name of the file to be split</param>
|
2016-09-16 16:35:58 -07:00
|
|
|
|
/// <param name="outDir">Name of the directory to write the DATs out to</param>
|
2016-09-06 17:20:16 -07:00
|
|
|
|
/// <param name="basepath">Parent path for replacement</param>
|
|
|
|
|
|
/// <param name="logger">Logger object for console and file writing</param>
|
|
|
|
|
|
/// <returns>True if split succeeded, false otherwise</returns>
|
2016-09-16 16:35:58 -07:00
|
|
|
|
public static bool SplitByType(string filename, string outDir, string basepath, Logger logger)
|
2016-09-06 17:20:16 -07:00
|
|
|
|
{
|
|
|
|
|
|
// Sanitize the basepath to be more predictable
|
|
|
|
|
|
basepath = (basepath.EndsWith(Path.DirectorySeparatorChar.ToString()) ? basepath : basepath + Path.DirectorySeparatorChar);
|
|
|
|
|
|
|
2016-09-06 20:57:03 -07:00
|
|
|
|
// Get the file format
|
2016-09-09 15:54:10 -07:00
|
|
|
|
OutputFormat outputFormat = GetOutputFormat(filename, logger);
|
|
|
|
|
|
if (outputFormat == 0)
|
2016-09-06 20:57:03 -07:00
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-06 17:20:16 -07:00
|
|
|
|
// Get the file data to be split
|
|
|
|
|
|
Dat datdata = new Dat();
|
2016-09-18 21:05:48 -07:00
|
|
|
|
Parse(filename, 0, 0, ref datdata, logger, true, softlist:true);
|
2016-09-06 17:20:16 -07:00
|
|
|
|
|
|
|
|
|
|
// Create each of the respective output DATs
|
|
|
|
|
|
logger.User("Creating and populating new DATs");
|
|
|
|
|
|
Dat romdat = new Dat
|
|
|
|
|
|
{
|
2016-09-06 20:57:03 -07:00
|
|
|
|
FileName = datdata.FileName + " (ROM)",
|
|
|
|
|
|
Name = datdata.Name + " (ROM)",
|
|
|
|
|
|
Description = datdata.Description + " (ROM)",
|
2016-09-06 17:20:16 -07:00
|
|
|
|
Category = datdata.Category,
|
|
|
|
|
|
Version = datdata.Version,
|
|
|
|
|
|
Date = datdata.Date,
|
|
|
|
|
|
Author = datdata.Author,
|
|
|
|
|
|
Email = datdata.Email,
|
|
|
|
|
|
Homepage = datdata.Homepage,
|
|
|
|
|
|
Url = datdata.Url,
|
|
|
|
|
|
Comment = datdata.Comment,
|
|
|
|
|
|
Header = datdata.Header,
|
|
|
|
|
|
Type = datdata.Type,
|
|
|
|
|
|
ForceMerging = datdata.ForceMerging,
|
|
|
|
|
|
ForceNodump = datdata.ForceNodump,
|
|
|
|
|
|
ForcePacking = datdata.ForcePacking,
|
2016-09-09 15:54:10 -07:00
|
|
|
|
OutputFormat = outputFormat,
|
2016-09-06 17:20:16 -07:00
|
|
|
|
MergeRoms = datdata.MergeRoms,
|
|
|
|
|
|
Files = new Dictionary<string, List<Rom>>(),
|
|
|
|
|
|
};
|
|
|
|
|
|
Dat diskdat = new Dat
|
|
|
|
|
|
{
|
|
|
|
|
|
FileName = datdata.FileName + " (Disk)",
|
|
|
|
|
|
Name = datdata.Name + " (Disk)",
|
|
|
|
|
|
Description = datdata.Description + " (Disk)",
|
|
|
|
|
|
Category = datdata.Category,
|
|
|
|
|
|
Version = datdata.Version,
|
|
|
|
|
|
Date = datdata.Date,
|
|
|
|
|
|
Author = datdata.Author,
|
|
|
|
|
|
Email = datdata.Email,
|
|
|
|
|
|
Homepage = datdata.Homepage,
|
|
|
|
|
|
Url = datdata.Url,
|
|
|
|
|
|
Comment = datdata.Comment,
|
|
|
|
|
|
Header = datdata.Header,
|
|
|
|
|
|
Type = datdata.Type,
|
|
|
|
|
|
ForceMerging = datdata.ForceMerging,
|
|
|
|
|
|
ForceNodump = datdata.ForceNodump,
|
|
|
|
|
|
ForcePacking = datdata.ForcePacking,
|
2016-09-09 15:54:10 -07:00
|
|
|
|
OutputFormat = outputFormat,
|
2016-09-06 17:20:16 -07:00
|
|
|
|
MergeRoms = datdata.MergeRoms,
|
|
|
|
|
|
Files = new Dictionary<string, List<Rom>>(),
|
|
|
|
|
|
};
|
2016-09-13 11:02:02 -07:00
|
|
|
|
Dat sampledat = new Dat
|
|
|
|
|
|
{
|
|
|
|
|
|
FileName = datdata.FileName + " (Sample)",
|
|
|
|
|
|
Name = datdata.Name + " (Sample)",
|
|
|
|
|
|
Description = datdata.Description + " (Sample)",
|
|
|
|
|
|
Category = datdata.Category,
|
|
|
|
|
|
Version = datdata.Version,
|
|
|
|
|
|
Date = datdata.Date,
|
|
|
|
|
|
Author = datdata.Author,
|
|
|
|
|
|
Email = datdata.Email,
|
|
|
|
|
|
Homepage = datdata.Homepage,
|
|
|
|
|
|
Url = datdata.Url,
|
|
|
|
|
|
Comment = datdata.Comment,
|
|
|
|
|
|
Header = datdata.Header,
|
|
|
|
|
|
Type = datdata.Type,
|
|
|
|
|
|
ForceMerging = datdata.ForceMerging,
|
|
|
|
|
|
ForceNodump = datdata.ForceNodump,
|
|
|
|
|
|
ForcePacking = datdata.ForcePacking,
|
|
|
|
|
|
OutputFormat = outputFormat,
|
|
|
|
|
|
MergeRoms = datdata.MergeRoms,
|
|
|
|
|
|
Files = new Dictionary<string, List<Rom>>(),
|
|
|
|
|
|
};
|
2016-09-06 17:20:16 -07:00
|
|
|
|
|
|
|
|
|
|
// Now populate each of the DAT objects in turn
|
|
|
|
|
|
List<string> keys = datdata.Files.Keys.ToList();
|
|
|
|
|
|
foreach (string key in keys)
|
|
|
|
|
|
{
|
|
|
|
|
|
List<Rom> roms = datdata.Files[key];
|
|
|
|
|
|
foreach (Rom rom in roms)
|
|
|
|
|
|
{
|
|
|
|
|
|
// If the file is a Rom
|
|
|
|
|
|
if (rom.Type == ItemType.Rom)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (romdat.Files.ContainsKey(key))
|
|
|
|
|
|
{
|
|
|
|
|
|
romdat.Files[key].Add(rom);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
List<Rom> temp = new List<Rom>();
|
|
|
|
|
|
temp.Add(rom);
|
|
|
|
|
|
romdat.Files.Add(key, temp);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// If the file is a Disk
|
|
|
|
|
|
else if (rom.Type == ItemType.Disk)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (diskdat.Files.ContainsKey(key))
|
|
|
|
|
|
{
|
|
|
|
|
|
diskdat.Files[key].Add(rom);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
List<Rom> temp = new List<Rom>();
|
|
|
|
|
|
temp.Add(rom);
|
|
|
|
|
|
diskdat.Files.Add(key, temp);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-09-13 11:02:02 -07:00
|
|
|
|
|
|
|
|
|
|
// If the file is a Sample
|
|
|
|
|
|
else if (rom.Type == ItemType.Sample)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (sampledat.Files.ContainsKey(key))
|
|
|
|
|
|
{
|
|
|
|
|
|
sampledat.Files[key].Add(rom);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
List<Rom> temp = new List<Rom>();
|
|
|
|
|
|
temp.Add(rom);
|
|
|
|
|
|
sampledat.Files.Add(key, temp);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-09-06 17:20:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Get the output directory
|
2016-09-16 16:35:58 -07:00
|
|
|
|
if (outDir != "")
|
2016-09-06 17:20:16 -07:00
|
|
|
|
{
|
2016-09-16 16:35:58 -07:00
|
|
|
|
outDir = outDir + Path.GetDirectoryName(filename).Remove(0, basepath.Length - 1);
|
2016-09-06 17:20:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2016-09-16 16:35:58 -07:00
|
|
|
|
outDir = Path.GetDirectoryName(filename);
|
2016-09-06 17:20:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Now, output all of the files to the output directory
|
|
|
|
|
|
logger.User("DAT information created, outputting new files");
|
|
|
|
|
|
bool success = true;
|
|
|
|
|
|
if (romdat.Files.Count > 0)
|
|
|
|
|
|
{
|
2016-09-16 16:35:58 -07:00
|
|
|
|
success &= WriteDatfile(romdat, outDir, logger);
|
2016-09-06 17:20:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
if (diskdat.Files.Count > 0)
|
|
|
|
|
|
{
|
2016-09-16 16:35:58 -07:00
|
|
|
|
success &= WriteDatfile(diskdat, outDir, logger);
|
2016-09-06 17:20:16 -07:00
|
|
|
|
}
|
2016-09-13 11:02:02 -07:00
|
|
|
|
if (sampledat.Files.Count > 0)
|
|
|
|
|
|
{
|
2016-09-16 16:35:58 -07:00
|
|
|
|
success &= WriteDatfile(sampledat, outDir, logger);
|
2016-09-13 11:02:02 -07:00
|
|
|
|
}
|
2016-09-06 17:20:16 -07:00
|
|
|
|
|
|
|
|
|
|
return success;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
2016-04-19 01:11:23 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|