mirror of
https://github.com/claunia/SabreTools.git
synced 2025-12-16 19:14:27 +00:00
Use centralized DAT parsing and manipulate data after
Though the change doesn't reflect this, RomManipulation is a renamed Sorting with an addtional method, Parse.
This commit is contained in:
@@ -255,8 +255,8 @@ JOIN checksums
|
||||
// If we're in a merged mode, merge and then resort by the correct parameters
|
||||
if (merged)
|
||||
{
|
||||
roms = Sorting.RomMerge(roms, true);
|
||||
Sorting.RomSort(roms, _norename);
|
||||
roms = RomManipulation.Merge(roms, true);
|
||||
RomManipulation.Sort(roms, _norename);
|
||||
}
|
||||
|
||||
// Now check rename within games
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SQLite;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -377,156 +378,24 @@ namespace SabreTools
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to load the current file as XML
|
||||
bool superdat = false;
|
||||
XmlDocument doc = new XmlDocument();
|
||||
try
|
||||
{
|
||||
doc.LoadXml(File.ReadAllText(_filepath));
|
||||
}
|
||||
catch (XmlException)
|
||||
{
|
||||
doc.LoadXml(Converters.RomVaultToXML(File.ReadAllLines(_filepath)).ToString());
|
||||
}
|
||||
// Get all roms that are found in the DAT to see what needs to be added
|
||||
List<RomData> roms = RomManipulation.Parse(_filepath, sysid, srcid, _logger);
|
||||
|
||||
// Experimental looping using only XML parsing
|
||||
XmlNode node = doc.FirstChild;
|
||||
if (node != null && node.Name == "xml")
|
||||
// Sort and loop over all roms, checking for adds
|
||||
RomManipulation.Sort(roms, true);
|
||||
string lastgame = "";
|
||||
long gameid = -1;
|
||||
foreach (RomData rom in roms)
|
||||
{
|
||||
// Skip over everything that's not an element
|
||||
while (node.NodeType != XmlNodeType.Element)
|
||||
// If we have a new game, check for a new ID
|
||||
if (rom.Game != lastgame)
|
||||
{
|
||||
node = node.NextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
// Once we find the main body, enter it
|
||||
if (node != null && (node.Name == "datafile" || node.Name == "softwarelist"))
|
||||
{
|
||||
node = node.FirstChild;
|
||||
}
|
||||
|
||||
// Skip the header if it exists
|
||||
if (node != null && node.Name == "header")
|
||||
{
|
||||
// Check for SuperDAT mode
|
||||
if (node.SelectSingleNode("name").InnerText.Contains(" - SuperDAT"))
|
||||
{
|
||||
superdat = true;
|
||||
gameid = AddGame(sysid, rom.Game, srcid);
|
||||
lastgame = rom.Game;
|
||||
}
|
||||
|
||||
// Skip over anything that's not an element
|
||||
while (node.NodeType != XmlNodeType.Element)
|
||||
{
|
||||
node = node.NextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
while (node != null)
|
||||
{
|
||||
if (node.NodeType == XmlNodeType.Element && (node.Name == "machine" || node.Name == "game" || node.Name == "software"))
|
||||
{
|
||||
long gameid = -1;
|
||||
string tempname = "";
|
||||
if (node.Name == "software")
|
||||
{
|
||||
tempname = node.SelectSingleNode("description").InnerText;
|
||||
}
|
||||
else
|
||||
{
|
||||
// There are rare cases where a malformed XML will not have the required attributes. We can only skip them.
|
||||
if (node.Attributes.Count == 0)
|
||||
{
|
||||
_logger.Error(@"A node with malformed XML has been found!
|
||||
For RV DATs, please make sure that all names and descriptions are quoted.
|
||||
For XML DATs, make sure that the DAT has all required information.");
|
||||
node = node.NextSibling;
|
||||
continue;
|
||||
}
|
||||
tempname = node.Attributes["name"].Value;
|
||||
}
|
||||
|
||||
if (superdat)
|
||||
{
|
||||
tempname = Regex.Match(tempname, @".*?\\(.*)").Groups[1].Value;
|
||||
}
|
||||
|
||||
gameid = AddGame(sysid, tempname, srcid);
|
||||
|
||||
// Get the roms from the machine
|
||||
if (node.HasChildNodes)
|
||||
{
|
||||
// If this node has children, traverse the children
|
||||
foreach (XmlNode child in node.ChildNodes)
|
||||
{
|
||||
// If we find a rom or disk, add it
|
||||
if (child.NodeType == XmlNodeType.Element && (child.Name == "rom" || child.Name == "disk"))
|
||||
{
|
||||
// Take care of hex-sized files
|
||||
long size = -1;
|
||||
if (child.Attributes["size"] != null && child.Attributes["size"].Value.Contains("0x"))
|
||||
{
|
||||
size = Convert.ToInt64(child.Attributes["size"].Value, 16);
|
||||
}
|
||||
else if (child.Attributes["size"] != null)
|
||||
{
|
||||
size = Int64.Parse(child.Attributes["size"].Value);
|
||||
}
|
||||
|
||||
AddRom(
|
||||
child.Name,
|
||||
gameid,
|
||||
child.Attributes["name"].Value,
|
||||
date,
|
||||
size,
|
||||
(child.Attributes["crc"] != null ? child.Attributes["crc"].Value.ToLowerInvariant().Trim() : ""),
|
||||
(child.Attributes["md5"] != null ? child.Attributes["md5"].Value.ToLowerInvariant().Trim() : ""),
|
||||
(child.Attributes["sha1"] != null ? child.Attributes["sha1"].Value.ToLowerInvariant().Trim() : "")
|
||||
);
|
||||
}
|
||||
// If we find the signs of a software list, traverse the children
|
||||
else if (child.NodeType == XmlNodeType.Element && child.Name == "part" && child.HasChildNodes)
|
||||
{
|
||||
foreach (XmlNode part in child.ChildNodes)
|
||||
{
|
||||
// If we find a dataarea, traverse the children
|
||||
if (part.NodeType == XmlNodeType.Element && part.Name == "dataarea")
|
||||
{
|
||||
foreach (XmlNode data in part.ChildNodes)
|
||||
{
|
||||
// If we find a rom or disk, add it
|
||||
if (data.NodeType == XmlNodeType.Element && (data.Name == "rom" || data.Name == "disk") && data.Attributes["name"] != null)
|
||||
{
|
||||
// Take care of hex-sized files
|
||||
long size = -1;
|
||||
if (data.Attributes["size"] != null && data.Attributes["size"].Value.Contains("0x"))
|
||||
{
|
||||
size = Convert.ToInt64(data.Attributes["size"].Value, 16);
|
||||
}
|
||||
else if (data.Attributes["size"] != null)
|
||||
{
|
||||
size = Int64.Parse(data.Attributes["size"].Value);
|
||||
}
|
||||
|
||||
AddRom(
|
||||
data.Name,
|
||||
gameid,
|
||||
data.Attributes["name"].Value,
|
||||
date,
|
||||
size,
|
||||
(data.Attributes["crc"] != null ? data.Attributes["crc"].Value.ToLowerInvariant().Trim() : ""),
|
||||
(data.Attributes["md5"] != null ? data.Attributes["md5"].Value.ToLowerInvariant().Trim() : ""),
|
||||
(data.Attributes["sha1"] != null ? data.Attributes["sha1"].Value.ToLowerInvariant().Trim() : "")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
node = node.NextSibling;
|
||||
// Try to add the rom with the game information
|
||||
AddRom(rom, gameid, date);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -598,28 +467,23 @@ namespace SabreTools
|
||||
/// <summary>
|
||||
/// Add a file to the database if it doesn't already exist
|
||||
/// </summary>
|
||||
/// <param name="romtype">File type (either "rom" or "disk")</param>
|
||||
/// <param name="rom">RomData object representing the rom</param>
|
||||
/// <param name="gameid">ID of the parent game to be mapped to</param>
|
||||
/// <param name="name">File name</param>
|
||||
/// <param name="date">Last updated date</param>
|
||||
/// <param name="size">File size in bytes</param>
|
||||
/// <param name="crc">CRC32 hash of the file</param>
|
||||
/// <param name="md5">MD5 hash of the file</param>
|
||||
/// <param name="sha1">SHA-1 hash of the file</param>
|
||||
/// <returns>True if the file exists or could be added, false on error</returns>
|
||||
private bool AddRom(string romtype, long gameid, string name, string date, long size, string crc, string md5, string sha1)
|
||||
private bool AddRom(RomData rom, long gameid, string date)
|
||||
{
|
||||
// WOD origninally stripped out any subdirs from the imported files, we do the same
|
||||
name = Path.GetFileName(name);
|
||||
rom.Name = Path.GetFileName(rom.Name);
|
||||
|
||||
// Run the name through the filters to make sure that it's correct
|
||||
name = Style.NormalizeChars(name);
|
||||
name = Style.RussianToLatin(name);
|
||||
name = Regex.Replace(name, @"(.*) \.(.*)", "$1.$2");
|
||||
rom.Name = Style.NormalizeChars(rom.Name);
|
||||
rom.Name = Style.RussianToLatin(rom.Name);
|
||||
rom.Name = Regex.Replace(rom.Name, @"(.*) \.(.*)", "$1.$2");
|
||||
|
||||
if (romtype != "rom" && romtype != "disk")
|
||||
if (rom.Type != "rom" && rom.Type != "disk")
|
||||
{
|
||||
romtype = "rom";
|
||||
rom.Type = "rom";
|
||||
}
|
||||
|
||||
// Check to see if this exact file is in the database already
|
||||
@@ -627,13 +491,13 @@ namespace SabreTools
|
||||
SELECT files.id FROM files
|
||||
JOIN checksums
|
||||
ON files.id=checksums.file
|
||||
WHERE files.name='" + name.Replace("'", "''") + @"'
|
||||
AND files.type='" + romtype + @"'
|
||||
WHERE files.name='" + rom.Name.Replace("'", "''") + @"'
|
||||
AND files.type='" + rom.Type + @"'
|
||||
AND files.setid=" + gameid + " " +
|
||||
" AND checksums.size=" + size +
|
||||
" AND checksums.crc='" + crc + "'" +
|
||||
" AND checksums.md5='" + md5 + "'" +
|
||||
" AND checksums.sha1='" + sha1 + "'";
|
||||
" AND checksums.size=" + rom.Size +
|
||||
" AND checksums.crc='" + rom.CRC + "'" +
|
||||
" AND checksums.md5='" + rom.MD5 + "'" +
|
||||
" AND checksums.sha1='" + rom.SHA1 + "'";
|
||||
using (SQLiteConnection dbc = new SQLiteConnection(_connectionString))
|
||||
{
|
||||
dbc.Open();
|
||||
@@ -646,7 +510,7 @@ SELECT files.id FROM files
|
||||
{
|
||||
query = @"
|
||||
INSERT INTO files (setid, name, type, lastupdated)
|
||||
VALUES (" + gameid + ", '" + name.Replace("'", "''") + "', '" + romtype + "', '" + date + "')";
|
||||
VALUES (" + gameid + ", '" + rom.Name.Replace("'", "''") + "', '" + rom.Type + "', '" + date + "')";
|
||||
using (SQLiteCommand slc2 = new SQLiteCommand(query, dbc))
|
||||
{
|
||||
int affected = slc2.ExecuteNonQuery();
|
||||
@@ -662,7 +526,7 @@ INSERT INTO files (setid, name, type, lastupdated)
|
||||
}
|
||||
|
||||
query = @"INSERT INTO checksums (file, size, crc, md5, sha1) VALUES (" +
|
||||
romid + ", " + size + ", '" + crc + "'" + ", '" + md5 + "'" + ", '" + sha1 + "')";
|
||||
romid + ", " + rom.Size + ", '" + rom.CRC + "'" + ", '" + rom.MD5 + "'" + ", '" + rom.SHA1 + "')";
|
||||
using (SQLiteCommand slc3 = new SQLiteCommand(query, dbc))
|
||||
{
|
||||
affected = slc3.ExecuteNonQuery();
|
||||
@@ -671,14 +535,14 @@ INSERT INTO files (setid, name, type, lastupdated)
|
||||
// If the insert of the checksums failed, that's bad
|
||||
if (affected < 1)
|
||||
{
|
||||
_logger.Error("There was an error adding checksums for " + name + " to the database!");
|
||||
_logger.Error("There was an error adding checksums for " + rom.Name + " to the database!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Otherwise, something happened which is bad
|
||||
else
|
||||
{
|
||||
_logger.Error("There was an error adding " + name + " to the database!");
|
||||
_logger.Error("There was an error adding " + rom.Name + " to the database!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,142 +32,47 @@ namespace DatSplit
|
||||
return;
|
||||
}
|
||||
|
||||
Logger logger = new Logger(false, "datsplit.log");
|
||||
logger.Start();
|
||||
|
||||
// Output the title
|
||||
Build.Start("DatSplit");
|
||||
|
||||
// Set needed strings
|
||||
// Set needed variables
|
||||
_filename = args[0];
|
||||
_extA = (args[1].StartsWith(".") ? args[1] : "." + args[1]).ToUpperInvariant();
|
||||
_extB = (args[2].StartsWith(".") ? args[2] : "." + args[2]).ToUpperInvariant();
|
||||
List<RomData> romsA = new List<RomData>();
|
||||
List<RomData> romsB = new List<RomData>();
|
||||
|
||||
// Take the filename, and load it as an XML document
|
||||
XmlDocument doc = new XmlDocument();
|
||||
try
|
||||
{
|
||||
doc.LoadXml(File.ReadAllText(_filename));
|
||||
}
|
||||
catch (XmlException)
|
||||
{
|
||||
doc.LoadXml(Converters.RomVaultToXML(File.ReadAllLines(_filename)).ToString());
|
||||
}
|
||||
// Load the current DAT to be processed
|
||||
List<RomData> roms = RomManipulation.Parse(_filename, 0, 0, logger);
|
||||
|
||||
// We all start the same
|
||||
XmlNode node = doc.FirstChild;
|
||||
if (node != null && node.Name == "xml")
|
||||
// Now separate the roms accordingly
|
||||
foreach (RomData rom in roms)
|
||||
{
|
||||
// Skip over everything that's not an element
|
||||
while (node.NodeType != XmlNodeType.Element)
|
||||
if (rom.Name.ToUpperInvariant().EndsWith(_extA))
|
||||
{
|
||||
node = node.NextSibling;
|
||||
romsA.Add(rom);
|
||||
}
|
||||
}
|
||||
|
||||
XmlDocument outDocA = new XmlDocument();
|
||||
outDocA.AppendChild(outDocA.CreateXmlDeclaration("1.0", Encoding.UTF8.WebName, null));
|
||||
outDocA.AppendChild(outDocA.CreateDocumentType("datafile", "-//Logiqx//DTD ROM Management Datafile//EN", "http://www.logiqx.com/Dats/datafile.dtd", null));
|
||||
XmlNode outA = outDocA.CreateNode(XmlNodeType.Element, node.Name, "");
|
||||
|
||||
XmlDocument outDocB = new XmlDocument();
|
||||
outDocB.AppendChild(outDocB.CreateXmlDeclaration("1.0", Encoding.UTF8.WebName, null));
|
||||
outDocB.AppendChild(outDocB.CreateDocumentType("datafile", "-//Logiqx//DTD ROM Management Datafile//EN", "http://www.logiqx.com/Dats/datafile.dtd", null));
|
||||
XmlNode outB = outDocB.CreateNode(XmlNodeType.Element, node.Name, "");
|
||||
|
||||
// Once we find the main body, enter it
|
||||
if (node != null && node.Name == "datafile")
|
||||
{
|
||||
node = node.FirstChild;
|
||||
}
|
||||
|
||||
// Now here's where it differs from import
|
||||
while (node != null)
|
||||
{
|
||||
// If we're at a game node, add the parent node but not all the internals
|
||||
if (node.NodeType == XmlNodeType.Element && (node.Name == "machine" || node.Name == "game"))
|
||||
else if (rom.Name.ToUpperInvariant().EndsWith(_extB))
|
||||
{
|
||||
bool inA = false;
|
||||
bool inB = false;
|
||||
|
||||
// Get the roms from the machine
|
||||
if (node.HasChildNodes)
|
||||
{
|
||||
// If this node has children, traverse the children
|
||||
foreach (XmlNode child in node.ChildNodes)
|
||||
{
|
||||
// If we find a rom or disk, add it
|
||||
if (child.NodeType == XmlNodeType.Element && (child.Name == "rom" || child.Name == "disk"))
|
||||
{
|
||||
// Take care of hex-sized files
|
||||
long size = -1;
|
||||
if (child.Attributes["size"] != null && child.Attributes["size"].Value.Contains("0x"))
|
||||
{
|
||||
size = Convert.ToInt64(child.Attributes["size"].Value, 16);
|
||||
}
|
||||
else if (child.Attributes["size"] != null)
|
||||
{
|
||||
size = Int64.Parse(child.Attributes["size"].Value);
|
||||
}
|
||||
|
||||
if (child.Attributes["name"].Value.ToUpperInvariant().EndsWith(_extA))
|
||||
{
|
||||
if (!inA)
|
||||
{
|
||||
//XmlNode temp = tempDoc.CreateNode(XmlNodeType.Element, node.Name, "");
|
||||
XmlNode temp = outDocA.ImportNode(node, false);
|
||||
outA.AppendChild(temp);
|
||||
outA = outA.LastChild;
|
||||
inA = true;
|
||||
}
|
||||
outA.AppendChild(outDocA.ImportNode(child, true));
|
||||
}
|
||||
else if (child.Attributes["name"].Value.ToUpperInvariant().EndsWith(_extB))
|
||||
{
|
||||
if (!inB)
|
||||
{
|
||||
//XmlNode temp = tempDoc.CreateNode(XmlNodeType.Element, node.Name, "");
|
||||
XmlNode temp = outDocB.ImportNode(node, false);
|
||||
outB.AppendChild(temp);
|
||||
outB = outB.LastChild;
|
||||
inB = true;
|
||||
}
|
||||
outB.AppendChild(outDocB.ImportNode(child, true));
|
||||
}
|
||||
else
|
||||
{
|
||||
outA.AppendChild(outDocA.ImportNode(child, true));
|
||||
outB.AppendChild(outDocB.ImportNode(child, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the output node to the right one for both
|
||||
if (inA)
|
||||
{
|
||||
outA = outA.ParentNode;
|
||||
}
|
||||
if (inB)
|
||||
{
|
||||
outB = outB.ParentNode;
|
||||
}
|
||||
}
|
||||
romsB.Add(rom);
|
||||
}
|
||||
else
|
||||
{
|
||||
XmlNode tempNode = outDocA.ImportNode(node, true);
|
||||
outA.AppendChild(tempNode);
|
||||
tempNode = outDocB.ImportNode(node, true);
|
||||
outB.AppendChild(tempNode);
|
||||
romsA.Add(rom);
|
||||
romsB.Add(rom);
|
||||
}
|
||||
node = node.NextSibling;
|
||||
}
|
||||
|
||||
// Append the built nodes to the documents
|
||||
outDocA.AppendChild(outDocA.ImportNode(outA, true));
|
||||
string outPathA = Path.GetFileNameWithoutExtension(_filename) + _extA + Path.GetExtension(_filename);
|
||||
File.WriteAllText(outPathA, Style.Beautify(outDocA), Encoding.UTF8);
|
||||
// Then write out both files
|
||||
Output.WriteToDat(Path.GetFileNameWithoutExtension(_filename) + "." + _extA, Path.GetFileNameWithoutExtension(_filename) + "." + _extA,
|
||||
"", "", "", "", false, Path.GetExtension(_filename) == ".dat", "", romsA, logger);
|
||||
Output.WriteToDat(Path.GetFileNameWithoutExtension(_filename) + "." + _extB, Path.GetFileNameWithoutExtension(_filename) + "." + _extB,
|
||||
"", "", "", "", false, Path.GetExtension(_filename) == ".dat", "", romsB, logger);
|
||||
|
||||
outDocB.AppendChild(outDocB.ImportNode(outB, true));
|
||||
string outPathB = Path.GetFileNameWithoutExtension(_filename) + _extB + Path.GetExtension(_filename);
|
||||
File.WriteAllText(outPathB, Style.Beautify(outDocB), Encoding.UTF8);
|
||||
logger.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
288
SabreHelper/RomManipulation.cs
Normal file
288
SabreHelper/RomManipulation.cs
Normal file
@@ -0,0 +1,288 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
|
||||
namespace SabreTools.Helper
|
||||
{
|
||||
public class RomManipulation
|
||||
{
|
||||
/// <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>();
|
||||
|
||||
bool superdat = false;
|
||||
XmlDocument doc = new XmlDocument();
|
||||
try
|
||||
{
|
||||
doc.LoadXml(File.ReadAllText(filename));
|
||||
}
|
||||
catch (XmlException)
|
||||
{
|
||||
doc.LoadXml(Converters.RomVaultToXML(File.ReadAllLines(filename)).ToString());
|
||||
}
|
||||
|
||||
// Experimental looping using only XML parsing
|
||||
XmlNode node = doc.FirstChild;
|
||||
if (node != null && node.Name == "xml")
|
||||
{
|
||||
// Skip over everything that's not an element
|
||||
while (node.NodeType != XmlNodeType.Element)
|
||||
{
|
||||
node = node.NextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
// Once we find the main body, enter it
|
||||
if (node != null && (node.Name == "datafile" || node.Name == "softwarelist"))
|
||||
{
|
||||
node = node.FirstChild;
|
||||
}
|
||||
|
||||
// Skip the header if it exists
|
||||
if (node != null && node.Name == "header")
|
||||
{
|
||||
// Check for SuperDAT mode
|
||||
if (node.SelectSingleNode("name").InnerText.Contains(" - SuperDAT"))
|
||||
{
|
||||
superdat = true;
|
||||
}
|
||||
|
||||
// Skip over anything that's not an element
|
||||
while (node.NodeType != XmlNodeType.Element)
|
||||
{
|
||||
node = node.NextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
// Loop over the document until the end
|
||||
while (node != null)
|
||||
{
|
||||
if (node.NodeType == XmlNodeType.Element && (node.Name == "machine" || node.Name == "game" || node.Name == "software"))
|
||||
{
|
||||
string tempname = "";
|
||||
if (node.Name == "software")
|
||||
{
|
||||
tempname = node.SelectSingleNode("description").InnerText;
|
||||
}
|
||||
else
|
||||
{
|
||||
// There are rare cases where a malformed XML will not have the required attributes. We can only skip them.
|
||||
if (node.Attributes.Count == 0)
|
||||
{
|
||||
logger.Error(@"A node with malformed XML has been found!
|
||||
For RV DATs, please make sure that all names and descriptions are quoted.
|
||||
For XML DATs, make sure that the DAT has all required information.");
|
||||
node = node.NextSibling;
|
||||
continue;
|
||||
}
|
||||
tempname = node.Attributes["name"].Value;
|
||||
}
|
||||
|
||||
if (superdat)
|
||||
{
|
||||
tempname = Regex.Match(tempname, @".*?\\(.*)").Groups[1].Value;
|
||||
}
|
||||
|
||||
// Get the roms from the machine
|
||||
if (node.HasChildNodes)
|
||||
{
|
||||
// If this node has children, traverse the children
|
||||
foreach (XmlNode child in node.ChildNodes)
|
||||
{
|
||||
// If we find a rom or disk, add it
|
||||
if (child.NodeType == XmlNodeType.Element && (child.Name == "rom" || child.Name == "disk"))
|
||||
{
|
||||
// Take care of hex-sized files
|
||||
long size = -1;
|
||||
if (child.Attributes["size"] != null && child.Attributes["size"].Value.Contains("0x"))
|
||||
{
|
||||
size = Convert.ToInt64(child.Attributes["size"].Value, 16);
|
||||
}
|
||||
else if (child.Attributes["size"] != null)
|
||||
{
|
||||
size = Int64.Parse(child.Attributes["size"].Value);
|
||||
}
|
||||
|
||||
roms.Add(new RomData
|
||||
{
|
||||
Game = tempname,
|
||||
Name = child.Attributes["name"].Value,
|
||||
Type = child.Name,
|
||||
SystemID = sysid,
|
||||
SourceID = srcid,
|
||||
Size = size,
|
||||
CRC = (child.Attributes["crc"] != null ? child.Attributes["crc"].Value.ToLowerInvariant().Trim() : ""),
|
||||
MD5 = (child.Attributes["md5"] != null ? child.Attributes["md5"].Value.ToLowerInvariant().Trim() : ""),
|
||||
SHA1 = (child.Attributes["sha1"] != null ? child.Attributes["sha1"].Value.ToLowerInvariant().Trim() : ""),
|
||||
});
|
||||
}
|
||||
// If we find the signs of a software list, traverse the children
|
||||
else if (child.NodeType == XmlNodeType.Element && child.Name == "part" && child.HasChildNodes)
|
||||
{
|
||||
foreach (XmlNode part in child.ChildNodes)
|
||||
{
|
||||
// If we find a dataarea, traverse the children
|
||||
if (part.NodeType == XmlNodeType.Element && part.Name == "dataarea")
|
||||
{
|
||||
foreach (XmlNode data in part.ChildNodes)
|
||||
{
|
||||
// If we find a rom or disk, add it
|
||||
if (data.NodeType == XmlNodeType.Element && (data.Name == "rom" || data.Name == "disk") && data.Attributes["name"] != null)
|
||||
{
|
||||
// Take care of hex-sized files
|
||||
long size = -1;
|
||||
if (data.Attributes["size"] != null && data.Attributes["size"].Value.Contains("0x"))
|
||||
{
|
||||
size = Convert.ToInt64(data.Attributes["size"].Value, 16);
|
||||
}
|
||||
else if (data.Attributes["size"] != null)
|
||||
{
|
||||
size = Int64.Parse(data.Attributes["size"].Value);
|
||||
}
|
||||
|
||||
roms.Add(new RomData
|
||||
{
|
||||
Game = tempname,
|
||||
Name = data.Attributes["name"].Value,
|
||||
Type = data.Name,
|
||||
SystemID = sysid,
|
||||
SourceID = srcid,
|
||||
Size = size,
|
||||
CRC = (data.Attributes["crc"] != null ? data.Attributes["crc"].Value.ToLowerInvariant().Trim() : ""),
|
||||
MD5 = (data.Attributes["md5"] != null ? data.Attributes["md5"].Value.ToLowerInvariant().Trim() : ""),
|
||||
SHA1 = (data.Attributes["sha1"] != null ? data.Attributes["sha1"].Value.ToLowerInvariant().Trim() : ""),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
node = node.NextSibling;
|
||||
}
|
||||
|
||||
return roms;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Merge an arbitrary set of ROMs based on the supplied information
|
||||
/// </summary>
|
||||
/// <param name="inroms">List of RomData objects representing the roms to be merged</param>
|
||||
/// <param name="presorted">True if the list should be considered pre-sorted (default false)</param>
|
||||
/// <returns>A List of RomData objects representing the merged roms</returns>
|
||||
public static List<RomData> Merge(List<RomData> inroms, bool presorted = false)
|
||||
{
|
||||
List<RomData> outroms = new List<RomData>();
|
||||
|
||||
// First sort the roms by size, crc, sysid, srcid, md5, and sha1 (in order), if not sorted already
|
||||
if (!presorted)
|
||||
{
|
||||
inroms.Sort(delegate (RomData x, RomData y)
|
||||
{
|
||||
if (x.Size == y.Size)
|
||||
{
|
||||
if (x.CRC == y.CRC)
|
||||
{
|
||||
if (x.SystemID == y.SystemID)
|
||||
{
|
||||
if (x.SourceID == y.SourceID)
|
||||
{
|
||||
if (x.MD5 == y.MD5)
|
||||
{
|
||||
return String.Compare(x.SHA1, y.SHA1);
|
||||
}
|
||||
return String.Compare(x.MD5, y.MD5);
|
||||
}
|
||||
return x.SourceID - y.SourceID;
|
||||
}
|
||||
return x.SystemID - y.SystemID;
|
||||
}
|
||||
return String.Compare(x.CRC, y.CRC);
|
||||
}
|
||||
return (int)(x.Size - y.Size);
|
||||
});
|
||||
}
|
||||
|
||||
// Then, deduplicate them by checking to see if data matches
|
||||
foreach (RomData rom in inroms)
|
||||
{
|
||||
// If it's the first rom in the list, don't touch it
|
||||
if (outroms.Count != 0)
|
||||
{
|
||||
// Check if the rom is a duplicate
|
||||
RomData last = outroms[outroms.Count - 1];
|
||||
|
||||
bool shouldcont = false;
|
||||
if (rom.Type == "rom" && last.Type == "rom")
|
||||
{
|
||||
shouldcont = ((rom.Size != -1 && rom.Size == last.Size) && (
|
||||
(rom.CRC != "" && last.CRC != "" && rom.CRC == last.CRC) ||
|
||||
(rom.MD5 != "" && last.MD5 != "" && rom.MD5 == last.MD5) ||
|
||||
(rom.SHA1 != "" && last.SHA1 != "" && rom.SHA1 == last.SHA1)
|
||||
)
|
||||
);
|
||||
}
|
||||
else if (rom.Type == "disk" && last.Type == "disk")
|
||||
{
|
||||
shouldcont = ((rom.MD5 != "" && last.MD5 != "" && rom.MD5 == last.MD5) ||
|
||||
(rom.SHA1 != "" && last.SHA1 != "" && rom.SHA1 == last.SHA1)
|
||||
);
|
||||
}
|
||||
|
||||
// If it's a duplicate, skip adding it to the output but add any missing information
|
||||
if (shouldcont)
|
||||
{
|
||||
last.CRC = (last.CRC == "" && rom.CRC != "" ? rom.CRC : last.CRC);
|
||||
last.MD5 = (last.MD5 == "" && rom.MD5 != "" ? rom.MD5 : last.MD5);
|
||||
last.SHA1 = (last.SHA1 == "" && rom.SHA1 != "" ? rom.SHA1 : last.SHA1);
|
||||
|
||||
outroms.RemoveAt(inroms.Count - 1);
|
||||
outroms.Insert(inroms.Count, last);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then return the result
|
||||
return outroms;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sort a list of RomData objects by SystemID, SourceID, Game, and Name (in order)
|
||||
/// </summary>
|
||||
/// <param name="roms">List of RomData objects representing the roms to be sorted</param>
|
||||
/// <param name="norename">True if files are not renamed, false otherwise</param>
|
||||
public static void Sort(List<RomData> roms, bool norename)
|
||||
{
|
||||
roms.Sort(delegate (RomData x, RomData y)
|
||||
{
|
||||
if (x.SystemID == y.SystemID)
|
||||
{
|
||||
if (x.SourceID == y.SourceID)
|
||||
{
|
||||
if (x.Game == y.Game)
|
||||
{
|
||||
return String.Compare(x.Name, y.Name);
|
||||
}
|
||||
return String.Compare(x.Game, y.Game);
|
||||
}
|
||||
return (norename ? String.Compare(x.Game, y.Game) : x.SourceID - y.SourceID);
|
||||
}
|
||||
return (norename ? String.Compare(x.Game, y.Game) : x.SystemID - y.SystemID);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,7 @@
|
||||
<Compile Include="Output.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Remapping.cs" />
|
||||
<Compile Include="Sorting.cs" />
|
||||
<Compile Include="RomManipulation.cs" />
|
||||
<Compile Include="Structs.cs" />
|
||||
<Compile Include="Style.cs" />
|
||||
<Compile Include="Build.cs" />
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SabreTools.Helper
|
||||
{
|
||||
public class Sorting
|
||||
{
|
||||
/// <summary>
|
||||
/// Merge an arbitrary set of ROMs based on the supplied information
|
||||
/// </summary>
|
||||
/// <param name="inroms">List of RomData objects representing the roms to be merged</param>
|
||||
/// <param name="presorted">True if the list should be considered pre-sorted (default false)</param>
|
||||
/// <returns>A List of RomData objects representing the merged roms</returns>
|
||||
public static List<RomData> RomMerge(List<RomData> inroms, bool presorted = false)
|
||||
{
|
||||
List<RomData> outroms = new List<RomData>();
|
||||
|
||||
// First sort the roms by size, crc, sysid, srcid, md5, and sha1 (in order), if not sorted already
|
||||
if (!presorted)
|
||||
{
|
||||
inroms.Sort(delegate (RomData x, RomData y)
|
||||
{
|
||||
if (x.Size == y.Size)
|
||||
{
|
||||
if (x.CRC == y.CRC)
|
||||
{
|
||||
if (x.SystemID == y.SystemID)
|
||||
{
|
||||
if (x.SourceID == y.SourceID)
|
||||
{
|
||||
if (x.MD5 == y.MD5)
|
||||
{
|
||||
return String.Compare(x.SHA1, y.SHA1);
|
||||
}
|
||||
return String.Compare(x.MD5, y.MD5);
|
||||
}
|
||||
return x.SourceID - y.SourceID;
|
||||
}
|
||||
return x.SystemID - y.SystemID;
|
||||
}
|
||||
return String.Compare(x.CRC, y.CRC);
|
||||
}
|
||||
return (int)(x.Size - y.Size);
|
||||
});
|
||||
}
|
||||
|
||||
// Then, deduplicate them by checking to see if data matches
|
||||
foreach (RomData rom in inroms)
|
||||
{
|
||||
// If it's the first rom in the list, don't touch it
|
||||
if (outroms.Count != 0)
|
||||
{
|
||||
// Check if the rom is a duplicate
|
||||
RomData last = outroms[outroms.Count - 1];
|
||||
|
||||
bool shouldcont = false;
|
||||
if (rom.Type == "rom" && last.Type == "rom")
|
||||
{
|
||||
shouldcont = ((rom.Size != -1 && rom.Size == last.Size) && (
|
||||
(rom.CRC != "" && last.CRC != "" && rom.CRC == last.CRC) ||
|
||||
(rom.MD5 != "" && last.MD5 != "" && rom.MD5 == last.MD5) ||
|
||||
(rom.SHA1 != "" && last.SHA1 != "" && rom.SHA1 == last.SHA1)
|
||||
)
|
||||
);
|
||||
}
|
||||
else if (rom.Type == "disk" && last.Type == "disk")
|
||||
{
|
||||
shouldcont = ((rom.MD5 != "" && last.MD5 != "" && rom.MD5 == last.MD5) ||
|
||||
(rom.SHA1 != "" && last.SHA1 != "" && rom.SHA1 == last.SHA1)
|
||||
);
|
||||
}
|
||||
|
||||
// If it's a duplicate, skip adding it to the output but add any missing information
|
||||
if (shouldcont)
|
||||
{
|
||||
last.CRC = (last.CRC == "" && rom.CRC != "" ? rom.CRC : last.CRC);
|
||||
last.MD5 = (last.MD5 == "" && rom.MD5 != "" ? rom.MD5 : last.MD5);
|
||||
last.SHA1 = (last.SHA1 == "" && rom.SHA1 != "" ? rom.SHA1 : last.SHA1);
|
||||
|
||||
outroms.RemoveAt(inroms.Count - 1);
|
||||
outroms.Insert(inroms.Count, last);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then return the result
|
||||
return outroms;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sort a list of RomData objects by SystemID, SourceID, Game, and Name (in order)
|
||||
/// </summary>
|
||||
/// <param name="roms">List of RomData objects representing the roms to be sorted</param>
|
||||
/// <param name="norename">True if files are not renamed, false otherwise</param>
|
||||
public static void RomSort(List<RomData> roms, bool norename)
|
||||
{
|
||||
roms.Sort(delegate (RomData x, RomData y)
|
||||
{
|
||||
if (x.SystemID == y.SystemID)
|
||||
{
|
||||
if (x.SourceID == y.SourceID)
|
||||
{
|
||||
if (x.Game == y.Game)
|
||||
{
|
||||
return String.Compare(x.Name, y.Name);
|
||||
}
|
||||
return String.Compare(x.Game, y.Game);
|
||||
}
|
||||
return (norename ? String.Compare(x.Game, y.Game) : x.SourceID - y.SourceID);
|
||||
}
|
||||
return (norename ? String.Compare(x.Game, y.Game) : x.SystemID - y.SystemID);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,9 @@ namespace SabreTools
|
||||
return;
|
||||
}
|
||||
|
||||
Logger logger = new Logger(false, "singlegame.log");
|
||||
logger.Start();
|
||||
|
||||
// Output the title
|
||||
Build.Start("SingleGame");
|
||||
|
||||
@@ -46,122 +49,37 @@ namespace SabreTools
|
||||
|
||||
_path = (_path == "" ? Environment.CurrentDirectory : _path);
|
||||
|
||||
// Take the filename, and load it as an XML document
|
||||
XmlDocument doc = new XmlDocument();
|
||||
try
|
||||
{
|
||||
doc.LoadXml(File.ReadAllText(_filename));
|
||||
}
|
||||
catch (XmlException)
|
||||
{
|
||||
doc.LoadXml(Converters.RomVaultToXML(File.ReadAllLines(_filename)).ToString());
|
||||
}
|
||||
// Import the existing DAT
|
||||
List<RomData> roms = RomManipulation.Parse(_filename, 0, 0, logger);
|
||||
|
||||
// We all start the same
|
||||
XmlNode node = doc.FirstChild;
|
||||
if (node != null && node.Name == "xml")
|
||||
// If we are in single game mode, rename all games
|
||||
if (_rename)
|
||||
{
|
||||
// Skip over everything that's not an element
|
||||
while (node.NodeType != XmlNodeType.Element)
|
||||
roms.ForEach(delegate (RomData x)
|
||||
{
|
||||
node = node.NextSibling;
|
||||
}
|
||||
x.Game = "!";
|
||||
});
|
||||
}
|
||||
|
||||
XmlDocument tempDoc = new XmlDocument();
|
||||
XmlNode outNode = tempDoc.CreateNode(XmlNodeType.Element, node.Name, "");
|
||||
|
||||
// Once we find the main body, enter it
|
||||
if (node != null && node.Name == "datafile")
|
||||
// Trim all file names according to the path that's set
|
||||
roms.ForEach(delegate (RomData x)
|
||||
{
|
||||
node = node.FirstChild;
|
||||
}
|
||||
// Windows max name length is 260
|
||||
int usableLength = 259 - _path.Length;
|
||||
|
||||
// Now here's where it differs from import
|
||||
bool inGame = false;
|
||||
while (node != null)
|
||||
{
|
||||
// If we're at a game node, add the parent node but not all the internals
|
||||
if (_rename && node.NodeType == XmlNodeType.Element && (node.Name == "machine" || node.Name == "game"))
|
||||
if (x.Name.Length > usableLength)
|
||||
{
|
||||
if (!inGame)
|
||||
{
|
||||
XmlElement tempNode = tempDoc.CreateElement(node.Name);
|
||||
tempNode.SetAttribute("name", "!");
|
||||
outNode.AppendChild(tempNode);
|
||||
outNode = outNode.LastChild;
|
||||
inGame = true;
|
||||
}
|
||||
|
||||
// Get the roms from the machine
|
||||
if (node.HasChildNodes)
|
||||
{
|
||||
// If this node has children, traverse the children
|
||||
foreach (XmlNode child in node.ChildNodes)
|
||||
{
|
||||
// If we find a rom or disk, add it
|
||||
if (child.NodeType == XmlNodeType.Element && (child.Name == "rom" || child.Name == "disk"))
|
||||
{
|
||||
// Take care of hex-sized files
|
||||
long size = -1;
|
||||
if (child.Attributes["size"] != null && child.Attributes["size"].Value.Contains("0x"))
|
||||
{
|
||||
size = Convert.ToInt64(child.Attributes["size"].Value, 16);
|
||||
}
|
||||
else if (child.Attributes["size"] != null)
|
||||
{
|
||||
size = Int64.Parse(child.Attributes["size"].Value);
|
||||
}
|
||||
|
||||
XmlElement tempNode = (XmlElement)tempDoc.ImportNode(child, true);
|
||||
|
||||
// Windows max name length is 260
|
||||
string tempname = child.Attributes["name"].Value;
|
||||
int usableLength = 259 - _path.Length;
|
||||
|
||||
if (tempname.Length > usableLength)
|
||||
{
|
||||
string ext = Path.GetExtension(tempname);
|
||||
tempname = tempname.Substring(0, usableLength - ext.Length);
|
||||
tempname += ext;
|
||||
}
|
||||
tempNode.SetAttribute("name", tempname);
|
||||
outNode.AppendChild(tempNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
string ext = Path.GetExtension(x.Name);
|
||||
x.Name = x.Name.Substring(0, usableLength - ext.Length);
|
||||
x.Name += ext;
|
||||
}
|
||||
else
|
||||
{
|
||||
XmlNode tempNode = tempDoc.ImportNode(node, true);
|
||||
});
|
||||
|
||||
if (tempNode.Name == "header")
|
||||
{
|
||||
if (tempNode.SelectSingleNode("clrmamepro") == null)
|
||||
{
|
||||
XmlElement tempChild = tempDoc.CreateElement("clrmamepro");
|
||||
tempChild.SetAttribute("forcepacking", "unzip");
|
||||
tempNode.AppendChild(tempChild);
|
||||
}
|
||||
else
|
||||
{
|
||||
(tempNode.SelectSingleNode("clrmamepro") as XmlElement).SetAttribute("forcepacking", "unzip");
|
||||
}
|
||||
}
|
||||
// Now write the file out accordingly
|
||||
Output.WriteToDat(Path.GetFileNameWithoutExtension(_filename),
|
||||
Path.GetFileNameWithoutExtension(_filename), "", "", "", "", false, Path.GetExtension(_filename) == ".dat", "", roms, logger);
|
||||
|
||||
outNode.AppendChild(tempNode);
|
||||
}
|
||||
node = node.NextSibling;
|
||||
}
|
||||
if (inGame)
|
||||
{
|
||||
outNode = outNode.ParentNode;
|
||||
}
|
||||
|
||||
tempDoc.AppendChild(tempDoc.CreateDocumentType("datafile", "-//Logiqx//DTD ROM Management Datafile//EN", "http://www.logiqx.com/Dats/datafile.dtd", null));
|
||||
tempDoc.AppendChild(outNode);
|
||||
string outPath = Path.GetFileNameWithoutExtension(_filename) + ".new" + Path.GetExtension(_filename);
|
||||
File.WriteAllText(outPath, Style.Beautify(tempDoc));
|
||||
logger.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user