More code cleanup

This change comprises of multiple smaller changes:
- Convert all WriteToDat to WriteToDatFromDict, including MissFile
- Change obsolete Import to use updated ParseDict
- Remove all references to Parse
- Rename all references to "Dict" specific code to shorter names
- Remove more unused methods rendered obsolete by other changes
This commit is contained in:
Matt Nadareski
2016-05-16 21:52:49 -07:00
parent fc67d62fe5
commit e3595ea384
13 changed files with 266 additions and 593 deletions

View File

@@ -10,134 +10,6 @@ namespace SabreTools.Helper
{
public class Output
{
/// <summary>
/// Create and open an output file for writing
/// </summary>
/// <param name="name">Internal name of the DAT</param>
/// <param name="description">Description and external name of the DAT</param>
/// <param name="version">Version or iteration of the DAT</param>
/// <param name="date">Usually the DAT creation date</param>
/// <param name="category">Category of the DAT</param>
/// <param name="author">DAT author</param>
/// <param name="forceunpack">Force all sets to be unzipped</param>
/// <param name="old">Set output mode to old-style DAT</param>
/// <param name="outDir">Set the output directory</param>
/// <param name="roms">List of RomData objects representing the games to be written out</param>
/// <param name="logger">Logger object for console and/or file output</param>
/// <returns>Tru if the DAT was written correctly, false otherwise</returns>
public static bool WriteToDat(string name, string description, string version, string date, string category, string author,
bool forceunpack, bool old, string outDir, List<RomData> roms, Logger logger)
{
// If it's empty, use the current folder
if (outDir.Trim() == "")
{
outDir = Environment.CurrentDirectory;
}
// Double check the outdir for the end delim
if (!outDir.EndsWith(Path.DirectorySeparatorChar.ToString()))
{
outDir += Path.DirectorySeparatorChar;
}
// (currently uses current time, change to "last updated time")
logger.User("Opening file for writing: " + outDir + description + (old ? ".dat" : ".xml"));
try
{
FileStream fs = File.Create(outDir + description + (old ? ".dat" : ".xml"));
StreamWriter sw = new StreamWriter(fs, Encoding.UTF8);
string header_old = "clrmamepro (\n" +
"\tname \"" + HttpUtility.HtmlEncode(name) + "\"\n" +
"\tdescription \"" + HttpUtility.HtmlEncode(description) + "\"\n" +
"\tcategory \"" + HttpUtility.HtmlEncode(category) + "\"\n" +
"\tversion \"" + HttpUtility.HtmlEncode(version) + "\"\n" +
"\tdate \"" + HttpUtility.HtmlEncode(date) + "\"\n" +
"\tauthor \"" + HttpUtility.HtmlEncode(author) + "\"\n" +
(forceunpack ? "\tforcezipping no\n" : "") +
")\n";
string 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(name) + "</name>\n" +
"\t\t<description>" + HttpUtility.HtmlEncode(description) + "</description>\n" +
"\t\t<category>" + HttpUtility.HtmlEncode(category) + "</category>\n" +
"\t\t<version>" + HttpUtility.HtmlEncode(version) + "</version>\n" +
"\t\t<date>" + HttpUtility.HtmlEncode(date) + "</date>\n" +
"\t\t<author>" + HttpUtility.HtmlEncode(author) + "</author>\n" +
(forceunpack ? "\t\t<clrmamepro forcepacking=\"unzip\" />\n" : "") +
"\t</header>\n";
// Write the header out
sw.Write((old ? header_old : header));
// Write out each of the machines and roms
string lastgame = null;
foreach (RomData rom in roms)
{
string state = "";
if (lastgame != null && lastgame != rom.Game)
{
state += (old ? ")\n" : "\t</machine>\n");
}
if (lastgame != rom.Game)
{
state += (old ? "game (\n\tname \"" + rom.Game + "\"\n" +
"\tdescription \"" + rom.Game + "\"\n" :
"\t<machine name=\"" + HttpUtility.HtmlEncode(rom.Game) + "\">\n" +
"\t\t<description>" + HttpUtility.HtmlEncode(rom.Game) + "</description>\n");
}
if (old)
{
state += "\t" + rom.Type + " ( name \"" + rom.Name + "\"" +
(rom.Size != -1 &&
rom.Size != 0 &&
rom.CRC != RomManipulation.CRCZero &&
rom.MD5 != RomManipulation.MD5Zero &&
rom.SHA1 != RomManipulation.SHA1Zero ? " size " + rom.Size : "") +
(rom.CRC != "" ? " crc " + rom.CRC.ToLowerInvariant() : "") +
(rom.MD5 != "" ? " md5 " + rom.MD5.ToLowerInvariant() : "") +
(rom.SHA1 != "" ? " sha1 " + rom.SHA1.ToLowerInvariant() : "") +
" )\n";
}
else
{
state += "\t\t<" + rom.Type + " name=\"" + HttpUtility.HtmlEncode(rom.Name) + "\"" +
(rom.Size != -1 &&
rom.Size != 0 &&
rom.CRC != RomManipulation.CRCZero &&
rom.MD5 != RomManipulation.MD5Zero &&
rom.SHA1 != RomManipulation.SHA1Zero ? " size=\"" + rom.Size + "\"" : "") +
(rom.CRC != "" ? " crc=\"" + rom.CRC.ToLowerInvariant() + "\"" : "") +
(rom.MD5 != "" ? " md5=\"" + rom.MD5.ToLowerInvariant() + "\"" : "") +
(rom.SHA1 != "" ? " sha1=\"" + rom.SHA1.ToLowerInvariant() + "\"" : "") +
"/>\n";
}
lastgame = rom.Game;
sw.Write(state);
}
sw.Write((old ? ")" : "\t</machine>\n</datafile>"));
logger.User("File written!" + Environment.NewLine);
sw.Close();
fs.Close();
}
catch (Exception ex)
{
logger.Error(ex.ToString());
return false;
}
return true;
}
/// <summary>
/// Create and open an output file for writing direct from a dictionary
/// </summary>
@@ -150,8 +22,13 @@ namespace SabreTools.Helper
/// The following features have been requested for file output:
/// - Have the ability to strip special (non-ASCII) characters from rom information
/// - Add a flag for ignoring roms with blank sizes
/// - For OutputFormat.MissFile:
/// + Have switch for automatically outputting to Romba format:
/// e.g. /aa/bb/cc/dd/aabbccddef770b06131a878b46d4302ac28dd126.gz
/// Anything without a SHA-1 has to be skipped
/// </remarks>
public static bool WriteToDatFromDict(DatData datdata, string outDir, Logger logger, bool norename = true)
/// </remarks>
public static bool WriteDatfile(DatData datdata, string outDir, Logger logger, bool norename = true)
{
// Get all values in the dictionary and write out
SortedDictionary<string, List<RomData>> sortable = new SortedDictionary<string, List<RomData>>();
@@ -299,6 +176,36 @@ namespace SabreTools.Helper
(rom.SHA1 != "" ? " sha1 " + rom.SHA1.ToLowerInvariant() : "") +
" )\n";
break;
case OutputFormat.MissFile:
string pre = datdata.Prefix + (datdata.Quotes ? "\"" : "");
string post = (datdata.Quotes ? "\"" : "") + datdata.Postfix;
string name = (datdata.UseGame ? rom.Game : rom.Name);
if (datdata.RepExt != "")
{
string dir = Path.GetDirectoryName(name);
dir = (dir.EndsWith(Path.DirectorySeparatorChar.ToString()) ? dir : dir + Path.DirectorySeparatorChar);
dir = (dir.StartsWith(Path.DirectorySeparatorChar.ToString()) ? dir.Remove(0, 1) : dir);
name = dir + Path.GetFileNameWithoutExtension(name) + datdata.RepExt;
}
if (datdata.AddExt != "")
{
name += datdata.AddExt;
}
if (!datdata.UseGame && datdata.GameName)
{
name = (rom.Game.EndsWith(Path.DirectorySeparatorChar.ToString()) ? rom.Game : rom.Game + Path.DirectorySeparatorChar) + name;
}
if (datdata.UseGame && rom.Game != lastgame)
{
state += pre + name + post + "\n";
lastgame = rom.Game;
}
else if (!datdata.UseGame)
{
state += pre + name + post + "\n";
}
break;
case OutputFormat.RomCenter:
state += "¬¬¬" + HttpUtility.HtmlEncode(rom.Game) +
"¬" + HttpUtility.HtmlEncode(rom.Game) +
@@ -346,185 +253,5 @@ namespace SabreTools.Helper
return true;
}
/// <summary>
/// Output a list of roms as a text file with an arbitrary prefix and postfix
/// </summary>
/// <param name="textfile">Name of the output file</param>
/// <param name="outdir">Output directory for the miss file</param>
/// <param name="roms">List of RomData objects representing the roms to be output</param>
/// <param name="logger">Logger object for console and/or file output</param>
/// <param name="useGame">True if only games are written to text file (default), false for files only</param>
/// <param name="prefix">Arbitrary string to prefix each line</param>
/// <param name="postfix">Arbitrary string to postfix each line</param>
/// <param name="quotes">True if quotes should be put around the item, false otherwise (default)</param>
/// <param name="addext">Arbitrary extension added to the end of each item</param>
/// <param name="repext">Arbitrary extension to replace all extensions in the item</param>
/// <param name="gamename">True if the game name is appended (only when !usegame), false otherwise</param>
/// <returns>True if the file was written, false otherwise</returns>
/// <remarks>
/// The following features have been requested for this method:
/// - Have switch for automatically outputting to Romba format:
/// e.g. /aa/bb/cc/dd/aabbccddef770b06131a878b46d4302ac28dd126.gz
/// Anything without a SHA-1 has to be skipped
/// </remarks>
public static bool WriteToText(string textfile, string outdir, List<RomData> roms, Logger logger, bool useGame = true, string prefix = "",
string postfix = "", string addext = "", string repext = "", bool quotes = false, bool gamename = false)
{
// Normalize the output directory
if (outdir == "")
{
outdir = Environment.CurrentDirectory;
}
if (!outdir.EndsWith(Path.DirectorySeparatorChar.ToString()))
{
outdir += Path.DirectorySeparatorChar;
}
// Make the output directory if it doesn't exist
if (!Directory.Exists(outdir))
{
Directory.CreateDirectory(outdir);
}
// Normalize the extensions
addext = (addext == "" || addext.StartsWith(".") ? addext : "." + addext);
repext = (repext == "" || repext.StartsWith(".") ? repext : "." + repext);
logger.User("Opening file for writing: " + outdir + textfile);
try
{
FileStream fs = File.Create(outdir + textfile);
StreamWriter sw = new StreamWriter(fs, Encoding.UTF8);
string lastgame = "";
foreach (RomData rom in roms)
{
string pre = prefix + (quotes ? "\"" : "");
string post = (quotes ? "\"" : "") + postfix;
string name = (useGame ? rom.Game : rom.Name);
if (repext != "")
{
string dir = Path.GetDirectoryName(name);
dir = (dir.EndsWith(Path.DirectorySeparatorChar.ToString()) ? dir : dir + Path.DirectorySeparatorChar);
dir = (dir.StartsWith(Path.DirectorySeparatorChar.ToString()) ? dir.Remove(0, 1) : dir);
name = dir + Path.GetFileNameWithoutExtension(name) + repext;
}
if (addext != "")
{
name += addext;
}
if (!useGame && gamename)
{
name = (rom.Game.EndsWith(Path.DirectorySeparatorChar.ToString()) ? rom.Game : rom.Game + Path.DirectorySeparatorChar) + name;
}
if (useGame && rom.Game != lastgame)
{
sw.WriteLine(pre + name + post);
lastgame = rom.Game;
}
else if (!useGame)
{
sw.WriteLine(pre + name + post);
}
}
logger.User("File written!" + Environment.NewLine);
sw.Close();
fs.Close();
}
catch (Exception ex)
{
logger.Error(ex.ToString());
return false;
}
return true;
}
/// <summary>
/// Convert a List of RomData objects to a List of tab-deliminated strings
/// </summary>
/// <param name="roms">List of RomData objects representing the roms to be parsed</param>
/// <returns>List of Strings representing the roms</returns>
public static List<String> RomDataToString(List<RomData> roms)
{
List<String> outlist = new List<String>();
foreach (RomData rom in roms)
{
outlist.Add(rom.Manufacturer + "\t" +
rom.System + "\t" +
rom.SystemID + "\t" +
rom.Source + "\t" +
rom.URL + "\t" +
rom.SourceID + "\t" +
rom.Game + "\t" +
rom.Name + "\t" +
rom.Type + "\t" +
rom.Size + "\t" +
rom.CRC + "\t" +
rom.MD5 + "\t" +
rom.SHA1);
}
return outlist;
}
/// <summary>
/// Convert a List of RomData objects' hash information to a List of tab-deliminated strings
/// </summary>
/// <param name="roms">List of RomData objects representing the roms to be parsed</param>
/// <returns>List of Strings representing the rom hashes</returns>
public static List<String> HashDataToString(List<RomData> roms)
{
List<String> outlist = new List<String>();
foreach (RomData rom in roms)
{
outlist.Add(rom.Size + "\t" +
rom.CRC + "\t" +
rom.MD5 + "\t" +
rom.SHA1);
}
return outlist;
}
/// <summary>
/// Convert a List of tab-deliminated strings objects to a List of RomData objects
/// </summary>
/// <param name="roms">List of Strings representing the roms to be parsed</param>
/// <returns>List of RomData objects representing the roms</returns>
public static List<RomData> StringToRomData(List<String> roms)
{
List<RomData> outlist = new List<RomData>();
foreach (String rom in roms)
{
string[] temp = rom.Split('\t');
try
{
outlist.Add(new RomData
{
Manufacturer = temp[0],
System = temp[1],
SystemID = Int32.Parse(temp[2]),
Source = temp[3],
URL = temp[4],
SourceID = Int32.Parse(temp[5]),
Game = temp[6],
Name = temp[7],
Type = temp[8],
Size = Int64.Parse(temp[9]),
CRC = temp[10],
MD5 = temp[11],
SHA1 = temp[12],
});
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
return outlist;
}
}
}

View File

@@ -89,152 +89,6 @@ namespace SabreTools.Helper
return xtr;
}
/// <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="logger">Logger object for console and/or file output</param>
/// <returns>List of RomData objects representing the found data</returns>
public static List<RomData> Parse(string filename, int sysid, int srcid, Logger logger)
{
List<RomData> roms = new List<RomData>();
XmlTextReader xtr = GetXmlTextReader(filename, logger);
bool superdat = false, shouldbreak = false;
string parent = "";
if (xtr != null)
{
xtr.MoveToContent();
while (xtr.NodeType != XmlNodeType.None)
{
// We only want elements
if (xtr.NodeType != XmlNodeType.Element)
{
xtr.Read();
continue;
}
switch (xtr.Name)
{
case "datafile":
case "softwarelist":
parent = xtr.Name;
xtr.Read();
break;
case "header":
xtr.ReadToDescendant("name");
string content = xtr.ReadElementContentAsString();
superdat = (content != null ? content.Contains(" - SuperDAT") : false);
while (xtr.Name != "header")
{
xtr.Read();
}
xtr.Read();
break;
case "machine":
case "game":
case "software":
string temptype = xtr.Name;
string tempname = "";
// We want to process the entire subtree of the game
XmlReader subreader = xtr.ReadSubtree();
if (subreader != null)
{
if (temptype == "software" && subreader.ReadToFollowing("description"))
{
tempname = subreader.ReadElementContentAsString();
}
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");
xtr.ReadToNextSibling(xtr.Name);
continue;
}
tempname = xtr.GetAttribute("name");
}
if (superdat)
{
tempname = Regex.Match(tempname, @".*?\\(.*)").Groups[1].Value;
}
while (subreader.Read())
{
// We only want elements
if (subreader.NodeType != XmlNodeType.Element)
{
continue;
}
// Get the roms from the machine
switch (subreader.Name)
{
case "rom":
case "disk":
// Take care of hex-sized files
long 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);
}
// Take care of hex-prefixed hashes
string crc = (xtr.GetAttribute("crc") != null ? xtr.GetAttribute("crc").ToLowerInvariant().Trim() : "");
crc = (crc.StartsWith("0x") ? crc.Remove(0, 2) : crc);
string md5 = (xtr.GetAttribute("md5") != null ? xtr.GetAttribute("md5").ToLowerInvariant().Trim() : "");
md5 = (md5.StartsWith("0x") ? md5.Remove(0, 2) : md5);
string sha1 = (xtr.GetAttribute("sha1") != null ? xtr.GetAttribute("sha1").ToLowerInvariant().Trim() : "");
sha1 = (sha1.StartsWith("0x") ? sha1.Remove(0, 2) : sha1);
roms.Add(new RomData
{
Game = tempname,
Name = xtr.GetAttribute("name"),
Type = xtr.Name,
SystemID = sysid,
SourceID = srcid,
Size = size,
CRC = crc,
MD5 = md5,
SHA1 = sha1,
});
break;
}
}
}
// Read to next game
if (!xtr.ReadToNextSibling(temptype))
{
shouldbreak = true;
}
break;
default:
xtr.Read();
break;
}
// If we hit an endpoint, break out of the loop early
if (shouldbreak)
{
break;
}
}
}
return roms;
}
/// <summary>
/// Parse a DAT and return all found games and roms within
/// </summary>
@@ -244,7 +98,7 @@ namespace SabreTools.Helper
/// <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>
/// <returns>DatData object representing the read-in data</returns>
public static DatData ParseDict(string filename, int sysid, int srcid, DatData datdata, Logger logger)
public static DatData Parse(string filename, int sysid, int srcid, DatData datdata, Logger logger)
{
XmlTextReader xtr = GetXmlTextReader(filename, logger);
bool superdat = false, shouldbreak = false;
@@ -695,50 +549,5 @@ namespace SabreTools.Helper
});
return true;
}
/// <summary>
/// Get differences between two lists of RomData objects
/// </summary>
/// <param name="A">First RomData list</param>
/// <param name="B">Second RomData list</param>
/// <returns>Any rom that's not in both lists</returns>
/// <remarks>Adapted from http://stackoverflow.com/questions/5620266/the-opposite-of-intersect</remarks>
public static List<RomData> Diff(List<RomData> A, List<RomData> B)
{
List<String> AString = Output.RomDataToString(A);
List<String> BString = Output.RomDataToString(B);
List<String> CString = AString.Except(BString).Union(BString.Except(AString)).ToList();
return Output.StringToRomData(CString);
}
/// <summary>
/// Get all RomData objects that are in A but not in B
/// </summary>
/// <param name="A">First RomData list</param>
/// <param name="B">Second RomData list</param>
/// <returns>Any rom that's only in the first list</returns>
/// <remarks>Adapted from http://stackoverflow.com/questions/5620266/the-opposite-of-intersect</remarks>
public static List<RomData> DiffOnlyInA(List<RomData> A, List<RomData> B)
{
List<String> AString = Output.RomDataToString(A);
List<String> BString = Output.RomDataToString(B);
List<String> CString = AString.Except(BString).ToList();
return Output.StringToRomData(CString);
}
/// <summary>
/// Get all RomData objects that are in A and B
/// </summary>
/// <param name="A">First RomData list</param>
/// <param name="B">Second RomData list</param>
/// <returns>Any rom that's in both lists</returns>
/// <remarks>Adapted from http://stackoverflow.com/questions/5620266/the-opposite-of-intersect</remarks>
public static List<RomData> DiffInAB(List<RomData> A, List<RomData> B)
{
List<String> AString = Output.RomDataToString(A);
List<String> BString = Output.RomDataToString(B);
List<String> CString = AString.Union(BString).Except(AString.Except(BString).Union(BString.Except(AString))).ToList();
return Output.StringToRomData(CString);
}
}
}

View File

@@ -28,6 +28,7 @@ namespace SabreTools.Helper
/// </summary>
public struct DatData
{
// Data common to most DAT types
public string Name;
public string Description;
public string Category;
@@ -45,5 +46,15 @@ namespace SabreTools.Helper
public OutputFormat OutputFormat;
public bool MergeRoms;
public Dictionary<string, List<RomData>> Roms;
// Data specific to the Miss DAT type
public bool UseGame;
public string Prefix;
public string Postfix;
public bool Quotes;
public string RepExt;
public string AddExt;
public bool GameName;
public bool Romba;
}
}