mirror of
https://github.com/claunia/SabreTools.git
synced 2025-12-16 19:14:27 +00:00
[ALL] Move some methods around to make more internal sense
This commit is contained in:
@@ -331,7 +331,7 @@ namespace SabreTools
|
|||||||
header = sldr.GetString(0);
|
header = sldr.GetString(0);
|
||||||
|
|
||||||
_logger.User("Creating reheadered file: " + file + ".new" + sub);
|
_logger.User("Creating reheadered file: " + file + ".new" + sub);
|
||||||
Output.AppendBytesToFile(file, file + ".new" + sub, header, string.Empty);
|
FileTools.AppendBytesToFile(file, file + ".new" + sub, header, string.Empty);
|
||||||
_logger.User("Reheadered file created!");
|
_logger.User("Reheadered file created!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ namespace SabreTools.Helper.Resources {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to This is the default help output.
|
/// Looks up a localized string similar to This is the default help DatTools.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string Default_Desc {
|
public static string Default_Desc {
|
||||||
get {
|
get {
|
||||||
@@ -124,7 +124,7 @@ namespace SabreTools.Helper.Resources {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Convert files to TGZ output.
|
/// Looks up a localized string similar to Convert files to TGZ DatTools.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TGZTest_Desc {
|
public static string TGZTest_Desc {
|
||||||
get {
|
get {
|
||||||
|
|||||||
@@ -114,7 +114,6 @@
|
|||||||
<Compile Include="Interfaces\IGenerate.cs" />
|
<Compile Include="Interfaces\IGenerate.cs" />
|
||||||
<Compile Include="Interfaces\IImport.cs" />
|
<Compile Include="Interfaces\IImport.cs" />
|
||||||
<Compile Include="Logger.cs" />
|
<Compile Include="Logger.cs" />
|
||||||
<Compile Include="Tools\Output.cs" />
|
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Mappings.cs" />
|
<Compile Include="Mappings.cs" />
|
||||||
<Compile Include="Tools\DatTools.cs" />
|
<Compile Include="Tools\DatTools.cs" />
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Web;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
|
||||||
namespace SabreTools.Helper
|
namespace SabreTools.Helper
|
||||||
@@ -1434,7 +1436,7 @@ namespace SabreTools.Helper
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Bucketing methods
|
#region Bucketing
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Take an arbitrarily ordered List and return a Dictionary sorted by Game
|
/// Take an arbitrarily ordered List and return a Dictionary sorted by Game
|
||||||
@@ -1586,7 +1588,7 @@ namespace SabreTools.Helper
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Converting and updating
|
#region Converting and Updating
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert, update, and filter a DAT file
|
/// Convert, update, and filter a DAT file
|
||||||
@@ -1720,7 +1722,7 @@ namespace SabreTools.Helper
|
|||||||
// If we have roms, output them
|
// If we have roms, output them
|
||||||
if (datdata.Files.Count != 0)
|
if (datdata.Files.Count != 0)
|
||||||
{
|
{
|
||||||
Output.WriteDatfile(datdata, (outputDirectory == "" ? Path.GetDirectoryName(inputFileName) : outputDirectory), logger);
|
DatTools.WriteDatfile(datdata, (outputDirectory == "" ? Path.GetDirectoryName(inputFileName) : outputDirectory), logger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Directory.Exists(inputFileName))
|
else if (Directory.Exists(inputFileName))
|
||||||
@@ -1746,7 +1748,7 @@ namespace SabreTools.Helper
|
|||||||
// If we have roms, output them
|
// If we have roms, output them
|
||||||
if (innerDatdata.Files.Count != 0)
|
if (innerDatdata.Files.Count != 0)
|
||||||
{
|
{
|
||||||
Output.WriteDatfile(innerDatdata, (outputDirectory == "" ? Path.GetDirectoryName(file) : outputDirectory + Path.GetDirectoryName(file).Remove(0, inputFileName.Length - 1)), logger);
|
DatTools.WriteDatfile(innerDatdata, (outputDirectory == "" ? Path.GetDirectoryName(file) : outputDirectory + Path.GetDirectoryName(file).Remove(0, inputFileName.Length - 1)), logger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2141,13 +2143,13 @@ namespace SabreTools.Helper
|
|||||||
// Output the difflist (a-b)+(b-a) diff
|
// Output the difflist (a-b)+(b-a) diff
|
||||||
if ((diff & DiffMode.NoDupes) != 0)
|
if ((diff & DiffMode.NoDupes) != 0)
|
||||||
{
|
{
|
||||||
Output.WriteDatfile(outerDiffData, outdir, logger);
|
DatTools.WriteDatfile(outerDiffData, outdir, logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output the (ab) diff
|
// Output the (ab) diff
|
||||||
if ((diff & DiffMode.Dupes) != 0)
|
if ((diff & DiffMode.Dupes) != 0)
|
||||||
{
|
{
|
||||||
Output.WriteDatfile(dupeData, outdir, logger);
|
DatTools.WriteDatfile(dupeData, outdir, logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output the individual (a-b) DATs
|
// Output the individual (a-b) DATs
|
||||||
@@ -2161,7 +2163,7 @@ namespace SabreTools.Helper
|
|||||||
// If we have more than 0 roms, output
|
// If we have more than 0 roms, output
|
||||||
if (outDats[j].Files.Count > 0)
|
if (outDats[j].Files.Count > 0)
|
||||||
{
|
{
|
||||||
Output.WriteDatfile(outDats[j], path, logger);
|
DatTools.WriteDatfile(outDats[j], path, logger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2256,7 +2258,7 @@ namespace SabreTools.Helper
|
|||||||
// If we have more than 0 roms, output
|
// If we have more than 0 roms, output
|
||||||
if (outDats[j].Files.Count > 0)
|
if (outDats[j].Files.Count > 0)
|
||||||
{
|
{
|
||||||
Output.WriteDatfile(outDats[j], path, logger);
|
DatTools.WriteDatfile(outDats[j], path, logger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.User("Outputting complete in " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff"));
|
logger.User("Outputting complete in " + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.fffff"));
|
||||||
@@ -2299,10 +2301,627 @@ namespace SabreTools.Helper
|
|||||||
// Output a DAT only if there are roms
|
// Output a DAT only if there are roms
|
||||||
if (userData.Files.Count != 0)
|
if (userData.Files.Count != 0)
|
||||||
{
|
{
|
||||||
Output.WriteDatfile(userData, outdir, logger);
|
DatTools.WriteDatfile(userData, outdir, logger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#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>
|
||||||
|
/// <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>
|
||||||
|
public static bool WriteDatfile(Dat datdata, string outDir, Logger logger, bool norename = true, bool stats = false, bool ignoreblanks = false)
|
||||||
|
{
|
||||||
|
// If the DAT has no output format, default to XML
|
||||||
|
if (datdata.OutputFormat == OutputFormat.None)
|
||||||
|
{
|
||||||
|
datdata.OutputFormat = OutputFormat.Xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output initial statistics, for kicks
|
||||||
|
if (stats)
|
||||||
|
{
|
||||||
|
Stats.OutputStats(datdata, logger, (datdata.RomCount + datdata.DiskCount == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bucket roms by game name and optionally dedupe
|
||||||
|
SortedDictionary<string, List<Rom>> sortable = DatTools.BucketByGame(datdata.Files, datdata.MergeRoms, norename, logger);
|
||||||
|
|
||||||
|
// Now write out to file
|
||||||
|
// If it's empty, use the current folder
|
||||||
|
if (outDir.Trim() == "")
|
||||||
|
{
|
||||||
|
outDir = Environment.CurrentDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the output directory if it doesn't already exist
|
||||||
|
Directory.CreateDirectory(outDir);
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the outfile name
|
||||||
|
string outfile = Style.CreateOutfileName(outDir, datdata);
|
||||||
|
|
||||||
|
logger.User("Opening file for writing: " + outfile);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FileStream fs = File.Create(outfile);
|
||||||
|
StreamWriter sw = new StreamWriter(fs, Encoding.UTF8);
|
||||||
|
|
||||||
|
// Write out the header
|
||||||
|
WriteHeader(sw, datdata, logger);
|
||||||
|
|
||||||
|
// Write out each of the machines and roms
|
||||||
|
int depth = 2, last = -1;
|
||||||
|
string lastgame = null;
|
||||||
|
List<string> splitpath = new List<string>();
|
||||||
|
foreach (List<Rom> roms in sortable.Values)
|
||||||
|
{
|
||||||
|
for (int index = 0; index < roms.Count; index++)
|
||||||
|
{
|
||||||
|
Rom rom = roms[index];
|
||||||
|
List<string> newsplit = rom.Machine.Name.Split('\\').ToList();
|
||||||
|
|
||||||
|
// 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())
|
||||||
|
{
|
||||||
|
depth = WriteEndGame(sw, rom, splitpath, newsplit, lastgame, datdata, depth, out last, logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a new game, output the beginning of the new item
|
||||||
|
if (lastgame == null || lastgame.ToLowerInvariant() != rom.Machine.Name.ToLowerInvariant())
|
||||||
|
{
|
||||||
|
depth = WriteStartGame(sw, rom, newsplit, lastgame, datdata, depth, last, logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a "null" game (created by DATFromDir or something similar), log it to file
|
||||||
|
if (rom.Name == "null" && rom.HashData.Size == -1 && rom.HashData.CRC == "null" && rom.HashData.MD5 == "null" && rom.HashData.SHA1 == "null")
|
||||||
|
{
|
||||||
|
logger.Log("Empty folder found: " + rom.Machine);
|
||||||
|
|
||||||
|
// If we're in a mode that doesn't allow for actual empty folders, add the blank info
|
||||||
|
if (datdata.OutputFormat != OutputFormat.SabreDat && datdata.OutputFormat != OutputFormat.MissFile)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, output the rom data
|
||||||
|
WriteRomData(sw, rom, lastgame, datdata, depth, logger, ignoreblanks);
|
||||||
|
|
||||||
|
// Set the new data to compare against
|
||||||
|
splitpath = newsplit;
|
||||||
|
lastgame = rom.Machine.Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the file footer out
|
||||||
|
WriteFooter(sw, datdata, depth, logger);
|
||||||
|
|
||||||
|
logger.Log("File written!" + Environment.NewLine);
|
||||||
|
sw.Close();
|
||||||
|
fs.Close();
|
||||||
|
}
|
||||||
|
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>
|
||||||
|
/// <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>
|
||||||
|
public static bool WriteHeader(StreamWriter sw, Dat datdata, Logger logger)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string header = "";
|
||||||
|
switch (datdata.OutputFormat)
|
||||||
|
{
|
||||||
|
case OutputFormat.ClrMamePro:
|
||||||
|
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" : "") +
|
||||||
|
")\n";
|
||||||
|
break;
|
||||||
|
case OutputFormat.MissFile:
|
||||||
|
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;
|
||||||
|
case OutputFormat.RomCenter:
|
||||||
|
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;
|
||||||
|
case OutputFormat.SabreDat:
|
||||||
|
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" +
|
||||||
|
"\t\t<rootdir>" + HttpUtility.HtmlEncode(datdata.RootDir) + "</rootdir>\n" +
|
||||||
|
"\t\t<category>" + HttpUtility.HtmlEncode(datdata.Category) + "</category>\n" +
|
||||||
|
"\t\t<version>" + HttpUtility.HtmlEncode(datdata.Version) + "</version>\n" +
|
||||||
|
"\t\t<date>" + HttpUtility.HtmlEncode(datdata.Date) + "</date>\n" +
|
||||||
|
"\t\t<author>" + HttpUtility.HtmlEncode(datdata.Author) + "</author>\n" +
|
||||||
|
"\t\t<comment>" + HttpUtility.HtmlEncode(datdata.Comment) + "</comment>\n" +
|
||||||
|
(!String.IsNullOrEmpty(datdata.Type) && datdata.ForcePacking != ForcePacking.Unzip ?
|
||||||
|
"\t\t<flags>\n" +
|
||||||
|
(!String.IsNullOrEmpty(datdata.Type) ? "\t\t\t<flag name=\"type\" value=\"" + datdata.Type + "\"/>\n" : "") +
|
||||||
|
(datdata.ForcePacking == ForcePacking.Unzip ? "\t\t\t<flag name=\"forcepacking\" value=\"unzip\"/>\n" : "") +
|
||||||
|
"\t\t</flags>\n" : "") +
|
||||||
|
"\t</header>\n" +
|
||||||
|
"\t<data>\n";
|
||||||
|
break;
|
||||||
|
case OutputFormat.Xml:
|
||||||
|
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" +
|
||||||
|
"\t\t<rootdir>" + HttpUtility.HtmlEncode(datdata.RootDir) + "</rootdir>\n" +
|
||||||
|
"\t\t<category>" + HttpUtility.HtmlEncode(datdata.Category) + "</category>\n" +
|
||||||
|
"\t\t<version>" + HttpUtility.HtmlEncode(datdata.Version) + "</version>\n" +
|
||||||
|
"\t\t<date>" + HttpUtility.HtmlEncode(datdata.Date) + "</date>\n" +
|
||||||
|
"\t\t<author>" + HttpUtility.HtmlEncode(datdata.Author) + "</author>\n" +
|
||||||
|
"\t\t<email>" + HttpUtility.HtmlEncode(datdata.Email) + "</email>\n" +
|
||||||
|
"\t\t<homepage>" + HttpUtility.HtmlEncode(datdata.Homepage) + "</homepage>\n" +
|
||||||
|
"\t\t<url>" + HttpUtility.HtmlEncode(datdata.Url) + "</url>\n" +
|
||||||
|
"\t\t<comment>" + HttpUtility.HtmlEncode(datdata.Comment) + "</comment>\n" +
|
||||||
|
(!String.IsNullOrEmpty(datdata.Type) ? "\t\t<type>" + datdata.Type + "</type>\n" : "") +
|
||||||
|
(datdata.ForcePacking == ForcePacking.Unzip ? "\t\t<clrmamepro forcepacking=\"unzip\" />\n" : "") +
|
||||||
|
"\t</header>\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the header out
|
||||||
|
sw.Write(header);
|
||||||
|
}
|
||||||
|
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>
|
||||||
|
/// <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="datdata">DatData object representing DAT information</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>
|
||||||
|
public static int WriteStartGame(StreamWriter sw, Rom rom, List<string> newsplit, string lastgame, Dat datdata, int depth, int last, Logger logger)
|
||||||
|
{
|
||||||
|
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 = "";
|
||||||
|
switch (datdata.OutputFormat)
|
||||||
|
{
|
||||||
|
case OutputFormat.ClrMamePro:
|
||||||
|
state += "game (\n\tname \"" + rom.Machine.Name + "\"\n" +
|
||||||
|
"\tdescription \"" + (String.IsNullOrEmpty(rom.Machine.Description) ? rom.Machine.Name : rom.Machine.Description) + "\"\n";
|
||||||
|
break;
|
||||||
|
case OutputFormat.SabreDat:
|
||||||
|
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;
|
||||||
|
case OutputFormat.Xml:
|
||||||
|
state += "\t<machine name=\"" + HttpUtility.HtmlEncode(rom.Machine.Name) + "\">\n" +
|
||||||
|
"\t\t<description>" + HttpUtility.HtmlEncode((String.IsNullOrEmpty(rom.Machine.Description) ? rom.Machine.Name : rom.Machine.Description)) + "</description>\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sw.Write(state);
|
||||||
|
}
|
||||||
|
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>
|
||||||
|
/// <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="datdata">DatData object representing DAT information</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>
|
||||||
|
public static int WriteEndGame(StreamWriter sw, Rom rom, List<string> splitpath, List<string> newsplit, string lastgame, Dat datdata, int depth, out int last, Logger logger)
|
||||||
|
{
|
||||||
|
last = 0;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string state = "";
|
||||||
|
|
||||||
|
switch (datdata.OutputFormat)
|
||||||
|
{
|
||||||
|
case OutputFormat.ClrMamePro:
|
||||||
|
state += ")\n";
|
||||||
|
break;
|
||||||
|
case OutputFormat.SabreDat:
|
||||||
|
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;
|
||||||
|
case OutputFormat.Xml:
|
||||||
|
state += "\t</machine>\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sw.Write(state);
|
||||||
|
}
|
||||||
|
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>
|
||||||
|
/// <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>
|
||||||
|
public static bool WriteRomData(StreamWriter sw, Rom rom, string lastgame, Dat datdata, int depth, Logger logger, bool ignoreblanks = false)
|
||||||
|
{
|
||||||
|
// 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 = "";
|
||||||
|
switch (datdata.OutputFormat)
|
||||||
|
{
|
||||||
|
case OutputFormat.ClrMamePro:
|
||||||
|
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;
|
||||||
|
case OutputFormat.MissFile:
|
||||||
|
string pre = datdata.Prefix + (datdata.Quotes ? "\"" : "");
|
||||||
|
string post = (datdata.Quotes ? "\"" : "") + datdata.Postfix;
|
||||||
|
|
||||||
|
// Check for special strings in prefix and postfix
|
||||||
|
pre = pre.Replace("%crc%", rom.HashData.CRC).Replace("%md5%", rom.HashData.MD5).Replace("%sha1%", rom.HashData.SHA1).Replace("%size%", rom.HashData.Size.ToString());
|
||||||
|
post = post.Replace("%crc%", rom.HashData.CRC).Replace("%md5%", rom.HashData.MD5).Replace("%sha1%", rom.HashData.SHA1).Replace("%size%", rom.HashData.Size.ToString());
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
if (datdata.RepExt != "")
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
case OutputFormat.RomCenter:
|
||||||
|
state += "¬¬¬" + HttpUtility.HtmlEncode(rom.Machine) +
|
||||||
|
"¬" + 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;
|
||||||
|
case OutputFormat.SabreDat:
|
||||||
|
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;
|
||||||
|
case OutputFormat.Xml:
|
||||||
|
state += "\t\t<" + 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 ? " status=\"nodump\"" : "") +
|
||||||
|
"/>\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sw.Write(state);
|
||||||
|
}
|
||||||
|
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>
|
||||||
|
public static bool WriteFooter(StreamWriter sw, Dat datdata, int depth, Logger logger)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string footer = "";
|
||||||
|
|
||||||
|
// If we have roms, output the full footer
|
||||||
|
if (datdata.Files != null && datdata.Files.Count > 0)
|
||||||
|
{
|
||||||
|
switch (datdata.OutputFormat)
|
||||||
|
{
|
||||||
|
case OutputFormat.ClrMamePro:
|
||||||
|
footer = ")";
|
||||||
|
break;
|
||||||
|
case OutputFormat.SabreDat:
|
||||||
|
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;
|
||||||
|
case OutputFormat.Xml:
|
||||||
|
footer = "\t</machine>\n</datafile>";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, output the abbreviated form
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (datdata.OutputFormat)
|
||||||
|
{
|
||||||
|
case OutputFormat.SabreDat:
|
||||||
|
case OutputFormat.Xml:
|
||||||
|
footer = "</datafile>";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the footer out
|
||||||
|
sw.Write(footer);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.Error(ex.ToString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -575,7 +575,7 @@ namespace SabreTools.Helper
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region File Information Methods
|
#region File Information
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieve file information for a single file
|
/// Retrieve file information for a single file
|
||||||
@@ -938,6 +938,162 @@ namespace SabreTools.Helper
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region File Manipulation
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove an arbitrary number of bytes from the inputted file
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">File to be cropped</param>
|
||||||
|
/// <param name="output">Outputted file</param>
|
||||||
|
/// <param name="bytesToRemoveFromHead">Bytes to be removed from head of file</param>
|
||||||
|
/// <param name="bytesToRemoveFromTail">Bytes to be removed from tail of file</param>
|
||||||
|
public static void RemoveBytesFromFile(string input, string output, long bytesToRemoveFromHead, long bytesToRemoveFromTail)
|
||||||
|
{
|
||||||
|
// If any of the inputs are invalid, skip
|
||||||
|
if (!File.Exists(input) || new FileInfo(input).Length <= (bytesToRemoveFromHead + bytesToRemoveFromTail))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the input file and write to the fail
|
||||||
|
using (BinaryReader br = new BinaryReader(File.OpenRead(input)))
|
||||||
|
using (BinaryWriter bw = new BinaryWriter(File.OpenWrite(output)))
|
||||||
|
{
|
||||||
|
int bufferSize = 1024;
|
||||||
|
long adjustedLength = br.BaseStream.Length - bytesToRemoveFromTail;
|
||||||
|
|
||||||
|
// Seek to the correct position
|
||||||
|
br.BaseStream.Seek((bytesToRemoveFromHead < 0 ? 0 : bytesToRemoveFromHead), SeekOrigin.Begin);
|
||||||
|
|
||||||
|
// Now read the file in chunks and write out
|
||||||
|
byte[] buffer = new byte[bufferSize];
|
||||||
|
while (br.BaseStream.Position <= (adjustedLength - bufferSize))
|
||||||
|
{
|
||||||
|
buffer = br.ReadBytes(bufferSize);
|
||||||
|
bw.Write(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For the final chunk, if any, write out only that number of bytes
|
||||||
|
int length = (int)(adjustedLength - br.BaseStream.Position);
|
||||||
|
buffer = new byte[length];
|
||||||
|
buffer = br.ReadBytes(length);
|
||||||
|
bw.Write(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add an aribtrary number of bytes to the inputted file
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">File to be appended to</param>
|
||||||
|
/// <param name="output">Outputted file</param>
|
||||||
|
/// <param name="bytesToAddToHead">String representing bytes to be added to head of file</param>
|
||||||
|
/// <param name="bytesToAddToTail">String representing bytes to be added to tail of file</param>
|
||||||
|
public static void AppendBytesToFile(string input, string output, string bytesToAddToHead, string bytesToAddToTail)
|
||||||
|
{
|
||||||
|
// Source: http://stackoverflow.com/questions/311165/how-do-you-convert-byte-array-to-hexadecimal-string-and-vice-versa
|
||||||
|
byte[] bytesToAddToHeadArray = new byte[bytesToAddToHead.Length / 2];
|
||||||
|
for (int i = 0; i < bytesToAddToHead.Length; i += 2)
|
||||||
|
{
|
||||||
|
bytesToAddToHeadArray[i / 2] = Convert.ToByte(bytesToAddToHead.Substring(i, 2), 16);
|
||||||
|
}
|
||||||
|
byte[] bytesToAddToTailArray = new byte[bytesToAddToTail.Length / 2];
|
||||||
|
for (int i = 0; i < bytesToAddToTail.Length; i += 2)
|
||||||
|
{
|
||||||
|
bytesToAddToTailArray[i / 2] = Convert.ToByte(bytesToAddToTail.Substring(i, 2), 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
AppendBytesToFile(input, output, bytesToAddToHeadArray, bytesToAddToTailArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add an aribtrary number of bytes to the inputted file
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">File to be appended to</param>
|
||||||
|
/// <param name="output">Outputted file</param>
|
||||||
|
/// <param name="bytesToAddToHead">Bytes to be added to head of file</param>
|
||||||
|
/// <param name="bytesToAddToTail">Bytes to be added to tail of file</param>
|
||||||
|
public static void AppendBytesToFile(string input, string output, byte[] bytesToAddToHead, byte[] bytesToAddToTail)
|
||||||
|
{
|
||||||
|
// If any of the inputs are invalid, skip
|
||||||
|
if (!File.Exists(input))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (BinaryReader br = new BinaryReader(File.OpenRead(input)))
|
||||||
|
using (BinaryWriter bw = new BinaryWriter(File.OpenWrite(output)))
|
||||||
|
{
|
||||||
|
if (bytesToAddToHead.Count() > 0)
|
||||||
|
{
|
||||||
|
bw.Write(bytesToAddToHead);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bufferSize = 1024;
|
||||||
|
|
||||||
|
// Now read the file in chunks and write out
|
||||||
|
byte[] buffer = new byte[bufferSize];
|
||||||
|
while (br.BaseStream.Position <= (br.BaseStream.Length - bufferSize))
|
||||||
|
{
|
||||||
|
buffer = br.ReadBytes(bufferSize);
|
||||||
|
bw.Write(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For the final chunk, if any, write out only that number of bytes
|
||||||
|
int length = (int)(br.BaseStream.Length - br.BaseStream.Position);
|
||||||
|
buffer = new byte[length];
|
||||||
|
buffer = br.ReadBytes(length);
|
||||||
|
bw.Write(buffer);
|
||||||
|
|
||||||
|
if (bytesToAddToTail.Count() > 0)
|
||||||
|
{
|
||||||
|
bw.Write(bytesToAddToTail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copy a file to a new location, creating directories as needed
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">Input filename</param>
|
||||||
|
/// <param name="output">Output filename</param>
|
||||||
|
public static void CopyFileToNewLocation(string input, string output)
|
||||||
|
{
|
||||||
|
if (File.Exists(input) && !File.Exists(output))
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(Path.GetDirectoryName(output)))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(Path.GetDirectoryName(output));
|
||||||
|
}
|
||||||
|
File.Copy(input, output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cleans out the temporary directory
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dirname">Name of the directory to clean out</param>
|
||||||
|
public static void CleanDirectory(string dirname)
|
||||||
|
{
|
||||||
|
foreach (string file in Directory.EnumerateFiles(dirname, "*", SearchOption.TopDirectoryOnly))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.Delete(file);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
foreach (string dir in Directory.EnumerateDirectories(dirname, "*", SearchOption.TopDirectoryOnly))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Directory.Delete(dir, true);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Hash-to-Dat functions
|
#region Hash-to-Dat functions
|
||||||
|
|
||||||
// All things in this region are direct ports and do not take advantage of the multiple rom per hash that comes with the new system
|
// All things in this region are direct ports and do not take advantage of the multiple rom per hash that comes with the new system
|
||||||
|
|||||||
@@ -1,777 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Web;
|
|
||||||
|
|
||||||
namespace SabreTools.Helper
|
|
||||||
{
|
|
||||||
public class Output
|
|
||||||
{
|
|
||||||
/// <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>
|
|
||||||
/// <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>
|
|
||||||
public static bool WriteDatfile(Dat datdata, string outDir, Logger logger, bool norename = true, bool stats = false, bool ignoreblanks = false)
|
|
||||||
{
|
|
||||||
// If the DAT has no output format, default to XML
|
|
||||||
if (datdata.OutputFormat == OutputFormat.None)
|
|
||||||
{
|
|
||||||
datdata.OutputFormat = OutputFormat.Xml;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output initial statistics, for kicks
|
|
||||||
if (stats)
|
|
||||||
{
|
|
||||||
Stats.OutputStats(datdata, logger, (datdata.RomCount + datdata.DiskCount == 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bucket roms by game name and optionally dedupe
|
|
||||||
SortedDictionary<string, List<Rom>> sortable = DatTools.BucketByGame(datdata.Files, datdata.MergeRoms, norename, logger);
|
|
||||||
|
|
||||||
// Now write out to file
|
|
||||||
// If it's empty, use the current folder
|
|
||||||
if (outDir.Trim() == "")
|
|
||||||
{
|
|
||||||
outDir = Environment.CurrentDirectory;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the output directory if it doesn't already exist
|
|
||||||
Directory.CreateDirectory(outDir);
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the outfile name
|
|
||||||
string outfile = Style.CreateOutfileName(outDir, datdata);
|
|
||||||
|
|
||||||
logger.User("Opening file for writing: " + outfile);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
FileStream fs = File.Create(outfile);
|
|
||||||
StreamWriter sw = new StreamWriter(fs, Encoding.UTF8);
|
|
||||||
|
|
||||||
// Write out the header
|
|
||||||
WriteHeader(sw, datdata, logger);
|
|
||||||
|
|
||||||
// Write out each of the machines and roms
|
|
||||||
int depth = 2, last = -1;
|
|
||||||
string lastgame = null;
|
|
||||||
List<string> splitpath = new List<string>();
|
|
||||||
foreach (List<Rom> roms in sortable.Values)
|
|
||||||
{
|
|
||||||
for (int index = 0; index < roms.Count; index++)
|
|
||||||
{
|
|
||||||
Rom rom = roms[index];
|
|
||||||
List<string> newsplit = rom.Machine.Name.Split('\\').ToList();
|
|
||||||
|
|
||||||
// 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())
|
|
||||||
{
|
|
||||||
depth = WriteEndGame(sw, rom, splitpath, newsplit, lastgame, datdata, depth, out last, logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have a new game, output the beginning of the new item
|
|
||||||
if (lastgame == null || lastgame.ToLowerInvariant() != rom.Machine.Name.ToLowerInvariant())
|
|
||||||
{
|
|
||||||
depth = WriteStartGame(sw, rom, newsplit, lastgame, datdata, depth, last, logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have a "null" game (created by DATFromDir or something similar), log it to file
|
|
||||||
if (rom.Name == "null" && rom.HashData.Size == -1 && rom.HashData.CRC == "null" && rom.HashData.MD5 == "null" && rom.HashData.SHA1 == "null")
|
|
||||||
{
|
|
||||||
logger.Log("Empty folder found: " + rom.Machine);
|
|
||||||
|
|
||||||
// If we're in a mode that doesn't allow for actual empty folders, add the blank info
|
|
||||||
if (datdata.OutputFormat != OutputFormat.SabreDat && datdata.OutputFormat != OutputFormat.MissFile)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, output the rom data
|
|
||||||
WriteRomData(sw, rom, lastgame, datdata, depth, logger, ignoreblanks);
|
|
||||||
|
|
||||||
// Set the new data to compare against
|
|
||||||
splitpath = newsplit;
|
|
||||||
lastgame = rom.Machine.Name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the file footer out
|
|
||||||
WriteFooter(sw, datdata, depth, logger);
|
|
||||||
|
|
||||||
logger.Log("File written!" + Environment.NewLine);
|
|
||||||
sw.Close();
|
|
||||||
fs.Close();
|
|
||||||
}
|
|
||||||
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>
|
|
||||||
/// <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>
|
|
||||||
public static bool WriteHeader(StreamWriter sw, Dat datdata, Logger logger)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string header = "";
|
|
||||||
switch (datdata.OutputFormat)
|
|
||||||
{
|
|
||||||
case OutputFormat.ClrMamePro:
|
|
||||||
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" : "") +
|
|
||||||
")\n";
|
|
||||||
break;
|
|
||||||
case OutputFormat.MissFile:
|
|
||||||
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;
|
|
||||||
case OutputFormat.RomCenter:
|
|
||||||
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;
|
|
||||||
case OutputFormat.SabreDat:
|
|
||||||
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" +
|
|
||||||
"\t\t<rootdir>" + HttpUtility.HtmlEncode(datdata.RootDir) + "</rootdir>\n" +
|
|
||||||
"\t\t<category>" + HttpUtility.HtmlEncode(datdata.Category) + "</category>\n" +
|
|
||||||
"\t\t<version>" + HttpUtility.HtmlEncode(datdata.Version) + "</version>\n" +
|
|
||||||
"\t\t<date>" + HttpUtility.HtmlEncode(datdata.Date) + "</date>\n" +
|
|
||||||
"\t\t<author>" + HttpUtility.HtmlEncode(datdata.Author) + "</author>\n" +
|
|
||||||
"\t\t<comment>" + HttpUtility.HtmlEncode(datdata.Comment) + "</comment>\n" +
|
|
||||||
(!String.IsNullOrEmpty(datdata.Type) && datdata.ForcePacking != ForcePacking.Unzip ?
|
|
||||||
"\t\t<flags>\n" +
|
|
||||||
(!String.IsNullOrEmpty(datdata.Type) ? "\t\t\t<flag name=\"type\" value=\"" + datdata.Type + "\"/>\n" : "") +
|
|
||||||
(datdata.ForcePacking == ForcePacking.Unzip ? "\t\t\t<flag name=\"forcepacking\" value=\"unzip\"/>\n" : "") +
|
|
||||||
"\t\t</flags>\n" : "") +
|
|
||||||
"\t</header>\n" +
|
|
||||||
"\t<data>\n";
|
|
||||||
break;
|
|
||||||
case OutputFormat.Xml:
|
|
||||||
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" +
|
|
||||||
"\t\t<rootdir>" + HttpUtility.HtmlEncode(datdata.RootDir) + "</rootdir>\n" +
|
|
||||||
"\t\t<category>" + HttpUtility.HtmlEncode(datdata.Category) + "</category>\n" +
|
|
||||||
"\t\t<version>" + HttpUtility.HtmlEncode(datdata.Version) + "</version>\n" +
|
|
||||||
"\t\t<date>" + HttpUtility.HtmlEncode(datdata.Date) + "</date>\n" +
|
|
||||||
"\t\t<author>" + HttpUtility.HtmlEncode(datdata.Author) + "</author>\n" +
|
|
||||||
"\t\t<email>" + HttpUtility.HtmlEncode(datdata.Email) + "</email>\n" +
|
|
||||||
"\t\t<homepage>" + HttpUtility.HtmlEncode(datdata.Homepage) + "</homepage>\n" +
|
|
||||||
"\t\t<url>" + HttpUtility.HtmlEncode(datdata.Url) + "</url>\n" +
|
|
||||||
"\t\t<comment>" + HttpUtility.HtmlEncode(datdata.Comment) + "</comment>\n" +
|
|
||||||
(!String.IsNullOrEmpty(datdata.Type) ? "\t\t<type>" + datdata.Type + "</type>\n" : "") +
|
|
||||||
(datdata.ForcePacking == ForcePacking.Unzip ? "\t\t<clrmamepro forcepacking=\"unzip\" />\n" : "") +
|
|
||||||
"\t</header>\n";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the header out
|
|
||||||
sw.Write(header);
|
|
||||||
}
|
|
||||||
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>
|
|
||||||
/// <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="datdata">DatData object representing DAT information</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>
|
|
||||||
public static int WriteStartGame(StreamWriter sw, Rom rom, List<string> newsplit, string lastgame, Dat datdata, int depth, int last, Logger logger)
|
|
||||||
{
|
|
||||||
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 = "";
|
|
||||||
switch (datdata.OutputFormat)
|
|
||||||
{
|
|
||||||
case OutputFormat.ClrMamePro:
|
|
||||||
state += "game (\n\tname \"" + rom.Machine.Name + "\"\n" +
|
|
||||||
"\tdescription \"" + (String.IsNullOrEmpty(rom.Machine.Description) ? rom.Machine.Name : rom.Machine.Description) + "\"\n";
|
|
||||||
break;
|
|
||||||
case OutputFormat.SabreDat:
|
|
||||||
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;
|
|
||||||
case OutputFormat.Xml:
|
|
||||||
state += "\t<machine name=\"" + HttpUtility.HtmlEncode(rom.Machine.Name) + "\">\n" +
|
|
||||||
"\t\t<description>" + HttpUtility.HtmlEncode((String.IsNullOrEmpty(rom.Machine.Description) ? rom.Machine.Name : rom.Machine.Description)) + "</description>\n";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
sw.Write(state);
|
|
||||||
}
|
|
||||||
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>
|
|
||||||
/// <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="datdata">DatData object representing DAT information</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>
|
|
||||||
public static int WriteEndGame(StreamWriter sw, Rom rom, List<string> splitpath, List<string> newsplit, string lastgame, Dat datdata, int depth, out int last, Logger logger)
|
|
||||||
{
|
|
||||||
last = 0;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string state = "";
|
|
||||||
|
|
||||||
switch (datdata.OutputFormat)
|
|
||||||
{
|
|
||||||
case OutputFormat.ClrMamePro:
|
|
||||||
state += ")\n";
|
|
||||||
break;
|
|
||||||
case OutputFormat.SabreDat:
|
|
||||||
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;
|
|
||||||
case OutputFormat.Xml:
|
|
||||||
state += "\t</machine>\n";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
sw.Write(state);
|
|
||||||
}
|
|
||||||
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>
|
|
||||||
/// <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>
|
|
||||||
public static bool WriteRomData(StreamWriter sw, Rom rom, string lastgame, Dat datdata, int depth, Logger logger, bool ignoreblanks = false)
|
|
||||||
{
|
|
||||||
// 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 = "";
|
|
||||||
switch (datdata.OutputFormat)
|
|
||||||
{
|
|
||||||
case OutputFormat.ClrMamePro:
|
|
||||||
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;
|
|
||||||
case OutputFormat.MissFile:
|
|
||||||
string pre = datdata.Prefix + (datdata.Quotes ? "\"" : "");
|
|
||||||
string post = (datdata.Quotes ? "\"" : "") + datdata.Postfix;
|
|
||||||
|
|
||||||
// Check for special strings in prefix and postfix
|
|
||||||
pre = pre.Replace("%crc%", rom.HashData.CRC).Replace("%md5%", rom.HashData.MD5).Replace("%sha1%", rom.HashData.SHA1).Replace("%size%", rom.HashData.Size.ToString());
|
|
||||||
post = post.Replace("%crc%", rom.HashData.CRC).Replace("%md5%", rom.HashData.MD5).Replace("%sha1%", rom.HashData.SHA1).Replace("%size%", rom.HashData.Size.ToString());
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
if (datdata.RepExt != "")
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
case OutputFormat.RomCenter:
|
|
||||||
state += "¬¬¬" + HttpUtility.HtmlEncode(rom.Machine) +
|
|
||||||
"¬" + 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;
|
|
||||||
case OutputFormat.SabreDat:
|
|
||||||
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;
|
|
||||||
case OutputFormat.Xml:
|
|
||||||
state += "\t\t<" + 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 ? " status=\"nodump\"" : "") +
|
|
||||||
"/>\n";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
sw.Write(state);
|
|
||||||
}
|
|
||||||
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>
|
|
||||||
public static bool WriteFooter(StreamWriter sw, Dat datdata, int depth, Logger logger)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string footer = "";
|
|
||||||
|
|
||||||
// If we have roms, output the full footer
|
|
||||||
if (datdata.Files != null && datdata.Files.Count > 0)
|
|
||||||
{
|
|
||||||
switch (datdata.OutputFormat)
|
|
||||||
{
|
|
||||||
case OutputFormat.ClrMamePro:
|
|
||||||
footer = ")";
|
|
||||||
break;
|
|
||||||
case OutputFormat.SabreDat:
|
|
||||||
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;
|
|
||||||
case OutputFormat.Xml:
|
|
||||||
footer = "\t</machine>\n</datafile>";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, output the abbreviated form
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (datdata.OutputFormat)
|
|
||||||
{
|
|
||||||
case OutputFormat.SabreDat:
|
|
||||||
case OutputFormat.Xml:
|
|
||||||
footer = "</datafile>";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the footer out
|
|
||||||
sw.Write(footer);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
logger.Error(ex.ToString());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Cleans out the temporary directory
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dirname">Name of the directory to clean out</param>
|
|
||||||
public static void CleanDirectory(string dirname)
|
|
||||||
{
|
|
||||||
foreach (string file in Directory.EnumerateFiles(dirname, "*", SearchOption.TopDirectoryOnly))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
File.Delete(file);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
foreach (string dir in Directory.EnumerateDirectories(dirname, "*", SearchOption.TopDirectoryOnly))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Directory.Delete(dir, true);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove an arbitrary number of bytes from the inputted file
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input">File to be cropped</param>
|
|
||||||
/// <param name="output">Outputted file</param>
|
|
||||||
/// <param name="bytesToRemoveFromHead">Bytes to be removed from head of file</param>
|
|
||||||
/// <param name="bytesToRemoveFromTail">Bytes to be removed from tail of file</param>
|
|
||||||
public static void RemoveBytesFromFile(string input, string output, long bytesToRemoveFromHead, long bytesToRemoveFromTail)
|
|
||||||
{
|
|
||||||
// If any of the inputs are invalid, skip
|
|
||||||
if (!File.Exists(input) || new FileInfo(input).Length <= (bytesToRemoveFromHead + bytesToRemoveFromTail))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the input file and write to the fail
|
|
||||||
using (BinaryReader br = new BinaryReader(File.OpenRead(input)))
|
|
||||||
using (BinaryWriter bw = new BinaryWriter(File.OpenWrite(output)))
|
|
||||||
{
|
|
||||||
int bufferSize = 1024;
|
|
||||||
long adjustedLength = br.BaseStream.Length - bytesToRemoveFromTail;
|
|
||||||
|
|
||||||
// Seek to the correct position
|
|
||||||
br.BaseStream.Seek((bytesToRemoveFromHead < 0 ? 0 : bytesToRemoveFromHead), SeekOrigin.Begin);
|
|
||||||
|
|
||||||
// Now read the file in chunks and write out
|
|
||||||
byte[] buffer = new byte[bufferSize];
|
|
||||||
while (br.BaseStream.Position <= (adjustedLength - bufferSize))
|
|
||||||
{
|
|
||||||
buffer = br.ReadBytes(bufferSize);
|
|
||||||
bw.Write(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For the final chunk, if any, write out only that number of bytes
|
|
||||||
int length = (int)(adjustedLength - br.BaseStream.Position);
|
|
||||||
buffer = new byte[length];
|
|
||||||
buffer = br.ReadBytes(length);
|
|
||||||
bw.Write(buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Add an aribtrary number of bytes to the inputted file
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input">File to be appended to</param>
|
|
||||||
/// <param name="output">Outputted file</param>
|
|
||||||
/// <param name="bytesToAddToHead">String representing bytes to be added to head of file</param>
|
|
||||||
/// <param name="bytesToAddToTail">String representing bytes to be added to tail of file</param>
|
|
||||||
public static void AppendBytesToFile(string input, string output, string bytesToAddToHead, string bytesToAddToTail)
|
|
||||||
{
|
|
||||||
// Source: http://stackoverflow.com/questions/311165/how-do-you-convert-byte-array-to-hexadecimal-string-and-vice-versa
|
|
||||||
byte[] bytesToAddToHeadArray = new byte[bytesToAddToHead.Length / 2];
|
|
||||||
for (int i = 0; i < bytesToAddToHead.Length; i += 2)
|
|
||||||
{
|
|
||||||
bytesToAddToHeadArray[i/2] = Convert.ToByte(bytesToAddToHead.Substring(i, 2), 16);
|
|
||||||
}
|
|
||||||
byte[] bytesToAddToTailArray = new byte[bytesToAddToTail.Length / 2];
|
|
||||||
for (int i = 0; i < bytesToAddToTail.Length; i += 2)
|
|
||||||
{
|
|
||||||
bytesToAddToTailArray[i / 2] = Convert.ToByte(bytesToAddToTail.Substring(i, 2), 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
AppendBytesToFile(input, output, bytesToAddToHeadArray, bytesToAddToTailArray);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Add an aribtrary number of bytes to the inputted file
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input">File to be appended to</param>
|
|
||||||
/// <param name="output">Outputted file</param>
|
|
||||||
/// <param name="bytesToAddToHead">Bytes to be added to head of file</param>
|
|
||||||
/// <param name="bytesToAddToTail">Bytes to be added to tail of file</param>
|
|
||||||
public static void AppendBytesToFile(string input, string output, byte[] bytesToAddToHead, byte[] bytesToAddToTail)
|
|
||||||
{
|
|
||||||
// If any of the inputs are invalid, skip
|
|
||||||
if (!File.Exists(input))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
using (BinaryReader br = new BinaryReader(File.OpenRead(input)))
|
|
||||||
using (BinaryWriter bw = new BinaryWriter(File.OpenWrite(output)))
|
|
||||||
{
|
|
||||||
if (bytesToAddToHead.Count() > 0)
|
|
||||||
{
|
|
||||||
bw.Write(bytesToAddToHead);
|
|
||||||
}
|
|
||||||
|
|
||||||
int bufferSize = 1024;
|
|
||||||
|
|
||||||
// Now read the file in chunks and write out
|
|
||||||
byte[] buffer = new byte[bufferSize];
|
|
||||||
while (br.BaseStream.Position <= (br.BaseStream.Length - bufferSize))
|
|
||||||
{
|
|
||||||
buffer = br.ReadBytes(bufferSize);
|
|
||||||
bw.Write(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For the final chunk, if any, write out only that number of bytes
|
|
||||||
int length = (int)(br.BaseStream.Length - br.BaseStream.Position);
|
|
||||||
buffer = new byte[length];
|
|
||||||
buffer = br.ReadBytes(length);
|
|
||||||
bw.Write(buffer);
|
|
||||||
|
|
||||||
if (bytesToAddToTail.Count() > 0)
|
|
||||||
{
|
|
||||||
bw.Write(bytesToAddToTail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Copy a file to a new location, creating directories as needed
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input">Input filename</param>
|
|
||||||
/// <param name="output">Output filename</param>
|
|
||||||
public static void CopyFileToNewLocation(string input, string output)
|
|
||||||
{
|
|
||||||
if (File.Exists(input) && !File.Exists(output))
|
|
||||||
{
|
|
||||||
if (!Directory.Exists(Path.GetDirectoryName(output)))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(output));
|
|
||||||
}
|
|
||||||
File.Copy(input, output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -121,7 +121,7 @@ namespace SabreTools
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write out the initial file header
|
// Write out the initial file header
|
||||||
Output.WriteHeader(sw, _datdata, _logger);
|
DatTools.WriteHeader(sw, _datdata, _logger);
|
||||||
|
|
||||||
// Loop over each of the found paths, if any
|
// Loop over each of the found paths, if any
|
||||||
string lastparent = null;
|
string lastparent = null;
|
||||||
@@ -295,19 +295,19 @@ namespace SabreTools
|
|||||||
int last = 0;
|
int last = 0;
|
||||||
if (lastparent != null && lastparent.ToLowerInvariant() != rom.Machine.Name.ToLowerInvariant())
|
if (lastparent != null && lastparent.ToLowerInvariant() != rom.Machine.Name.ToLowerInvariant())
|
||||||
{
|
{
|
||||||
Output.WriteEndGame(sw, rom, new List<string>(), new List<string>(), lastparent, _datdata, 0, out last, _logger);
|
DatTools.WriteEndGame(sw, rom, new List<string>(), new List<string>(), lastparent, _datdata, 0, out last, _logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have a new game, output the beginning of the new item
|
// If we have a new game, output the beginning of the new item
|
||||||
if (lastparent == null || lastparent.ToLowerInvariant() != rom.Machine.Name.ToLowerInvariant())
|
if (lastparent == null || lastparent.ToLowerInvariant() != rom.Machine.Name.ToLowerInvariant())
|
||||||
{
|
{
|
||||||
Output.WriteStartGame(sw, rom, new List<string>(), lastparent, _datdata, 0, last, _logger);
|
DatTools.WriteStartGame(sw, rom, new List<string>(), lastparent, _datdata, 0, last, _logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write out the rom data
|
// Write out the rom data
|
||||||
if (_datdata.OutputFormat != OutputFormat.SabreDat && _datdata.OutputFormat != OutputFormat.MissFile)
|
if (_datdata.OutputFormat != OutputFormat.SabreDat && _datdata.OutputFormat != OutputFormat.MissFile)
|
||||||
{
|
{
|
||||||
Output.WriteRomData(sw, rom, lastparent, _datdata, 0, _logger);
|
DatTools.WriteRomData(sw, rom, lastparent, _datdata, 0, _logger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,7 +323,7 @@ namespace SabreTools
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now write the final piece and close the output stream
|
// Now write the final piece and close the output stream
|
||||||
Output.WriteFooter(sw, _datdata, 0, _logger);
|
DatTools.WriteFooter(sw, _datdata, 0, _logger);
|
||||||
sw.Close();
|
sw.Close();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -369,9 +369,9 @@ namespace SabreTools
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Output.WriteStartGame(sw, rom, new List<string>(), "", _datdata, 0, 0, _logger);
|
DatTools.WriteStartGame(sw, rom, new List<string>(), "", _datdata, 0, 0, _logger);
|
||||||
Output.WriteRomData(sw, rom, "", _datdata, 0, _logger);
|
DatTools.WriteRomData(sw, rom, "", _datdata, 0, _logger);
|
||||||
Output.WriteEndGame(sw, rom, new List<string>(), new List<string>(), "", _datdata, 0, out last, _logger);
|
DatTools.WriteEndGame(sw, rom, new List<string>(), new List<string>(), "", _datdata, 0, out last, _logger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -436,7 +436,7 @@ namespace SabreTools
|
|||||||
// Clear the temp directory
|
// Clear the temp directory
|
||||||
if (Directory.Exists(tempdir))
|
if (Directory.Exists(tempdir))
|
||||||
{
|
{
|
||||||
Output.CleanDirectory(tempdir);
|
FileTools.CleanDirectory(tempdir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Otherwise, just get the info on the file itself
|
// Otherwise, just get the info on the file itself
|
||||||
@@ -548,17 +548,17 @@ namespace SabreTools
|
|||||||
int last = 0;
|
int last = 0;
|
||||||
if (lastparent != null && lastparent.ToLowerInvariant() != rom.Machine.Name.ToLowerInvariant())
|
if (lastparent != null && lastparent.ToLowerInvariant() != rom.Machine.Name.ToLowerInvariant())
|
||||||
{
|
{
|
||||||
Output.WriteEndGame(sw, rom, new List<string>(), new List<string>(), lastparent, datdata, 0, out last, _logger);
|
DatTools.WriteEndGame(sw, rom, new List<string>(), new List<string>(), lastparent, datdata, 0, out last, _logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have a new game, output the beginning of the new item
|
// If we have a new game, output the beginning of the new item
|
||||||
if (lastparent == null || lastparent.ToLowerInvariant() != rom.Machine.Name.ToLowerInvariant())
|
if (lastparent == null || lastparent.ToLowerInvariant() != rom.Machine.Name.ToLowerInvariant())
|
||||||
{
|
{
|
||||||
Output.WriteStartGame(sw, rom, new List<string>(), lastparent, datdata, 0, last, _logger);
|
DatTools.WriteStartGame(sw, rom, new List<string>(), lastparent, datdata, 0, last, _logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write out the rom data
|
// Write out the rom data
|
||||||
Output.WriteRomData(sw, rom, lastparent, datdata, 0, _logger);
|
DatTools.WriteRomData(sw, rom, lastparent, datdata, 0, _logger);
|
||||||
}
|
}
|
||||||
_logger.User("File added: " + actualitem + Environment.NewLine);
|
_logger.User("File added: " + actualitem + Environment.NewLine);
|
||||||
|
|
||||||
|
|||||||
@@ -379,7 +379,7 @@ namespace SabreTools
|
|||||||
// Clear the temp directory
|
// Clear the temp directory
|
||||||
if (Directory.Exists(tempdir))
|
if (Directory.Exists(tempdir))
|
||||||
{
|
{
|
||||||
Output.CleanDirectory(tempdir);
|
FileTools.CleanDirectory(tempdir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Otherwise, just get the info on the file itself
|
// Otherwise, just get the info on the file itself
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ namespace SabreTools
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Then write out the file
|
// Then write out the file
|
||||||
Output.WriteDatfile(datdata, _outroot, _logger, _norename);
|
DatTools.WriteDatfile(datdata, _outroot, _logger, _norename);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -348,10 +348,10 @@ namespace SabreTools
|
|||||||
Files = have,
|
Files = have,
|
||||||
};
|
};
|
||||||
|
|
||||||
Output.WriteDatfile(netNewData, "", _logger);
|
DatTools.WriteDatfile(netNewData, "", _logger);
|
||||||
Output.WriteDatfile(unneededData, "", _logger);
|
DatTools.WriteDatfile(unneededData, "", _logger);
|
||||||
Output.WriteDatfile(newMissingData, "", _logger);
|
DatTools.WriteDatfile(newMissingData, "", _logger);
|
||||||
Output.WriteDatfile(haveData, "", _logger);
|
DatTools.WriteDatfile(haveData, "", _logger);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -421,7 +421,7 @@ namespace SabreTools
|
|||||||
MergeRoms = true,
|
MergeRoms = true,
|
||||||
Files = have,
|
Files = have,
|
||||||
};
|
};
|
||||||
Output.WriteDatfile(haveData, "", _logger);
|
DatTools.WriteDatfile(haveData, "", _logger);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -491,7 +491,7 @@ namespace SabreTools
|
|||||||
MergeRoms = true,
|
MergeRoms = true,
|
||||||
Files = have,
|
Files = have,
|
||||||
};
|
};
|
||||||
Output.WriteDatfile(haveData, "", _logger);
|
DatTools.WriteDatfile(haveData, "", _logger);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -414,7 +414,7 @@ namespace SabreTools
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
// For DFDParallel only
|
// For DFDParallel only
|
||||||
Output.WriteDatfile(dfd.DatData, "", _logger);
|
DatTools.WriteDatfile(dfd.DatData, "", _logger);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// If we failed, show the help
|
// If we failed, show the help
|
||||||
|
|||||||
@@ -306,19 +306,19 @@ namespace SabreTools
|
|||||||
bool success = true;
|
bool success = true;
|
||||||
if (nodump.Files.Count > 0)
|
if (nodump.Files.Count > 0)
|
||||||
{
|
{
|
||||||
success &= Output.WriteDatfile(nodump, outdir, _logger);
|
success &= DatTools.WriteDatfile(nodump, outdir, _logger);
|
||||||
}
|
}
|
||||||
if (sha1.Files.Count > 0)
|
if (sha1.Files.Count > 0)
|
||||||
{
|
{
|
||||||
success &= Output.WriteDatfile(sha1, outdir, _logger);
|
success &= DatTools.WriteDatfile(sha1, outdir, _logger);
|
||||||
}
|
}
|
||||||
if (md5.Files.Count > 0)
|
if (md5.Files.Count > 0)
|
||||||
{
|
{
|
||||||
success &= Output.WriteDatfile(md5, outdir, _logger);
|
success &= DatTools.WriteDatfile(md5, outdir, _logger);
|
||||||
}
|
}
|
||||||
if (crc.Files.Count > 0)
|
if (crc.Files.Count > 0)
|
||||||
{
|
{
|
||||||
success &= Output.WriteDatfile(crc, outdir, _logger);
|
success &= DatTools.WriteDatfile(crc, outdir, _logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
@@ -446,8 +446,8 @@ namespace SabreTools
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Then write out both files
|
// Then write out both files
|
||||||
bool success = Output.WriteDatfile(datdataA, outdir, _logger);
|
bool success = DatTools.WriteDatfile(datdataA, outdir, _logger);
|
||||||
success &= Output.WriteDatfile(datdataB, outdir, _logger);
|
success &= DatTools.WriteDatfile(datdataB, outdir, _logger);
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -327,7 +327,7 @@ namespace SabreTools
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Output.CleanDirectory(_tempdir);
|
FileTools.CleanDirectory(_tempdir);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_verify)
|
if (_verify)
|
||||||
@@ -401,7 +401,7 @@ namespace SabreTools
|
|||||||
// Now output the fixdat to the main folder
|
// Now output the fixdat to the main folder
|
||||||
if (found)
|
if (found)
|
||||||
{
|
{
|
||||||
Output.WriteDatfile(_matched, "", _logger, stats: true);
|
DatTools.WriteDatfile(_matched, "", _logger, stats: true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -449,7 +449,7 @@ namespace SabreTools
|
|||||||
for (int i = 0; i < files.Count; i++)
|
for (int i = 0; i < files.Count; i++)
|
||||||
{
|
{
|
||||||
success &= RebuildToOutputHelper(files[i], i, files.Count);
|
success &= RebuildToOutputHelper(files[i], i, files.Count);
|
||||||
Output.CleanDirectory(_tempdir);
|
FileTools.CleanDirectory(_tempdir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now one final delete of the temp directory
|
// Now one final delete of the temp directory
|
||||||
@@ -478,7 +478,7 @@ namespace SabreTools
|
|||||||
_datdata.Name = "fixDat_" + _datdata.Name;
|
_datdata.Name = "fixDat_" + _datdata.Name;
|
||||||
_datdata.Description = "fixDat_" + _datdata.Description;
|
_datdata.Description = "fixDat_" + _datdata.Description;
|
||||||
_datdata.OutputFormat = OutputFormat.Xml;
|
_datdata.OutputFormat = OutputFormat.Xml;
|
||||||
Output.WriteDatfile(_datdata, "", _logger);
|
DatTools.WriteDatfile(_datdata, "", _logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
@@ -862,7 +862,7 @@ namespace SabreTools
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clear the temporary archive directory
|
// Clear the temporary archive directory
|
||||||
Output.CleanDirectory(temparcdir);
|
FileTools.CleanDirectory(temparcdir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then add each of the found files to the new dictionary
|
// Then add each of the found files to the new dictionary
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ namespace SabreTools
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Output.CleanDirectory(_tempdir);
|
FileTools.CleanDirectory(_tempdir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now process all of the inputs
|
// Now process all of the inputs
|
||||||
|
|||||||
Reference in New Issue
Block a user