[ALL] Add Everdrive SMDB

This commit is contained in:
Matt Nadareski
2019-02-08 15:31:44 -08:00
parent 2743b1d61f
commit 2ab4e3d48e
8 changed files with 3463 additions and 3221 deletions

View File

@@ -5717,6 +5717,20 @@ namespace SabreTools.Library.DatFiles
outfileNames.Add(DatFormat.SabreDat, CreateOutfileNamesHelper(outDir, ".sd.xml", overwrite));
};
// Everdrive SMDB
if ((DatFormat & DatFormat.EverdriveSMDB) != 0
&& (DatFormat & DatFormat.AttractMode) == 0
&& (DatFormat & DatFormat.MissFile) == 0)
{
outfileNames.Add(DatFormat.EverdriveSMDB, CreateOutfileNamesHelper(outDir, ".txt", overwrite));
}
if ((DatFormat & DatFormat.EverdriveSMDB) != 0
&& ((DatFormat & DatFormat.AttractMode) != 0
|| (DatFormat & DatFormat.MissFile) != 0))
{
outfileNames.Add(DatFormat.SoftwareList, CreateOutfileNamesHelper(outDir, ".smdb.txt", overwrite));
}
// Software List
if ((DatFormat & DatFormat.SoftwareList) != 0
&& (DatFormat & DatFormat.Logiqx) == 0

View File

@@ -0,0 +1,214 @@
using System;
using System.Collections.Generic;
using System.Text;
using SabreTools.Library.Data;
using SabreTools.Library.DatItems;
using SabreTools.Library.Tools;
#if MONO
using System.IO;
#else
using Alphaleonis.Win32.Filesystem;
using FileStream = System.IO.FileStream;
using StreamReader = System.IO.StreamReader;
using StreamWriter = System.IO.StreamWriter;
#endif
using NaturalSort;
namespace SabreTools.Library.DatFiles
{
/// <summary>
/// Represents parsing and writing of an Everdrive SMDB file
/// </summary>
internal class EverdriveSMDB : DatFile
{
/// <summary>
/// Constructor designed for casting a base DatFile
/// </summary>
/// <param name="datFile">Parent DatFile to copy from</param>
public EverdriveSMDB(DatFile datFile)
: base(datFile, cloneHeader: false)
{
}
/// <summary>
/// Parse an Everdrive SMDB file and return all found games 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="keep">True if full pathnames are to be kept, false otherwise (default)</param>
/// <param name="clean">True if game names are sanitized, false otherwise (default)</param>
/// <param name="remUnicode">True if we should remove non-ASCII characters from output, false otherwise (default)</param>
public override void ParseFile(
// Standard Dat parsing
string filename,
int sysid,
int srcid,
// Miscellaneous
bool keep,
bool clean,
bool remUnicode)
{
// Open a file reader
Encoding enc = Utilities.GetEncoding(filename);
StreamReader sr = new StreamReader(Utilities.TryOpenRead(filename), enc);
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
/*
The gameinfo order is as follows
0 - SHA-256
1 - Machine Name/Filename
2 - SHA-1
3 - MD5
4 - CRC32
*/
string[] gameinfo = line.Split('\t');
string[] fullname = gameinfo[1].Split('/');
Rom rom = new Rom
{
Name = gameinfo[1].Substring(fullname.Length + 1),
Size = Constants.SizeZero,
CRC = gameinfo[4].PadLeft(8, '0'),
MD5 = gameinfo[3].PadLeft(32, '0'),
SHA1 = gameinfo[2].PadLeft(40, '0'),
SHA256 = gameinfo[0].PadLeft(64, '0'),
ItemStatus = ItemStatus.None,
MachineName = fullname[0],
MachineDescription = fullname[0],
};
// Now process and add the rom
ParseAddHelper(rom, clean, remUnicode);
}
sr.Dispose();
}
/// <summary>
/// Create and open an output file for writing direct from a dictionary
/// </summary>
/// <param name="outfile">Name of the file to write to</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>
public override bool WriteToFile(string outfile, bool ignoreblanks = false)
{
try
{
Globals.Logger.User("Opening file for writing: {0}", outfile);
FileStream fs = Utilities.TryCreate(outfile);
// If we get back null for some reason, just log and return
if (fs == null)
{
Globals.Logger.Warning("File '{0}' could not be created for writing! Please check to see if the file is writable", outfile);
return false;
}
StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
// Get a properly sorted set of keys
List<string> keys = Keys;
keys.Sort(new NaturalComparer());
foreach (string key in keys)
{
List<DatItem> roms = this[key];
// Resolve the names in the block
roms = DatItem.ResolveNames(roms);
for (int index = 0; index < roms.Count; index++)
{
DatItem item = roms[index];
// There are apparently times when a null rom can skip by, skip them
if (item.Name == null || item.MachineName == null)
{
Globals.Logger.Warning("Null rom found!");
continue;
}
// If we have a "null" game (created by DATFromDir or something similar), log it to file
if (item.ItemType == ItemType.Rom
&& ((Rom)item).Size == -1
&& ((Rom)item).CRC == "null")
{
Globals.Logger.Verbose("Empty folder found: {0}", item.MachineName);
item.Name = (item.Name == "null" ? "-" : item.Name);
((Rom)item).Size = Constants.SizeZero;
}
WriteDatItem(sw, item, ignoreblanks);
}
}
Globals.Logger.Verbose("File written!" + Environment.NewLine);
sw.Dispose();
fs.Dispose();
}
catch (Exception ex)
{
Globals.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">DatItem object to be output</param>
/// <returns>True if the data was written, false on error</returns>
private bool WriteDatItem(StreamWriter sw, DatItem rom, bool ignoreblanks = false)
{
// If we are in ignore blanks mode AND we have a blank (0-size) rom, skip
if (ignoreblanks
&& (rom.ItemType == ItemType.Rom
&& (((Rom)rom).Size == 0 || ((Rom)rom).Size == -1)))
{
return true;
}
try
{
// No game should start with a path separator
if (rom.MachineName.StartsWith(Path.DirectorySeparatorChar.ToString()))
rom.MachineName = rom.MachineName.Substring(1);
// If the DatItem isn't a rom, we don't output it
if (rom.ItemType != ItemType.Rom)
return true;
Rom temp = rom as Rom;
string state = (!ExcludeFields[(int)Field.SHA256] ? temp.SHA256 : "") + "\t"
+ (!ExcludeFields[(int)Field.MachineName] ? temp.MachineName + "/" : "")
+ temp.Name + "\t"
+ (!ExcludeFields[(int)Field.SHA1] ? temp.SHA1 : "") + "\t"
+ (!ExcludeFields[(int)Field.MD5] ? temp.MD5 : "") + "\t"
+ (!ExcludeFields[(int)Field.CRC] ? temp.CRC : "") + "\n";
sw.Write(state);
sw.Flush();
}
catch (Exception ex)
{
Globals.Logger.Error(ex.ToString());
return false;
}
return true;
}
}
}

View File

@@ -343,6 +343,11 @@ namespace SabreTools.Library.Data
/// </summary>
Listrom = 1 << 15,
/// <summary>
/// Everdrive Packs SMDB
/// </summary>
EverdriveSMDB = 1 << 16,
#endregion
#region SFV-similar Formats
@@ -350,32 +355,32 @@ namespace SabreTools.Library.Data
/// <summary>
/// CRC32 hash list
/// </summary>
RedumpSFV = 1 << 16,
RedumpSFV = 1 << 17,
/// <summary>
/// MD5 hash list
/// </summary>
RedumpMD5 = 1 << 17,
RedumpMD5 = 1 << 18,
/// <summary>
/// SHA-1 hash list
/// </summary>
RedumpSHA1 = 1 << 18,
RedumpSHA1 = 1 << 19,
/// <summary>
/// SHA-256 hash list
/// </summary>
RedumpSHA256 = 1 << 19,
RedumpSHA256 = 1 << 20,
/// <summary>
/// SHA-384 hash list
/// </summary>
RedumpSHA384 = 1 << 20,
RedumpSHA384 = 1 << 21,
/// <summary>
/// SHA-512 hash list
/// </summary>
RedumpSHA512 = 1 << 21,
RedumpSHA512 = 1 << 22,
#endregion

View File

@@ -228,6 +228,7 @@ Options:
sha256 - SHA256
sha384 - SHA384
sha512 - SHA512
smdb, everdrive - Everdrive SMDB
sl, softwarelist - MAME Software List XML
ssv - Standardized Semicolon-Separated Value
tsv - Standardized Tab-Separated Value
@@ -756,6 +757,7 @@ Options:
sha256 - SHA256
sha384 - SHA384
sha512 - SHA512
smdb, everdrive - Everdrive SMDB
sl, softwarelist - MAME Software List XML
ssv - Standardized Semicolon-Separated Value
tsv - Standardized Tab-Separated Value
@@ -928,6 +930,7 @@ Options:
sha256 - SHA256
sha384 - SHA384
sha512 - SHA512
smdb, everdrive - Everdrive SMDB
sl, softwarelist - MAME Software List XML
ssv - Standardized Semicolon-Separated Value
tsv - Standardized Tab-Separated Value
@@ -1832,6 +1835,7 @@ This section contains remappings from old flag names to new ones for the purpose
-osha256, --output-sha256 -> -ot=sha256, --output-type=sha256
-osha384, --output-sha384 -> -ot=sha384, --output-type=sha384
-osha512, --output-sha512 -> -ot=sha512, --output-type=sha512
-osmdb, --output-everdrive -> -ot=smdb, --output-type=everdrive
-osl, --output-sl -> -ot=sl, --output-type=softwarelist
-osl, --output-softwarelist -> -ot=sl, --output-type=softwarelist
-ossv, --output-ssv -> -ot=ssv, --output-type=ssv

View File

@@ -92,6 +92,7 @@
<Compile Include="DatFiles\DatHeader.cs" />
<Compile Include="DatFiles\DatStats.cs" />
<Compile Include="DatFiles\DosCenter.cs" />
<Compile Include="DatFiles\EverdriveSmdb.cs" />
<Compile Include="DatFiles\Filter.cs" />
<Compile Include="DatFiles\FilterItem.cs" />
<Compile Include="DatFiles\Hashfile.cs" />

View File

@@ -620,6 +620,8 @@ namespace SabreTools.Library.Tools
return new DatFiles.SeparatedValue(baseDat, ',');
case DatFormat.DOSCenter:
return new DosCenter(baseDat);
case DatFormat.EverdriveSMDB:
return new EverdriveSMDB(baseDat);
case DatFormat.Listrom:
return new Listrom(baseDat);
case DatFormat.Listxml:
@@ -773,6 +775,9 @@ namespace SabreTools.Library.Tools
case "sl":
case "softwarelist":
return DatFormat.SoftwareList;
case "smdb":
case "everdrive":
return DatFormat.EverdriveSMDB;
case "ssv":
return DatFormat.SSV;
case "tsv":
@@ -1215,9 +1220,7 @@ namespace SabreTools.Library.Tools
{
// Limit the output formats based on extension
if (!HasValidDatExtension(filename))
{
return 0;
}
// Get the extension from the filename
string ext = GetExtension(filename);
@@ -1262,88 +1265,72 @@ namespace SabreTools.Library.Tools
StreamReader sr = File.OpenText(filename);
string first = sr.ReadLine().ToLowerInvariant();
while (String.IsNullOrWhiteSpace(first) || first.StartsWith("<!--"))
{
first = sr.ReadLine().ToLowerInvariant();
}
string second = sr.ReadLine().ToLowerInvariant();
while (String.IsNullOrWhiteSpace(second) || second.StartsWith("<!--"))
{
second = sr.ReadLine().ToLowerInvariant();
}
sr.Dispose();
// If we have an XML-based DAT
if (first.Contains("<?xml") && first.Contains("?>"))
{
if (second.StartsWith("<!doctype datafile"))
{
return DatFormat.Logiqx;
}
else if (second.StartsWith("<!doctype mame")
|| second.StartsWith("<!doctype m1")
|| second.StartsWith("<mame")
|| second.StartsWith("<m1"))
{
return DatFormat.Listxml;
}
else if (second.StartsWith("<!doctype softwaredb"))
{
return DatFormat.OpenMSX;
}
else if (second.StartsWith("<!doctype softwarelist"))
{
return DatFormat.SoftwareList;
}
else if (second.StartsWith("<!doctype sabredat"))
{
return DatFormat.SabreDat;
}
else if ((second.StartsWith("<dat") && !second.StartsWith("<datafile"))
|| second.StartsWith("<?xml-stylesheet"))
{
return DatFormat.OfflineList;
}
// Older and non-compliant DATs
else
{
return DatFormat.Logiqx;
}
}
// If we have an SMDB (SHA-256, Filename, SHA-1, MD5, CRC32)
else if (Regex.IsMatch(first, @"[0-9a-f]{64}\t.*?\t[0-9a-f]{40}\t[0-9a-f]{32}\t[0-9a-f]{8}"))
return DatFormat.EverdriveSMDB;
// If we have an INI-based DAT
else if (first.Contains("[") && first.Contains("]"))
{
return DatFormat.RomCenter;
}
// If we have a listroms DAT
else if (first.StartsWith("roms required for driver"))
{
return DatFormat.Listrom;
}
// If we have a CMP-based DAT
else if (first.Contains("clrmamepro"))
{
return DatFormat.ClrMamePro;
}
else if (first.Contains("romvault"))
{
return DatFormat.ClrMamePro;
}
else if (first.Contains("doscenter"))
{
return DatFormat.DOSCenter;
}
else if (first.Contains("#Name;Title;Emulator;CloneOf;Year;Manufacturer;Category;Players;Rotation;Control;Status;DisplayCount;DisplayType;AltRomname;AltTitle;Extra"))
{
return DatFormat.AttractMode;
}
else
{
return DatFormat.ClrMamePro;
}
}
catch (Exception)
{
return 0;

View File

@@ -789,6 +789,18 @@ namespace SabreTools
longDescription: "Output in SHA-256 format [DEPRECIATED]");
}
} // TODO: Remove
private static Feature _outputSmdbFlag
{
get
{
return new Feature(
"output-smdb",
new List<string>() { "-osmdb", "--output-smdb" },
"Output in Everdrive SMDB format [DEPRECIATED]",
FeatureType.Flag,
longDescription: "Output in Everdrive SMDB format [DEPRECIATED]");
}
} // TODO: Remove
private static Feature _outputSoftwarelistFlag
{
get
@@ -1845,6 +1857,7 @@ Possible values are:
sha256 - SHA256
sha384 - SHA384
sha512 - SHA512
smdb, everdrive - Everdrive SMDB
sl, softwarelist - MAME Software List XML
ssv - Standardized Semicolon-Separated Value
tsv - Standardized Tab-Separated Value

View File

@@ -425,6 +425,10 @@ namespace SabreTools
datHeader.DatFormat |= DatFormat.RedumpSHA512;
Globals.Logger.User("This flag '{0}' is depreciated, please use {1} instead", feat.Key, String.Join(", ", _outputTypeListInput.Flags));
break;
case "output-smdb":
datHeader.DatFormat |= DatFormat.EverdriveSMDB;
Globals.Logger.User("This flag '{0}' is depreciated, please use {1} instead", feat.Key, String.Join(", ", _outputTypeListInput.Flags));
break;
case "output-softwarelist":
datHeader.DatFormat |= DatFormat.SoftwareList;
Globals.Logger.User("This flag '{0}' is depreciated, please use {1} instead", feat.Key, String.Join(", ", _outputTypeListInput.Flags));