Merge pull request #1 from mnadareski/StructToObject

Struct to object
This commit is contained in:
Matt Nadareski
2016-09-20 12:06:07 -07:00
committed by GitHub
30 changed files with 3042 additions and 4930 deletions

View File

@@ -33,7 +33,7 @@ namespace SabreTools
Dictionary<string, Tuple<long, bool>> depots = new Dictionary<string, Tuple<long, bool>>();
// Get the XML text reader for the configuration file, if possible
XmlTextReader xtr = DatTools.GetXmlTextReader(_config, _logger);
XmlTextReader xtr = DatFile.GetXmlTextReader(_config, _logger);
// Now parse the XML file for settings
if (xtr != null)
@@ -341,15 +341,15 @@ namespace SabreTools
Rom dat = FileTools.GetSingleFileInfo(file);
// If the Dat isn't in the database and isn't already accounted for in the DatRoot, add it
if (!databaseDats.Contains(dat.HashData.SHA1) && !toscan.ContainsKey(dat.HashData.SHA1))
if (!databaseDats.Contains(dat.SHA1) && !toscan.ContainsKey(dat.SHA1))
{
toscan.Add(dat.HashData.SHA1, Path.GetFullPath(file));
toscan.Add(dat.SHA1, Path.GetFullPath(file));
}
// If the Dat is in the database already, remove it to find stragglers
else if (databaseDats.Contains(dat.HashData.SHA1))
else if (databaseDats.Contains(dat.SHA1))
{
databaseDats.Remove(dat.HashData.SHA1);
databaseDats.Remove(dat.SHA1);
}
}
@@ -357,8 +357,8 @@ namespace SabreTools
foreach (string key in toscan.Keys)
{
// Parse the Dat if possible
Dat tempdat = new Dat();
DatTools.Parse(toscan[key], 0, 0, ref tempdat, _logger);
DatFile tempdat = new DatFile();
DatFile.Parse(toscan[key], 0, 0, ref tempdat, _logger);
// If the Dat wasn't empty, add the information
if (tempdat.Files.Count != 0)
@@ -368,10 +368,10 @@ namespace SabreTools
{
foreach (Rom rom in tempdat.Files[romkey])
{
query = "SELECT id FROM data WHERE key=\"size\" AND value=\"" + rom.HashData.Size + "\" AND ("
+ "(key=\"crc\" AND (value=\"" + rom.HashData.CRC + "\" OR value=\"null\"))"
+ "AND (key=\"md5\" AND value=\"" + rom.HashData.MD5 + "\" OR value=\"null\"))"
+ "AND (key=\"sha1\" AND value=\"" + rom.HashData.SHA1 + "\" OR value=\"null\")))";
query = "SELECT id FROM data WHERE key=\"size\" AND value=\"" + rom.Size + "\" AND ("
+ "(key=\"crc\" AND (value=\"" + rom.CRC + "\" OR value=\"null\"))"
+ "AND (key=\"md5\" AND value=\"" + rom.MD5 + "\" OR value=\"null\"))"
+ "AND (key=\"sha1\" AND value=\"" + rom.SHA1 + "\" OR value=\"null\")))";
using (SqliteCommand slc = new SqliteCommand(query, dbc))
{
using (SqliteDataReader sldr = slc.ExecuteReader())
@@ -392,7 +392,7 @@ namespace SabreTools
// If it doesn't exist, add the hash and the dat hash for a new id
else
{
string squery = "INSERT INTO data (key, value) VALUES (\"size\", \"" + rom.HashData.Size + "\")";
string squery = "INSERT INTO data (key, value) VALUES (\"size\", \"" + rom.Size + "\")";
using (SqliteCommand sslc = new SqliteCommand(squery, dbc))
{
sslc.ExecuteNonQuery();
@@ -406,9 +406,9 @@ namespace SabreTools
id = (long)sslc.ExecuteScalar();
}
squery = "INSERT INTO data (id, key, value) VALUES (\"" + id + "\", \"crc\", \"" + rom.HashData.CRC + "\"),"
+ " (\"" + id + "\", \"md5\", \"" + rom.HashData.MD5 + "\"),"
+ " (\"" + id + "\", \"sha1\", \"" + rom.HashData.SHA1 + "\"),"
squery = "INSERT INTO data (id, key, value) VALUES (\"" + id + "\", \"crc\", \"" + rom.CRC + "\"),"
+ " (\"" + id + "\", \"md5\", \"" + rom.MD5 + "\"),"
+ " (\"" + id + "\", \"sha1\", \"" + rom.SHA1 + "\"),"
+ " (\"" + id + "\", \"dat\", \"" + key + "\"),"
+ " (\"" + id + "\", \"exists\", \"false\")";
using (SqliteCommand sslc = new SqliteCommand(squery, dbc))
@@ -451,7 +451,7 @@ namespace SabreTools
if (datRootDats.Contains(input.ToLowerInvariant()))
{
string fullpath = Path.GetFullPath(datRootDats[datRootDats.IndexOf(input.ToLowerInvariant())]);
string sha1 = FileTools.GetSingleFileInfo(fullpath).HashData.SHA1;
string sha1 = FileTools.GetSingleFileInfo(fullpath).SHA1;
foundDats.Add(sha1, fullpath);
}
else

View File

@@ -57,13 +57,13 @@ namespace SabreTools
private static void InitDir2Dat(List<string> inputs)
{
// Create a simple Dat output
Dat datdata = new Dat()
DatFile datdata = new DatFile()
{
FileName = Path.GetFileName(inputs[0]) + " Dir2Dat",
Name = Path.GetFileName(inputs[0]) + " Dir2Dat",
Description = Path.GetFileName(inputs[0]) + " Dir2Dat",
OutputFormat = OutputFormat.Xml,
Files = new Dictionary<string, List<Rom>>(),
Files = new Dictionary<string, List<DatItem>>(),
};
Logger logger = new Logger(false, "");
@@ -73,7 +73,7 @@ namespace SabreTools
DATFromDir dfd = new DATFromDir(input, datdata, false /* noMD5 */, false /* noSHA1 */, true /* bare */, false /* archivesAsFiles */,
true /* enableGzip */, false /* addBlanks */, false /* addDate */, "__temp__" /* tempDir */, 4 /* maxDegreeOfParallelism */, _logger);
dfd.Start();
DatTools.WriteDatfile(dfd.DatData, "", logger);
DatFile.WriteDatfile(dfd.DatData, "", logger);
}
logger.Close();
}

View File

@@ -3,436 +3,6 @@ using System.Collections.Generic;
namespace SabreTools.Helper
{
#region Hash-to-Dat structs [Currently Unused]
/* Thought experiment
So, here's a connundrum: Should the internal structure of how DATs work (down to the hash level) mirror
how people see it (Dat to multiple games, game to multiple roms, rom to single hash) or
should it more closely mirror real life (Hash to multiple roms, rom to multiple games, game to single DAT)
If I use the "how people see it":
Things are pretty much how they are now with redundant data and the like
It makes sense to write things out to file, though. And life is easier when output is easier.
No code changes (big plus!)
If I use the "how it is":
Less data is likely to be mirrored
Refs to DAT files are possible so that there aren't duplicates
A lot of code will have to change...
*/
/// <summary>
/// Intermediate struct for holding and processing Hash data (NEW SYSTEM)
/// </summary>
public struct HashData : IEquatable<HashData>
{
public long Size;
public byte[] CRC;
public byte[] MD5;
public byte[] SHA1;
public List<RomData> Roms;
public bool Equals(HashData other)
{
return this.Equals(other, false);
}
public bool Equals(HashData other, bool IsDisk)
{
bool equals = false;
if (!IsDisk &&
((this.MD5 == null || other.MD5 == null) || this.MD5 == other.MD5) &&
((this.SHA1 == null || other.SHA1 == null) || this.SHA1 == other.SHA1))
{
equals = true;
}
else if (!IsDisk &&
(this.Size == other.Size) &&
((this.CRC == null || other.CRC != null) || this.CRC == other.CRC) &&
((this.MD5 == null || other.MD5 == null) || this.MD5 == other.MD5) &&
((this.SHA1 == null || other.SHA1 == null) || this.SHA1 == other.SHA1))
{
equals = true;
}
return equals;
}
}
/// <summary>
/// Intermediate struct for holding and processing Rom data (NEW SYSTEM)
/// </summary>
public struct RomData
{
public string Name;
public ItemType Type;
public bool Nodump;
public string Date;
public DupeType DupeType;
public MachineData Machine;
}
/// <summary>
/// Intermediate struct for holding and processing Game/Machine data (NEW SYSTEM)
/// </summary>
public struct MachineData
{
// Data specific to Machine/Game
public string Name;
public string Comment;
public string Description;
public string Year;
public string Manufacturer;
public string RomOf;
public string CloneOf;
public string SampleOf;
public string SourceFile;
public bool IsBios;
public string Board;
public string RebuildTo;
public bool TorrentZipped;
// Data specific to the source of the Machine/Game
public int SystemID;
public string System;
public int SourceID;
public string Source;
}
/// <summary>
/// Intermediate struct for holding and processing DAT data (NEW SYSTEM)
/// </summary>
public struct DatData
{
// Data common to most DAT types
public string FileName;
public string Name;
public string Description;
public string RootDir;
public string Category;
public string Version;
public string Date;
public string Author;
public string Email;
public string Homepage;
public string Url;
public string Comment;
public string Header;
public string Type; // Generally only used for SuperDAT
public ForceMerging ForceMerging;
public ForceNodump ForceNodump;
public ForcePacking ForcePacking;
public OutputFormat OutputFormat;
public bool MergeRoms;
public List<HashData> Hashes;
// Data specific to the Miss DAT type
public bool UseGame;
public string Prefix;
public string Postfix;
public bool Quotes;
public string RepExt;
public string AddExt;
public bool GameName;
public bool Romba;
public bool? XSV; // true for tab-deliminated output, false for comma-deliminated output
// Statistical data related to the DAT
public long RomCount;
public long DiskCount;
public long TotalSize;
public long CRCCount;
public long MD5Count;
public long SHA1Count;
public long NodumpCount;
}
#endregion
#region Dat-to-Hash structs
/// <summary>
/// Intermediate struct for holding and processing hash data
/// </summary>
public struct Hash : IEquatable<Hash>
{
public long Size;
public string CRC;
public string MD5;
public string SHA1;
public bool Equals(Hash other)
{
return this.Equals(other, false);
}
public bool Equals(Hash other, bool IsDisk)
{
bool equals = false;
if (IsDisk &&
((String.IsNullOrEmpty(this.MD5) || String.IsNullOrEmpty(other.MD5)) || this.MD5 == other.MD5) &&
((String.IsNullOrEmpty(this.SHA1) || String.IsNullOrEmpty(other.SHA1)) || this.SHA1 == other.SHA1))
{
equals = true;
}
else if (!IsDisk &&
(this.Size == other.Size) &&
((String.IsNullOrEmpty(this.CRC) || String.IsNullOrEmpty(other.CRC)) || this.CRC == other.CRC) &&
((String.IsNullOrEmpty(this.MD5) || String.IsNullOrEmpty(other.MD5)) || this.MD5 == other.MD5) &&
((String.IsNullOrEmpty(this.SHA1) || String.IsNullOrEmpty(other.SHA1)) || this.SHA1 == other.SHA1))
{
equals = true;
}
return equals;
}
}
/// <summary>
/// Intermediate struct for holding and processing rom data
/// </summary>
public struct Rom : IComparable, IEquatable<Rom>
{
public Machine Machine;
public string Name;
public ItemType Type;
public Hash HashData;
public DupeType Dupe;
public bool Nodump;
public string Date;
public SourceMetadata Metadata;
// Non rom or disk
public string Region;
public string Language;
public bool? Default;
public string Description;
public int CompareTo(object obj)
{
int ret = 0;
try
{
Rom comp = (Rom)obj;
if (this.Machine.Name == comp.Machine.Name)
{
if (this.Name == comp.Name)
{
ret = (this.Equals(comp) ? 0 : 1);
}
ret = String.Compare(this.Name, comp.Name);
}
ret = String.Compare(this.Machine.Name, comp.Machine.Name);
}
catch
{
ret = 1;
}
return ret;
}
public bool Equals(Rom other)
{
bool dupefound = false;
// If either is a nodump, it's never a match
if (this.Nodump || other.Nodump)
{
return dupefound;
}
if (this.Type == ItemType.Rom && other.Type == ItemType.Rom)
{
dupefound = this.HashData.Equals(other.HashData, false);
}
else if (this.Type == ItemType.Disk && other.Type == ItemType.Disk)
{
dupefound = this.HashData.Equals(other.HashData, true);
}
return dupefound;
}
}
/// <summary>
/// Intermediate metadata kept with a RomData object representing source information
/// </summary>
public struct SourceMetadata
{
public int SystemID;
public string System;
public int SourceID;
public string Source;
}
/// <summary>
/// Intermediate struct for holding and processing Rom/Machine data
/// </summary>
public struct Machine : IEquatable<Machine>
{
public string Name;
public string Comment;
public string Description;
public string Year;
public string Manufacturer;
public string RomOf;
public string CloneOf;
public string SampleOf;
public string SourceFile;
public bool IsBios;
public string Board;
public string RebuildTo;
public bool TorrentZipped;
public bool Equals(Machine other)
{
if (this.Name == other.Name)
{
return true;
}
return false;
}
}
/// <summary>
/// Intermediate struct for holding DAT information
/// </summary>
public struct Dat : ICloneable
{
// Data common to most DAT types
public string FileName;
public string Name;
public string Description;
public string RootDir;
public string Category;
public string Version;
public string Date;
public string Author;
public string Email;
public string Homepage;
public string Url;
public string Comment;
public string Header;
public string Type; // Generally only used for SuperDAT
public ForceMerging ForceMerging;
public ForceNodump ForceNodump;
public ForcePacking ForcePacking;
public OutputFormat OutputFormat;
public bool MergeRoms;
public Dictionary<string, List<Rom>> Files;
// Data specific to the Miss DAT type
public bool UseGame;
public string Prefix;
public string Postfix;
public bool Quotes;
public string RepExt;
public string AddExt;
public bool RemExt;
public bool GameName;
public bool Romba;
public bool? XSV; // true for tab-deliminated output, false for comma-deliminated output
// Statistical data related to the DAT
public long RomCount;
public long DiskCount;
public long TotalSize;
public long CRCCount;
public long MD5Count;
public long SHA1Count;
public long NodumpCount;
public object Clone()
{
return new Dat
{
FileName = this.FileName,
Name = this.Name,
Description = this.Description,
RootDir = this.RootDir,
Category = this.Category,
Version = this.Version,
Date = this.Date,
Author = this.Author,
Email = this.Email,
Homepage = this.Homepage,
Url = this.Url,
Comment = this.Comment,
Header = this.Header,
Type = this.Type,
ForceMerging = this.ForceMerging,
ForceNodump = this.ForceNodump,
ForcePacking = this.ForcePacking,
OutputFormat = this.OutputFormat,
MergeRoms = this.MergeRoms,
Files = this.Files,
UseGame = this.UseGame,
Prefix = this.Prefix,
Postfix = this.Postfix,
Quotes = this.Quotes,
RepExt = this.RepExt,
AddExt = this.AddExt,
RemExt = this.RemExt,
GameName = this.GameName,
Romba = this.Romba,
XSV = this.XSV,
RomCount = this.RomCount,
DiskCount = this.DiskCount,
TotalSize = this.TotalSize,
CRCCount = this.CRCCount,
MD5Count = this.MD5Count,
SHA1Count = this.SHA1Count,
NodumpCount = this.NodumpCount,
};
}
public object CloneHeader()
{
return new Dat
{
FileName = this.FileName,
Name = this.Name,
Description = this.Description,
RootDir = this.RootDir,
Category = this.Category,
Version = this.Version,
Date = this.Date,
Author = this.Author,
Email = this.Email,
Homepage = this.Homepage,
Url = this.Url,
Comment = this.Comment,
Header = this.Header,
Type = this.Type,
ForceMerging = this.ForceMerging,
ForceNodump = this.ForceNodump,
ForcePacking = this.ForcePacking,
OutputFormat = this.OutputFormat,
MergeRoms = this.MergeRoms,
Files = new Dictionary<string, List<Rom>>(),
UseGame = this.UseGame,
Prefix = this.Prefix,
Postfix = this.Postfix,
Quotes = this.Quotes,
RepExt = this.RepExt,
AddExt = this.AddExt,
RemExt = this.RemExt,
GameName = this.GameName,
Romba = this.Romba,
XSV = this.XSV,
};
}
}
#endregion
#region Skipper structs
/// <summary>

View File

@@ -18,7 +18,7 @@ namespace SabreTools
private string _tempDir;
// User specified inputs
private Dat _datdata;
private DatFile _datdata;
private bool _noMD5;
private bool _noSHA1;
private bool _bare;
@@ -32,7 +32,7 @@ namespace SabreTools
private Logger _logger;
// Public variables
public Dat DatData
public DatFile DatData
{
get { return _datdata; }
}
@@ -52,13 +52,13 @@ namespace SabreTools
/// <param name="tempDir">Name of the directory to create a temp folder in (blank is current directory)</param>
/// <param name="maxDegreeOfParallelism">Integer representing the maximum amount of parallelization to be used</param>
/// <param name="logger">Logger object for console and file output</param>
public DATFromDir(string basePath, Dat datdata, bool noMD5, bool noSHA1, bool bare, bool archivesAsFiles,
public DATFromDir(string basePath, DatFile datdata, bool noMD5, bool noSHA1, bool bare, bool archivesAsFiles,
bool enableGzip, bool addBlanks, bool addDate, string tempDir, int maxDegreeOfParallelism, Logger logger)
{
_basePath = Path.GetFullPath(basePath);
_datdata = datdata;
_datdata.Files = new Dictionary<string, List<Rom>>();
_datdata.Files.Add("null", new List<Rom>());
_datdata.Files = new Dictionary<string, List<DatItem>>();
_datdata.Files.Add("null", new List<DatItem>());
_noMD5 = noMD5;
_noSHA1 = noSHA1;
_bare = bare;
@@ -158,25 +158,7 @@ namespace SabreTools
}
_logger.Log("Adding blank empty folder: " + gamename);
Rom blankrom = new Rom
{
Name = romname,
Machine = new Machine
{
Name = gamename,
Description = gamename,
},
HashData = new Hash
{
Size = -1,
CRC = "null",
MD5 = "null",
SHA1 = "null",
},
};
_datdata.Files["null"].Add(blankrom);
_datdata.Files["null"].Add(new Rom(romname, gamename));
}
});
}
@@ -215,13 +197,13 @@ namespace SabreTools
if (rom.Name != null)
{
// Add the list if it doesn't exist already
string key = rom.HashData.Size + "-" + rom.HashData.CRC;
string key = rom.Size + "-" + rom.CRC;
lock (_datdata.Files)
{
if (!_datdata.Files.ContainsKey(key))
{
_datdata.Files.Add(key, new List<Rom>());
_datdata.Files.Add(key, new List<DatItem>());
}
_datdata.Files[key].Add(rom);
@@ -321,18 +303,33 @@ namespace SabreTools
/// Process a single file as a file (with found Rom data)
/// </summary>
/// <param name="item">File to be added</param>
/// <param name="rom">Rom data to be used to write to file</param>
/// <param name="item">Rom data to be used to write to file</param>
/// <param name="basepath">Path the represents the parent directory</param>
/// <param name="parent">Parent game to be used</param>
private void ProcessFileHelper(string item, Rom rom, string basepath, string parent)
private void ProcessFileHelper(string item, DatItem datItem, string basepath, string parent)
{
// If the datItem isn't a Rom or Disk, return
if (datItem.Type != ItemType.Rom && datItem.Type != ItemType.Disk)
{
return;
}
string key = "";
if (datItem.Type == ItemType.Rom)
{
key = ((Rom)datItem).Size + "-" + ((Rom)datItem).CRC;
}
else
{
key = ((Disk)datItem).MD5;
}
// Add the list if it doesn't exist already
string key = rom.HashData.Size + "-" + rom.HashData.CRC;
lock (_datdata.Files)
{
if (!_datdata.Files.ContainsKey(key))
{
_datdata.Files.Add(key, new List<Rom>());
_datdata.Files.Add(key, new List<DatItem>());
}
}
@@ -406,17 +403,14 @@ namespace SabreTools
}
// Update rom information
rom.Machine = new Machine
{
Name = gamename,
Description = gamename,
};
rom.Name = romname;
datItem.Name = romname;
datItem.MachineName = gamename;
datItem.MachineDescription = gamename;
// Add the file information to the DAT
lock (_datdata.Files)
{
_datdata.Files[key].Add(rom);
_datdata.Files[key].Add(datItem);
}
_logger.User("File added: " + romname + Environment.NewLine);

View File

@@ -0,0 +1,91 @@
namespace SabreTools.Helper
{
public class Archive : DatItem
{
#region Constructors
/// <summary>
/// Create a default, empty Archive object
/// </summary>
public Archive()
{
_name = "";
_itemType = ItemType.Archive;
}
/// <summary>
/// Create a new Archive object with the included information
/// </summary>
/// <param name="name">Name of the item, including extension</param>
public Archive(string name)
{
_name = name;
_itemType = ItemType.Archive;
}
/// <summary>
/// Create a new Archive object with the included information
/// </summary>
/// <param name="name">Name of the item, including extension</param>
/// <param name="machineName">Name for the machine/game</param>
/// <param name="comment">Comment for the machine/game</param>
/// <param name="machineDescription">Description for the machine/game</param>
/// <param name="year">Year for the machine/game</param>
/// <param name="manufacturer">Manufacturer name for the machine/game</param>
/// <param name="romOf">Set that this machine/game is a rom of</param>
/// <param name="cloneOf">Set that this machine/game is a clone of</param>
/// <param name="sampleOf">Set that this machine/game is a sample of</param>
/// <param name="sourceFile">Source file for the machine/game</param>
/// <param name="isBios">True if this game is a BIOS, false otherwise</param>
/// <param name="board">Name of the board for this machine/game</param>
/// <param name="rebuildTo">Name of the game to rebuild to</param>
/// <param name="systemId">System ID to be associated with</param>
/// <param name="systemName">System Name to be associated with</param>
/// <param name="sourceId">Source ID to be associated with</param>
/// <param name="sourceName">Source Name to be associated with</param>
public Archive(string name, string machineName, string comment, string machineDescription, string year,
string manufacturer, string romOf, string cloneOf, string sampleOf, string sourceFile, bool isBios, string board, string rebuildTo,
int systemId, string systemName, int sourceId, string sourceName)
{
_name = name;
_itemType = ItemType.Archive;
_machineName = machineName;
_comment = comment;
_machineDescription = machineDescription;
_year = year;
_manufacturer = manufacturer;
_romOf = romOf;
_cloneOf = cloneOf;
_sampleOf = sampleOf;
_sourceFile = sourceFile;
_isBios = isBios;
_board = board;
_rebuildTo = rebuildTo;
_systemId = systemId;
_systemName = systemName;
_sourceId = sourceId;
_sourceName = sourceName;
}
#endregion
#region Comparision Methods
public override bool Equals(DatItem other)
{
// If we don't have an archive, return false
if (_itemType != other.Type)
{
return false;
}
// Otherwise, treat it as an archive
Archive newOther = (Archive)other;
// If the archive information matches
return (_name == newOther.Name);
}
#endregion
}
}

View File

@@ -0,0 +1,121 @@
namespace SabreTools.Helper
{
public class BiosSet : DatItem
{
#region Private instance variables
private string _description;
private bool? _default;
#endregion
#region Publicly facing variables
public string Description
{
get { return _description; }
set { _description = value; }
}
public bool? Default
{
get { return _default; }
set { _default = value; }
}
#endregion
#region Constructors
/// <summary>
/// Create a default, empty Sample object
/// </summary>
public BiosSet()
{
_name = "";
_itemType = ItemType.BiosSet;
}
/// <summary>
/// Create a new Sample object with the included information
/// </summary>
/// <param name="name">Name of the item, including extension</param>
/// <param name="description">Description of the Bios set item</param>
/// <param name="default">True if this is the default BIOS, false if it is not, null for undefined</param>
public BiosSet(string name, string description, bool? @default)
{
_name = name;
_itemType = ItemType.BiosSet;
_description = description;
_default = @default;
}
/// <summary>
/// Create a new Sample object with the included information
/// </summary>
/// <param name="name">Name of the item, including extension</param>
/// <param name="description">Description of the Bios set item</param>
/// <param name="default">True if this is the default BIOS, false if it is not, null for undefined</param>
/// <param name="machineName">Name for the machine/game</param>
/// <param name="comment">Comment for the machine/game</param>
/// <param name="machineDescription">Description for the machine/game</param>
/// <param name="year">Year for the machine/game</param>
/// <param name="manufacturer">Manufacturer name for the machine/game</param>
/// <param name="romOf">Set that this machine/game is a rom of</param>
/// <param name="cloneOf">Set that this machine/game is a clone of</param>
/// <param name="sampleOf">Set that this machine/game is a sample of</param>
/// <param name="sourceFile">Source file for the machine/game</param>
/// <param name="isBios">True if this game is a BIOS, false otherwise</param>
/// <param name="board">Name of the board for this machine/game</param>
/// <param name="rebuildTo">Name of the game to rebuild to</param>
/// <param name="systemId">System ID to be associated with</param>
/// <param name="systemName">System Name to be associated with</param>
/// <param name="sourceId">Source ID to be associated with</param>
/// <param name="sourceName">Source Name to be associated with</param>
public BiosSet(string name, string description, bool? @default, string machineName, string comment, string machineDescription, string year,
string manufacturer, string romOf, string cloneOf, string sampleOf, string sourceFile, bool isBios, string board, string rebuildTo,
int systemId, string systemName, int sourceId, string sourceName)
{
_name = name;
_itemType = ItemType.BiosSet;
_description = description;
_default = @default;
_machineName = machineName;
_comment = comment;
_machineDescription = machineDescription;
_year = year;
_manufacturer = manufacturer;
_romOf = romOf;
_cloneOf = cloneOf;
_sampleOf = sampleOf;
_sourceFile = sourceFile;
_isBios = isBios;
_board = board;
_rebuildTo = rebuildTo;
_systemId = systemId;
_systemName = systemName;
_sourceId = sourceId;
_sourceName = sourceName;
}
#endregion
#region Comparision Methods
public override bool Equals(DatItem other)
{
// If we don't have a biosset, return false
if (_itemType != other.Type)
{
return false;
}
// Otherwise, treat it as a biosset
BiosSet newOther = (BiosSet)other;
// If the archive information matches
return (_name == newOther.Name && _description == newOther.Description && _default == newOther.Default);
}
#endregion
}
}

View File

@@ -0,0 +1,784 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace SabreTools.Helper
{
public abstract class DatItem : IEquatable<DatItem>, IComparable<DatItem>
{
#region Protected instance variables
// Standard item information
protected string _name;
protected ItemType _itemType;
protected DupeType _dupeType;
// Machine information
protected string _machineName;
protected string _comment;
protected string _machineDescription;
protected string _year;
protected string _manufacturer;
protected string _romOf;
protected string _cloneOf;
protected string _sampleOf;
protected string _sourceFile;
protected bool _isBios;
protected string _board;
protected string _rebuildTo;
// Source metadata information
protected int _systemId;
protected string _systemName;
protected int _sourceId;
protected string _sourceName;
#endregion
#region Publicly facing variables
// Standard item information
public string Name
{
get { return _name; }
set { _name = value; }
}
public ItemType Type
{
get { return _itemType; }
set { _itemType = value; }
}
public DupeType Dupe
{
get { return _dupeType; }
set { _dupeType = value; }
}
// Machine information
public string MachineName
{
get { return _machineName; }
set { _machineName = value; }
}
public string Comment
{
get { return _comment; }
set { _comment = value; }
}
public string MachineDescription
{
get { return _machineDescription; }
set { _machineDescription = value; }
}
public string Year
{
get { return _year; }
set { _year = value; }
}
public string Manufacturer
{
get { return _manufacturer; }
set { _manufacturer = value; }
}
public string RomOf
{
get { return _romOf; }
set { _romOf = value; }
}
public string CloneOf
{
get { return _cloneOf; }
set { _cloneOf = value; }
}
public string SampleOf
{
get { return _sampleOf; }
set { _sampleOf = value; }
}
public string SourceFile
{
get { return _sourceFile; }
set { _sourceFile = value; }
}
public bool IsBios
{
get { return _isBios; }
set { _isBios = value; }
}
public string Board
{
get { return _board; }
set { _board = value; }
}
public string RebuildTo
{
get { return _rebuildTo; }
set { _rebuildTo = value; }
}
// Source metadata information
public int SystemID
{
get { return _systemId; }
set { _systemId = value; }
}
public string System
{
get { return _systemName; }
set { _systemName = value; }
}
public int SourceID
{
get { return _sourceId; }
set { _sourceId = value; }
}
public string Source
{
get { return _sourceName; }
set { _sourceName = value; }
}
#endregion
#region Comparision Methods
public int CompareTo(DatItem other)
{
int ret = 0;
try
{
if (_name == other.Name)
{
ret = (this.Equals(other) ? 0 : 1);
}
ret = String.Compare(_name, other.Name);
}
catch
{
ret = 1;
}
return ret;
}
public abstract bool Equals(DatItem other);
/// <summary>
/// Determine if an item is a duplicate using partial matching logic
/// </summary>
/// <param name="lastItem">DatItem to use as a baseline</param>
/// <param name="logger">Logger object for console and/or file output</param>
/// <returns>True if the roms are duplicates, false otherwise</returns>
public bool IsDuplicate(DatItem lastItem, Logger logger)
{
bool dupefound = this.Equals(lastItem);
// More wonderful SHA-1 logging that has to be done
if (_itemType == ItemType.Rom)
{
if (((Rom)this).SHA1 == ((Rom)lastItem).SHA1 && ((Rom)this).Size != ((Rom)lastItem).Size)
{
logger.User("SHA-1 mismatch - Hash: " + ((Rom)this).SHA1);
}
}
return dupefound;
}
/// <summary>
/// Return the duplicate status of two items
/// </summary>
/// <param name="lastItem">DatItem to check against</param>
/// <param name="logger">Logger object for console and/or file output</param>
/// <returns>The DupeType corresponding to the relationship between the two</returns>
public DupeType GetDuplicateStatus(DatItem lastItem, Logger logger)
{
DupeType output = DupeType.None;
// If we don't have a duplicate at all, return none
if (!this.IsDuplicate(lastItem, logger))
{
return output;
}
// If the duplicate is external already or should be, set it
if (lastItem.Dupe >= DupeType.ExternalHash || lastItem.SystemID != this.SystemID || lastItem.SourceID != this.SourceID)
{
if (lastItem.MachineName == this.MachineName && lastItem.Name == this.Name)
{
output = DupeType.ExternalAll;
}
else
{
output = DupeType.ExternalHash;
}
}
// Otherwise, it's considered an internal dupe
else
{
if (lastItem.MachineName == this.MachineName && lastItem.Name == this.Name)
{
output = DupeType.InternalAll;
}
else
{
output = DupeType.InternalHash;
}
}
return output;
}
#endregion
#region Sorting and merging
/// <summary>
/// Determine if a rom should be included based on filters
/// </summary>
/// <param name="itemdata">User supplied item to check</param>
/// <param name="gamename">Name of the game to match (can use asterisk-partials)</param>
/// <param name="romname">Name of the rom to match (can use asterisk-partials)</param>
/// <param name="romtype">Type of the rom to match</param>
/// <param name="sgt">Find roms greater than or equal to this size</param>
/// <param name="slt">Find roms less than or equal to this size</param>
/// <param name="seq">Find roms equal to this size</param>
/// <param name="crc">CRC of the rom to match (can use asterisk-partials)</param>
/// <param name="md5">MD5 of the rom to match (can use asterisk-partials)</param>
/// <param name="sha1">SHA-1 of the rom to match (can use asterisk-partials)</param>
/// <param name="nodump">Select roms with nodump status as follows: null (match all), true (match Nodump only), false (exclude Nodump)</param>
/// <param name="logger">Logging object for console and file output</param>
/// <returns>Returns true if it should be included, false otherwise</returns>
public static bool Filter(DatItem itemdata, string gamename, string romname, string romtype, long sgt,
long slt, long seq, string crc, string md5, string sha1, bool? nodump, Logger logger)
{
// Take care of Rom and Disk specific differences
if (itemdata.Type == ItemType.Rom)
{
Rom rom = (Rom)itemdata;
// Filter on nodump status
if (nodump == true && !rom.Nodump)
{
return false;
}
if (nodump == false && rom.Nodump)
{
return false;
}
// Filter on rom size
if (seq != -1 && rom.Size != seq)
{
return false;
}
else
{
if (sgt != -1 && rom.Size < sgt)
{
return false;
}
if (slt != -1 && rom.Size > slt)
{
return false;
}
}
// Filter on crc
if (!String.IsNullOrEmpty(crc))
{
if (crc.StartsWith("*") && crc.EndsWith("*"))
{
if (!rom.CRC.ToLowerInvariant().Contains(crc.ToLowerInvariant().Replace("*", "")))
{
return false;
}
}
else if (crc.StartsWith("*"))
{
if (!rom.CRC.EndsWith(crc.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else if (crc.EndsWith("*"))
{
if (!rom.CRC.StartsWith(crc.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else
{
if (!String.Equals(rom.CRC, crc, StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
}
// Filter on md5
if (!String.IsNullOrEmpty(md5))
{
if (md5.StartsWith("*") && md5.EndsWith("*"))
{
if (!rom.MD5.ToLowerInvariant().Contains(md5.ToLowerInvariant().Replace("*", "")))
{
return false;
}
}
else if (md5.StartsWith("*"))
{
if (!rom.MD5.EndsWith(md5.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else if (md5.EndsWith("*"))
{
if (!rom.MD5.StartsWith(md5.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else
{
if (!String.Equals(rom.MD5, md5, StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
}
// Filter on sha1
if (!String.IsNullOrEmpty(sha1))
{
if (sha1.StartsWith("*") && sha1.EndsWith("*"))
{
if (!rom.SHA1.ToLowerInvariant().Contains(sha1.ToLowerInvariant().Replace("*", "")))
{
return false;
}
}
else if (sha1.StartsWith("*"))
{
if (!rom.SHA1.EndsWith(sha1.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else if (sha1.EndsWith("*"))
{
if (!rom.SHA1.StartsWith(sha1.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else
{
if (!String.Equals(rom.SHA1, sha1, StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
}
}
else if (itemdata.Type == ItemType.Disk)
{
Disk rom = (Disk)itemdata;
// Filter on nodump status
if (nodump == true && !rom.Nodump)
{
return false;
}
if (nodump == false && rom.Nodump)
{
return false;
}
// Filter on md5
if (!String.IsNullOrEmpty(md5))
{
if (md5.StartsWith("*") && md5.EndsWith("*"))
{
if (!rom.MD5.ToLowerInvariant().Contains(md5.ToLowerInvariant().Replace("*", "")))
{
return false;
}
}
else if (md5.StartsWith("*"))
{
if (!rom.MD5.EndsWith(md5.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else if (md5.EndsWith("*"))
{
if (!rom.MD5.StartsWith(md5.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else
{
if (!String.Equals(rom.MD5, md5, StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
}
// Filter on sha1
if (!String.IsNullOrEmpty(sha1))
{
if (sha1.StartsWith("*") && sha1.EndsWith("*"))
{
if (!rom.SHA1.ToLowerInvariant().Contains(sha1.ToLowerInvariant().Replace("*", "")))
{
return false;
}
}
else if (sha1.StartsWith("*"))
{
if (!rom.SHA1.EndsWith(sha1.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else if (sha1.EndsWith("*"))
{
if (!rom.SHA1.StartsWith(sha1.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else
{
if (!String.Equals(rom.SHA1, sha1, StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
}
}
// Filter on game name
if (!String.IsNullOrEmpty(gamename))
{
if (gamename.StartsWith("*") && gamename.EndsWith("*"))
{
if (!itemdata.MachineName.ToLowerInvariant().Contains(gamename.ToLowerInvariant().Replace("*", "")))
{
return false;
}
}
else if (gamename.StartsWith("*"))
{
if (!itemdata.MachineName.EndsWith(gamename.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else if (gamename.EndsWith("*"))
{
if (!itemdata.MachineName.StartsWith(gamename.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else
{
if (!String.Equals(itemdata.MachineName, gamename, StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
}
// Filter on rom name
if (!String.IsNullOrEmpty(romname))
{
if (romname.StartsWith("*") && romname.EndsWith("*"))
{
if (!itemdata.Name.ToLowerInvariant().Contains(romname.ToLowerInvariant().Replace("*", "")))
{
return false;
}
}
else if (romname.StartsWith("*"))
{
if (!itemdata.Name.EndsWith(romname.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else if (romname.EndsWith("*"))
{
if (!itemdata.Name.StartsWith(romname.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else
{
if (!String.Equals(itemdata.Name, romname, StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
}
// Filter on rom type
if (String.IsNullOrEmpty(romtype) && itemdata.Type != ItemType.Rom && itemdata.Type != ItemType.Disk)
{
return false;
}
if (!String.IsNullOrEmpty(romtype) && !String.Equals(itemdata.Type.ToString(), romtype, StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
return true;
}
/// <summary>
/// Merge an arbitrary set of ROMs based on the supplied information
/// </summary>
/// <param name="infiles">List of File objects representing the roms to be merged</param>
/// <param name="logger">Logger object for console and/or file output</param>
/// <returns>A List of RomData objects representing the merged roms</returns>
public static List<DatItem> Merge(List<DatItem> infiles, Logger logger)
{
// Check for null or blank roms first
if (infiles == null || infiles.Count == 0)
{
return new List<DatItem>();
}
// Create output list
List<DatItem> outfiles = new List<DatItem>();
// Then deduplicate them by checking to see if data matches previous saved roms
foreach (DatItem file in infiles)
{
// If it's a nodump, add and skip
if (file.Type == ItemType.Rom && ((Rom)file).Nodump)
{
outfiles.Add(file);
continue;
}
else if (file.Type == ItemType.Disk && ((Disk)file).Nodump)
{
outfiles.Add(file);
continue;
}
// If it's the first rom in the list, don't touch it
if (outfiles.Count != 0)
{
// Check if the rom is a duplicate
DupeType dupetype = DupeType.None;
DatItem saveditem = new Rom();
int pos = -1;
for (int i = 0; i < outfiles.Count; i++)
{
DatItem lastrom = outfiles[i];
// Get the duplicate status
dupetype = file.GetDuplicateStatus(lastrom, logger);
// If it's a duplicate, skip adding it to the output but add any missing information
if (dupetype != DupeType.None)
{
// If we don't have a rom or disk, then just skip adding
if (file.Type != ItemType.Rom && file.Type != ItemType.Disk)
{
continue;
}
saveditem = lastrom;
pos = i;
// Roms have more infomration to save
if (file.Type == ItemType.Rom)
{
((Rom)saveditem).Size = ((Rom)saveditem).Size;
((Rom)saveditem).CRC = (String.IsNullOrEmpty(((Rom)saveditem).CRC) && !String.IsNullOrEmpty(((Rom)file).CRC)
? ((Rom)file).CRC
: ((Rom)saveditem).CRC);
((Rom)saveditem).MD5 = (String.IsNullOrEmpty(((Rom)saveditem).MD5) && !String.IsNullOrEmpty(((Rom)file).MD5)
? ((Rom)file).MD5
: ((Rom)saveditem).MD5);
((Rom)saveditem).SHA1 = (String.IsNullOrEmpty(((Rom)saveditem).SHA1) && !String.IsNullOrEmpty(((Rom)file).SHA1)
? ((Rom)file).SHA1
: ((Rom)saveditem).SHA1);
}
else
{
((Disk)saveditem).MD5 = (String.IsNullOrEmpty(((Disk)saveditem).MD5) && !String.IsNullOrEmpty(((Disk)file).MD5)
? ((Disk)file).MD5
: ((Disk)saveditem).MD5);
((Disk)saveditem).SHA1 = (String.IsNullOrEmpty(((Disk)saveditem).SHA1) && !String.IsNullOrEmpty(((Disk)file).SHA1)
? ((Disk)file).SHA1
: ((Disk)saveditem).SHA1);
}
saveditem.Dupe = dupetype;
// If the current system has a lower ID than the previous, set the system accordingly
if (file.SystemID < saveditem.SystemID)
{
saveditem.SystemID = file.SystemID;
saveditem.System = file.System;
saveditem.MachineName = file.MachineName;
saveditem.Name = file.Name;
}
// If the current source has a lower ID than the previous, set the source accordingly
if (file.SourceID < saveditem.SourceID)
{
saveditem.SourceID = file.SourceID;
saveditem.Source = file.Source;
saveditem.MachineName = file.MachineName;
saveditem.Name = file.Name;
}
break;
}
}
// If no duplicate is found, add it to the list
if (dupetype == DupeType.None)
{
outfiles.Add(file);
}
// Otherwise, if a new rom information is found, add that
else
{
outfiles.RemoveAt(pos);
outfiles.Insert(pos, saveditem);
}
}
else
{
outfiles.Add(file);
}
}
// Then return the result
return outfiles;
}
/// <summary>
/// List all duplicates found in a DAT based on a rom
/// </summary>
/// <param name="lastitem">Item to use as a base</param>
/// <param name="datdata">Dat to match against</param>
/// <param name="logger">Logger object for console and/or file output</param>
/// <param name="remove">True to remove matched roms from the input, false otherwise (default)</param>
/// <returns>List of matched DatItem objects</returns>
public static List<DatItem> GetDuplicates(DatItem lastitem, DatFile datdata, Logger logger, bool remove = false)
{
List<DatItem> output = new List<DatItem>();
// Check for an empty rom list first
if (datdata.Files == null || datdata.Files.Count == 0)
{
return output;
}
// Try to find duplicates
List<string> keys = datdata.Files.Keys.ToList();
foreach (string key in keys)
{
List<DatItem> roms = datdata.Files[key];
List<DatItem> left = new List<DatItem>();
foreach (DatItem rom in roms)
{
if (rom.IsDuplicate(lastitem, logger))
{
output.Add(rom);
}
else
{
left.Add(rom);
}
}
// If we're in removal mode, replace the list with the new one
if (remove)
{
datdata.Files[key] = left;
}
}
return output;
}
/// <summary>
/// Sort a list of File objects by SystemID, SourceID, Game, and Name (in order)
/// </summary>
/// <param name="roms">List of File objects representing the roms to be sorted</param>
/// <param name="norename">True if files are not renamed, false otherwise</param>
/// <returns>True if it sorted correctly, false otherwise</returns>
public static bool Sort(ref List<DatItem> roms, bool norename)
{
try
{
roms.Sort(delegate (DatItem x, DatItem y)
{
if (x.SystemID == y.SystemID)
{
if (x.SourceID == y.SourceID)
{
if (x.MachineName == y.MachineName)
{
if ((x.Type == ItemType.Rom || x.Type == ItemType.Disk) && (y.Type == ItemType.Rom || y.Type == ItemType.Disk))
{
if (Path.GetDirectoryName(x.Name) == Path.GetDirectoryName(y.Name))
{
return Style.CompareNumeric(Path.GetFileName(x.Name), Path.GetFileName(y.Name));
}
return Style.CompareNumeric(Path.GetDirectoryName(x.Name), Path.GetDirectoryName(y.Name));
}
else if ((x.Type == ItemType.Rom || x.Type == ItemType.Disk) && (y.Type != ItemType.Rom && y.Type != ItemType.Disk))
{
return -1;
}
else if ((x.Type != ItemType.Rom && x.Type != ItemType.Disk) && (y.Type == ItemType.Rom || y.Type == ItemType.Disk))
{
return 1;
}
else
{
if (Path.GetDirectoryName(x.Name) == Path.GetDirectoryName(y.Name))
{
return Style.CompareNumeric(Path.GetFileName(x.Name), Path.GetFileName(y.Name));
}
return Style.CompareNumeric(Path.GetDirectoryName(x.Name), Path.GetDirectoryName(y.Name));
}
}
return Style.CompareNumeric(x.MachineName, y.MachineName);
}
return (norename ? Style.CompareNumeric(x.MachineName, y.MachineName) : x.SourceID - y.SourceID);
}
return (norename ? Style.CompareNumeric(x.MachineName, y.MachineName) : x.SystemID - y.SystemID);
});
return true;
}
catch (Exception)
{
// Absorb the error
return false;
}
}
#endregion
}
}

View File

@@ -0,0 +1,152 @@
using System;
namespace SabreTools.Helper
{
public class Disk : DatItem
{
#region Private instance variables
// Disk information
protected string _md5;
protected string _sha1;
// private string _merge;
// private DiskStatus _romStatus;
protected bool _nodump;
#endregion
#region Publicly facing variables
// Disk information
public string MD5
{
get { return _md5; }
set { _md5 = value; }
}
public string SHA1
{
get { return _sha1; }
set { _sha1 = value; }
}
public bool Nodump
{
get { return _nodump; }
set { _nodump = value; }
}
#endregion
#region Constructors
/// <summary>
/// Create a default, empty Disk object
/// </summary>
public Disk()
{
_name = "";
_itemType = ItemType.Disk;
_dupeType = DupeType.None;
_nodump = false;
}
/// <summary>
/// Create a new Disk object with the included information
/// </summary>
/// <param name="name">Name of the item, including extension</param>
/// <param name="md5">String representation of the MD5</param>
/// <param name="sha1">String representation of the SHA-1</param>
/// <param name="nodump">True if the file is a nodump, false otherwise</param>
public Disk(string name, string md5, string sha1, bool nodump)
{
_name = name;
_itemType = ItemType.Disk;
_md5 = md5?.ToLowerInvariant();
_sha1 = sha1?.ToLowerInvariant();
_nodump = nodump;
}
/// <summary>
/// Create a new Disk object with the included information
/// </summary>
/// <param name="name">Name of the item, including extension</param>
/// <param name="md5">String representation of the MD5</param>
/// <param name="sha1">String representation of the SHA-1</param>
/// <param name="nodump">True if the file is a nodump, false otherwise</param>
/// <param name="machineName">Name for the machine/game</param>
/// <param name="comment">Comment for the machine/game</param>
/// <param name="machineDescription">Description for the machine/game</param>
/// <param name="year">Year for the machine/game</param>
/// <param name="manufacturer">Manufacturer name for the machine/game</param>
/// <param name="romOf">Set that this machine/game is a rom of</param>
/// <param name="cloneOf">Set that this machine/game is a clone of</param>
/// <param name="sampleOf">Set that this machine/game is a sample of</param>
/// <param name="sourceFile">Source file for the machine/game</param>
/// <param name="isBios">True if this game is a BIOS, false otherwise</param>
/// <param name="board">Name of the board for this machine/game</param>
/// <param name="rebuildTo">Name of the game to rebuild to</param>
/// <param name="systemId">System ID to be associated with</param>
/// <param name="systemName">System Name to be associated with</param>
/// <param name="sourceId">Source ID to be associated with</param>
/// <param name="sourceName">Source Name to be associated with</param>
public Disk(string name, string md5, string sha1, bool nodump, string machineName, string comment,
string machineDescription, string year, string manufacturer, string romOf, string cloneOf, string sampleOf, string sourceFile,
bool isBios, string board, string rebuildTo, int systemId, string systemName, int sourceId, string sourceName)
{
_name = name;
_itemType = ItemType.Disk;
_md5 = md5?.ToLowerInvariant();
_sha1 = sha1?.ToLowerInvariant();
_nodump = nodump;
_machineName = machineName;
_comment = comment;
_machineDescription = machineDescription;
_year = year;
_manufacturer = manufacturer;
_romOf = romOf;
_cloneOf = cloneOf;
_sampleOf = sampleOf;
_sourceFile = sourceFile;
_isBios = isBios;
_board = board;
_rebuildTo = rebuildTo;
_systemId = systemId;
_systemName = systemName;
_sourceId = sourceId;
_sourceName = sourceName;
}
#endregion
#region Comparision Methods
public override bool Equals(DatItem other)
{
bool dupefound = false;
// If we don't have a rom, return false
if (_itemType != other.Type)
{
return dupefound;
}
// Otherwise, treat it as a rom
Disk newOther = (Disk)other;
// If either is a nodump, it's never a match
if (_nodump || newOther.Nodump)
{
return dupefound;
}
if (((String.IsNullOrEmpty(_md5) || String.IsNullOrEmpty(newOther.MD5)) || this.MD5 == newOther.MD5) &&
((String.IsNullOrEmpty(this.SHA1) || String.IsNullOrEmpty(newOther.SHA1)) || this.SHA1 == newOther.SHA1))
{
dupefound = true;
}
return dupefound;
}
#endregion
}
}

View File

@@ -0,0 +1,149 @@
namespace SabreTools.Helper
{
public class Release : DatItem
{
#region Private instance variables
private string _region;
private string _language;
private string _date;
private bool? _default;
#endregion
#region Publicly facing variables
public string Region
{
get { return _region; }
set { _region = value; }
}
public string Language
{
get { return _language; }
set { _language = value; }
}
public string Date
{
get { return _date; }
set { _date = value; }
}
public bool? Default
{
get { return _default; }
set { _default = value; }
}
#endregion
#region Constructors
/// <summary>
/// Create a default, empty Release object
/// </summary>
public Release()
{
_name = "";
_itemType = ItemType.Release;
_region = "";
_language = "";
_date = "";
_default = null;
}
/// <summary>
/// Create a new Release object with the included information
/// </summary>
/// <param name="name">Name of the item, including extension</param>
/// <param name="region">Region of the item</param>
/// <param name="language">Language of the item</param>
/// <param name="date">String representation of the Date</param>
/// <param name="default">True if this is the default BIOS, false if it is not, null for undefined</param>
public Release(string name, string region, string language, string date, bool? @default)
{
_name = name;
_itemType = ItemType.Release;
_region = region;
_language = language;
_date = date;
_default = @default;
}
/// <summary>
/// Create a new Release object with the included information
/// </summary>
/// <param name="name">Name of the item, including extension</param>
/// <param name="region">Region of the item</param>
/// <param name="language">Language of the item</param>
/// <param name="date">String representation of the Date</param>
/// <param name="default">True if this is the default BIOS, false if it is not, null for undefined</param>
/// <param name="machineName">Name for the machine/game</param>
/// <param name="comment">Comment for the machine/game</param>
/// <param name="machineDescription">Description for the machine/game</param>
/// <param name="year">Year for the machine/game</param>
/// <param name="manufacturer">Manufacturer name for the machine/game</param>
/// <param name="romOf">Set that this machine/game is a rom of</param>
/// <param name="cloneOf">Set that this machine/game is a clone of</param>
/// <param name="sampleOf">Set that this machine/game is a sample of</param>
/// <param name="sourceFile">Source file for the machine/game</param>
/// <param name="isBios">True if this game is a BIOS, false otherwise</param>
/// <param name="board">Name of the board for this machine/game</param>
/// <param name="rebuildTo">Name of the game to rebuild to</param>
/// <param name="systemId">System ID to be associated with</param>
/// <param name="systemName">System Name to be associated with</param>
/// <param name="sourceId">Source ID to be associated with</param>
/// <param name="sourceName">Source Name to be associated with</param>
public Release(string name, string region, string language, string date, bool? @default, string machineName, string comment,
string machineDescription, string year, string manufacturer, string romOf, string cloneOf, string sampleOf, string sourceFile,
bool isBios, string board, string rebuildTo, int systemId, string systemName, int sourceId, string sourceName)
{
_name = name;
_itemType = ItemType.Release;
_region = region;
_language = language;
_date = date;
_default = @default;
_machineName = machineName;
_comment = comment;
_machineDescription = machineDescription;
_year = year;
_manufacturer = manufacturer;
_romOf = romOf;
_cloneOf = cloneOf;
_sampleOf = sampleOf;
_sourceFile = sourceFile;
_isBios = isBios;
_board = board;
_rebuildTo = rebuildTo;
_systemId = systemId;
_systemName = systemName;
_sourceId = sourceId;
_sourceName = sourceName;
}
#endregion
#region Comparision Methods
public override bool Equals(DatItem other)
{
// If we don't have a release return false
if (_itemType != other.Type)
{
return false;
}
// Otherwise, treat it as a reease
Release newOther = (Release)other;
// If the archive information matches
return (_name == newOther.Name
&& _region == newOther.Region
&& _language == newOther.Language
&& _date == newOther.Date
&& _default == newOther.Default);
}
#endregion
}
}

View File

@@ -0,0 +1,175 @@
using System;
namespace SabreTools.Helper
{
public class Rom : Disk
{
#region Private instance variables
// Rom information
protected long _size;
protected string _crc;
private string _date;
#endregion
#region Publicly facing variables
// Rom information
public long Size
{
get { return _size; }
set { _size = value; }
}
public string CRC
{
get { return _crc; }
set { _crc = value; }
}
public string Date
{
get { return _date; }
set { _date = value; }
}
#endregion
#region Constructors
/// <summary>
/// Create a default, empty Rom object
/// </summary>
public Rom()
{
_name = "";
_itemType = ItemType.Rom;
_dupeType = DupeType.None;
_nodump = false;
_date = "";
}
/// <summary>
/// Create a "blank" Rom object
/// </summary>
/// <param name="name"></param>
/// <param name="machineName"></param>
public Rom(string name, string machineName) :
this(name, -1, "null", "null", "null", false, null, machineName, null, machineName, null, null, null, null, null, null, false, null, null, -1, null, -1, null)
{
}
/// <summary>
/// Create a new Rom object with the included information
/// </summary>
/// <param name="name">Name of the item, including extension</param>
/// <param name="size">Long size of the item</param>
/// <param name="crc">String representation of the CRC</param>
/// <param name="md5">String representation of the MD5</param>
/// <param name="sha1">String representation of the SHA-1</param>
/// <param name="nodump">True if the file is a nodump, false otherwise</param>
/// <param name="date">String representation of the Date</param>
public Rom(string name, long size, string crc, string md5, string sha1, bool nodump, string date)
{
_name = name;
_itemType = ItemType.Rom;
_size = size;
_crc = crc?.ToLowerInvariant();
_md5 = md5?.ToLowerInvariant();
_sha1 = sha1?.ToLowerInvariant();
_nodump = nodump;
_date = date;
}
/// <summary>
/// Create a new Rom object with the included information
/// </summary>
/// <param name="name">Name of the item, including extension</param>
/// <param name="size">Long size of the item</param>
/// <param name="crc">String representation of the CRC</param>
/// <param name="md5">String representation of the MD5</param>
/// <param name="sha1">String representation of the SHA-1</param>
/// <param name="nodump">True if the file is a nodump, false otherwise</param>
/// <param name="date">String representation of the Date</param>
/// <param name="machineName">Name for the machine/game</param>
/// <param name="comment">Comment for the machine/game</param>
/// <param name="machineDescription">Description for the machine/game</param>
/// <param name="year">Year for the machine/game</param>
/// <param name="manufacturer">Manufacturer name for the machine/game</param>
/// <param name="romOf">Set that this machine/game is a rom of</param>
/// <param name="cloneOf">Set that this machine/game is a clone of</param>
/// <param name="sampleOf">Set that this machine/game is a sample of</param>
/// <param name="sourceFile">Source file for the machine/game</param>
/// <param name="isBios">True if this game is a BIOS, false otherwise</param>
/// <param name="board">Name of the board for this machine/game</param>
/// <param name="rebuildTo">Name of the game to rebuild to</param>
/// <param name="systemId">System ID to be associated with</param>
/// <param name="systemName">System Name to be associated with</param>
/// <param name="sourceId">Source ID to be associated with</param>
/// <param name="sourceName">Source Name to be associated with</param>
public Rom(string name, long size, string crc, string md5, string sha1, bool nodump, string date, string machineName,
string comment, string machineDescription, string year, string manufacturer, string romOf, string cloneOf, string sampleOf,
string sourceFile, bool isBios, string board, string rebuildTo, int systemId, string systemName, int sourceId, string sourceName)
{
_name = name;
_itemType = ItemType.Rom;
_size = size;
_crc = crc?.ToLowerInvariant();
_md5 = md5?.ToLowerInvariant();
_sha1 = sha1?.ToLowerInvariant();
_nodump = nodump;
_date = date;
_machineName = machineName;
_comment = comment;
_machineDescription = machineDescription;
_year = year;
_manufacturer = manufacturer;
_romOf = romOf;
_cloneOf = cloneOf;
_sampleOf = sampleOf;
_sourceFile = sourceFile;
_isBios = isBios;
_board = board;
_rebuildTo = rebuildTo;
_systemId = systemId;
_systemName = systemName;
_sourceId = sourceId;
_sourceName = sourceName;
}
#endregion
#region Comparision Methods
public override bool Equals(DatItem other)
{
bool dupefound = false;
// If we don't have a rom, return false
if (_itemType != other.Type)
{
return dupefound;
}
// Otherwise, treat it as a rom
Rom newOther = (Rom)other;
// If either is a nodump, it's never a match
if (_nodump || newOther.Nodump)
{
return dupefound;
}
if ((this.Size == newOther.Size) &&
((String.IsNullOrEmpty(this.CRC) || String.IsNullOrEmpty(newOther.CRC)) || this.CRC == newOther.CRC) &&
((String.IsNullOrEmpty(this.MD5) || String.IsNullOrEmpty(newOther.MD5)) || this.MD5 == newOther.MD5) &&
((String.IsNullOrEmpty(this.SHA1) || String.IsNullOrEmpty(newOther.SHA1)) || this.SHA1 == newOther.SHA1))
{
dupefound = true;
}
return dupefound;
}
#endregion
}
}

View File

@@ -0,0 +1,91 @@
namespace SabreTools.Helper
{
public class Sample : DatItem
{
#region Constructors
/// <summary>
/// Create a default, empty Sample object
/// </summary>
public Sample()
{
_name = "";
_itemType = ItemType.Sample;
}
/// <summary>
/// Create a new Sample object with the included information
/// </summary>
/// <param name="name">Name of the item, including extension</param>
public Sample(string name)
{
_name = name;
_itemType = ItemType.Sample;
}
/// <summary>
/// Create a new Sample object with the included information
/// </summary>
/// <param name="name">Name of the item, including extension</param>
/// <param name="machineName">Name for the machine/game</param>
/// <param name="comment">Comment for the machine/game</param>
/// <param name="machineDescription">Description for the machine/game</param>
/// <param name="year">Year for the machine/game</param>
/// <param name="manufacturer">Manufacturer name for the machine/game</param>
/// <param name="romOf">Set that this machine/game is a rom of</param>
/// <param name="cloneOf">Set that this machine/game is a clone of</param>
/// <param name="sampleOf">Set that this machine/game is a sample of</param>
/// <param name="sourceFile">Source file for the machine/game</param>
/// <param name="isBios">True if this game is a BIOS, false otherwise</param>
/// <param name="board">Name of the board for this machine/game</param>
/// <param name="rebuildTo">Name of the game to rebuild to</param>
/// <param name="systemId">System ID to be associated with</param>
/// <param name="systemName">System Name to be associated with</param>
/// <param name="sourceId">Source ID to be associated with</param>
/// <param name="sourceName">Source Name to be associated with</param>
public Sample(string name, string machineName, string comment, string machineDescription, string year,
string manufacturer, string romOf, string cloneOf, string sampleOf, string sourceFile, bool isBios, string board, string rebuildTo,
int systemId, string systemName, int sourceId, string sourceName)
{
_name = name;
_itemType = ItemType.Sample;
_machineName = machineName;
_comment = comment;
_machineDescription = machineDescription;
_year = year;
_manufacturer = manufacturer;
_romOf = romOf;
_cloneOf = cloneOf;
_sampleOf = sampleOf;
_sourceFile = sourceFile;
_isBios = isBios;
_board = board;
_rebuildTo = rebuildTo;
_systemId = systemId;
_systemName = systemName;
_sourceId = sourceId;
_sourceName = sourceName;
}
#endregion
#region Comparision Methods
public override bool Equals(DatItem other)
{
// If we don't have a sample, return false
if (_itemType != other.Type)
{
return false;
}
// Otherwise, treat it as a sample
Sample newOther = (Sample)other;
// If the archive information matches
return (_name == newOther.Name);
}
#endregion
}
}

View File

@@ -1,472 +0,0 @@
using Mono.Data.Sqlite;
using SabreTools.Helper;
using System;
using System.Collections.Generic;
using System.IO;
namespace SabreTools
{
/// <summary>
/// Generate a DAT from the data in the database
/// </summary>
class Generate : IGenerate
{
// Private instance variables
private string _systems;
private string _sources;
private string _outDir;
private string _connectionString;
private bool _norename;
private bool _old;
// Private required variables
private Logger _logger;
/// <summary>
/// Initialize a Generate object with the given information
/// </summary>
/// <param name="systems">Comma-separated list of systems to be included in the DAT (blank means all)</param>
/// <param name="sources">Comma-separated list of sources to be included in the DAT (blank means all)</param>
/// <param name="outDir">The output folder where the generated DAT will be put; blank means the current directory</param>
/// <param name="connectionString">Connection string for SQLite</param>
/// <param name="logger">Logger object for file or console output</param>
/// <param name="norename">True if files should not be renamed with system and/or source in merged mode (default false)</param>
/// <param name="old">True if the output file should be in ClrMamePro format (default false)</param>
public Generate(string systems, string sources, string outDir, string connectionString, Logger logger, bool norename = false, bool old = false)
{
_systems = systems;
_sources = sources;
_connectionString = connectionString;
_norename = norename;
_old = old;
_logger = logger;
// Take care of special outfolder cases
_outDir = (outDir == "" ? Environment.CurrentDirectory + Path.DirectorySeparatorChar :
(!outDir.EndsWith(Path.DirectorySeparatorChar.ToString()) ? outDir + Path.DirectorySeparatorChar : outDir)
);
if (_outDir != "" && !Directory.Exists(_outDir))
{
Directory.CreateDirectory(_outDir);
}
}
/// <summary>
/// Generate a DAT file that is represented by the data in the Generate object.
/// </summary>
/// <returns>True if the file could be created, false otherwise</returns>
public bool Export()
{
// Check to see if the source is an import-only. If so, tell the user and exit
int id = 0;
if (_sources != "" && Int32.TryParse(_sources, out id) && id <= 14)
{
_logger.Warning("This source (" + id + ") is import-only so a DAT cannot be created. We apologize for the inconvenience.");
return false;
}
// Get the system name, if applicable
string systemname = "";
if (_systems != "")
{
string query = "SELECT manufacturer, system FROM systems WHERE id in (" + _systems + ")";
//string query = "SELECT manufacturer, name FROM system WHERE id in (" + _systems + ")";
using (SqliteConnection dbc = new SqliteConnection(_connectionString))
{
dbc.Open();
using (SqliteCommand slc = new SqliteCommand(query, dbc))
{
using (SqliteDataReader sldr = slc.ExecuteReader())
{
// If there are no games for this combination, return nothing
if (!sldr.HasRows)
{
_logger.Error("No system could be found with id in \"" + _systems + "\". Please check and try again.");
return false;
}
// Retrieve and build the system name from all retrieved
int tempsize = 0;
while (sldr.Read() && tempsize < 3)
{
systemname += (tempsize == 0 ?
sldr.GetString(0) + " - " + sldr.GetString(1) :
"; " + sldr.GetString(0) + " - " + sldr.GetString(1));
tempsize++;
}
// If there are more than 3 systems, just put "etc." on the end
if (sldr.Read())
{
systemname += "; etc.";
}
}
}
}
}
else
{
systemname = "ALL";
}
string sourcename = "";
if (_sources != "")
{
string query = "SELECT name FROM sources WHERE id in (" + _sources + ")";
//string query = "SELECT name FROM source WHERE id in (" + _sources + ")";
using (SqliteConnection dbc = new SqliteConnection(_connectionString))
{
dbc.Open();
using (SqliteCommand slc = new SqliteCommand(query, dbc))
{
using (SqliteDataReader sldr = slc.ExecuteReader())
{
// If there are no games for this combination, return nothing
if (!sldr.HasRows)
{
_logger.Error("No source could be found with id in \"" + _sources + "\". Please check and try again.");
return false;
}
// Retrieve and build the source name from all retrieved
int tempsize = 0;
while (sldr.Read() && tempsize < 3)
{
sourcename += (tempsize == 0 ? sldr.GetString(0) : "; " + sldr.GetString(0));
tempsize++;
}
// If there are more than 3 systems, just put "etc." on the end
if (sldr.Read())
{
sourcename += "; etc.";
}
}
}
}
}
else
{
sourcename = "Merged";
}
// Retrieve the list of processed roms
Dictionary<string, List<Rom>> dict = ProcessRoms();
// If the output is null, nothing was found so return false
if (dict.Count == 0)
{
return false;
}
// Create a name for the file based on the retrieved information
string version = DateTime.Now.ToString("yyyyMMddHHmmss");
string intname = systemname + " (" + sourcename + ")";
string datname = systemname + " (" + sourcename + " " + version + ")";
Dat datdata = new Dat
{
Name = intname,
Description = datname,
Version = version,
Date = version,
Category = "The Wizard of DATz",
Author = "The Wizard of DATz",
ForcePacking = ForcePacking.None,
OutputFormat = (_old ? OutputFormat.ClrMamePro : OutputFormat.Xml),
Files = dict,
};
return DatTools.WriteDatfile(datdata, _outDir, _logger);
}
/// <summary>
/// Preprocess the rom data that is to be included in the outputted DAT
/// </summary>
/// <returns>A List of Rom objects containing all information about the files</returns>
public Dictionary<string, List<Rom>> ProcessRoms()
{
Dictionary<string, List<Rom>> roms = new Dictionary<string, List<Rom>>();
// Check if we have listed sources or systems
bool sysmerged = (_systems == "" || _systems.Split(',').Length > 1);
bool srcmerged = (_sources == "" || _sources.Split(',').Length > 1);
bool merged = sysmerged || srcmerged;
// BEGIN COMMENT
string query = @"
SELECT DISTINCT systems.manufacturer AS manufacturer, systems.system AS system, systems.id AS systemid,
sources.name AS source, sources.url AS url, sources.id AS sourceid,
games.name AS game, files.name AS name, files.type AS type,
checksums.size AS size, checksums.crc AS crc, checksums.md5 AS md5, checksums.sha1 AS sha1,
files.lastupdated AS lastupdated
FROM systems
JOIN games
ON systems.id=games.system
JOIN sources
ON games.source=sources.id
JOIN files
ON games.id=files.setid
JOIN checksums
ON files.id=checksums.file" +
(_systems != "" || _sources != "" ? "\nWHERE" : "") +
(_sources != "" ? " sources.id in (" + _sources + ")" : "") +
(_systems != "" && _sources != "" ? " AND" : "") +
(_systems != "" ? " systems.id in (" + _systems + ")" : "") +
"\nORDER BY " +
(merged ? "checksums.size, checksums.crc, systems.id, sources.id, files.lastupdated DESC, checksums.md5, checksums.sha1"
: "systems.id, sources.id, games.name, files.name");
using (SqliteConnection dbc = new SqliteConnection(_connectionString))
{
dbc.Open();
using (SqliteCommand slc = new SqliteCommand(query, dbc))
{
using (SqliteDataReader sldr = slc.ExecuteReader())
{
// If there are no games for this combination, return nothing
if (!sldr.HasRows)
{
_logger.Error("No games could be found with those inputs. Please check and try again.");
return null;
}
// Retrieve and process the roms for merging
while (sldr.Read())
{
Rom temp = new Rom
{
Name = sldr.GetString(7),
Type = (sldr.GetString(8) == "disk" ? ItemType.Disk : ItemType.Rom),
Machine = new Machine
{
Name = sldr.GetString(6),
Manufacturer = sldr.GetString(0),
},
Metadata = new SourceMetadata
{
System = sldr.GetString(1),
SystemID = sldr.GetInt32(2),
Source = sldr.GetString(3),
SourceID = sldr.GetInt32(5),
},
HashData = new Hash
{
Size = sldr.GetInt64(9),
CRC = sldr.GetString(10),
MD5 = sldr.GetString(11),
SHA1 = sldr.GetString(12),
},
};
// Rename the game associated if it's still valid and we allow renames
if (merged && !_norename)
{
temp.Machine.Name = temp.Machine.Name +
(sysmerged ? " [" + temp.Machine.Manufacturer + " - " + temp.Metadata.System + "]" : "") +
(srcmerged ? " [" + temp.Metadata.Source + "]" : "");
}
string key = temp.HashData.Size + "-" + temp.HashData.CRC;
if (roms.ContainsKey(key))
{
roms[key].Add(temp);
}
else
{
List<Rom> templist = new List<Rom>();
templist.Add(temp);
roms.Add(key, templist);
}
}
}
}
}
// If we're in a merged mode, merge and then resort by the correct parameters
if (merged)
{
foreach (string key in roms.Keys)
{
roms[key] = RomTools.Merge(roms[key], _logger);
}
}
// END COMMENT
/*
// This block would replace the whole block above between BEGIN COMMENT and END COMMENT
string query = @"
SELECT hash.id AS id, hash.size AS size, hash.crc AS crc, hash.md5 AS md5, hash.sha1 AS sha1,
a.key AS key, a.value AS value,
source.id, source.name, source.url,
system.id, system.manufacturer, system.name
FROM hash
JOIN hashdata a
ON hash.id=a.hashid
JOIN hashdata b
ON a.hashid=b.hashid
JOIN gamesystem
ON b.value=gamesystem.game
JOIN gamesource
ON b.value=gamesource.game
JOIN system
ON gamesystem.systemid=system.id
JOIN source
ON gamesource.sourceid=source.id" +
(_systems != "" || _sources != "" ? "\nWHERE" : "") +
(_sources != "" ? " source.id in (" + _sources + ")" : "") +
(_systems != "" && _sources != "" ? " AND" : "") +
(_systems != "" ? " system.id in (" + _systems + ")" : "") +
"\nORDER BY hash.id";
using (SqliteConnection dbc = new SqliteConnection(_connectionString))
{
dbc.Open();
using (SqliteCommand slc = new SqliteCommand(query, dbc))
{
using (SqliteDataReader sldr = slc.ExecuteReader())
{
// If there are no games for this combination, return nothing
if (!sldr.HasRows)
{
_logger.Error("No games could be found with those inputs. Please check and try again.");
return null;
}
// Retrieve and process the roms for merging
int systemid = -1, sourceid = -1;
long lastid = -1, size = -1;
string name = "", game = "", type = "", manufacturer = "", system = "", source = "", url = "", crc = "", md5 = "", sha1 = "";
while (sldr.Read())
{
// If the hash is different than the last
if (lastid != -1 && sldr.GetInt64(0) != lastid)
{
Rom temp = new Rom
{
Manufacturer = manufacturer,
System = system,
SystemID = systemid,
Source = source,
URL = url,
SourceID = sourceid,
Game = game,
Name = name,
Type = type,
Size = size,
CRC = crc,
MD5 = md5,
SHA1 = sha1,
};
// Rename the game associated if it's still valid and we allow renames
if (merged && !_norename)
{
temp.Machine = temp.Machine +
(sysmerged ? " [" + temp.Manufacturer + " - " + temp.System + "]" : "") +
(srcmerged ? " [" + temp.Source + "]" : "");
}
string key = temp.Size + "-" + temp.CRC;
if (roms.ContainsKey(key))
{
roms[key].Add(temp);
}
else
{
List<Rom> templist = new List<Rom>();
templist.Add(temp);
roms.Add(key, templist);
}
// Reset the variables
game = "";
name = "";
type = "";
}
// Get all of the current ROM information
manufacturer = sldr.GetString(11);
system = sldr.GetString(12);
systemid = sldr.GetInt32(10);
source = sldr.GetString(8);
url = sldr.GetString(9);
sourceid = sldr.GetInt32(7);
size = sldr.GetInt64(1);
crc = sldr.GetString(2);
md5 = sldr.GetString(3);
sha1 = sldr.GetString(4);
switch (sldr.GetString(5))
{
case "game":
game = sldr.GetString(6);
break;
case "name":
name = sldr.GetString(6);
break;
case "type":
type = sldr.GetString(6);
break;
}
lastid = sldr.GetInt64(0);
}
}
}
}
// If we're in a merged mode, merge
if (merged)
{
foreach (string key in roms.Keys)
{
roms[key] = RomManipulation.Merge(roms[key]);
}
}
*/
/*
// THIS CODE SHOULD BE PUT IN WriteToDatFromDict
// Now check rename within games
string lastname = "", lastgame = "";
for (int i = 0; i < roms.Count; i++)
{
Rom rom = roms[i];
// Now relable any roms that have the same name inside of the same game
bool samename = false, samegame = false;
if (rom.Name != "")
{
samename = (lastname == rom.Name);
}
if (rom.Machine != "")
{
samegame = (lastgame == rom.Machine);
}
lastname = rom.Name;
lastgame = rom.Machine;
// If the name and set are the same, rename it with whatever is different
if (samename && samegame)
{
rom.Name = Regex.Replace(rom.Name, @"^(.*)(\..*)", "$1(" +
(rom.CRC != "" ? rom.CRC :
(rom.MD5 != "" ? rom.MD5 :
(rom.SHA1 != "" ? rom.SHA1 : "Alt"))) +
")$2");
}
// Assign back just in case
roms[i] = rom;
}
*/
return roms;
}
}
}

View File

@@ -144,7 +144,7 @@ namespace SabreTools
}
// Create the output DatData object
Dat datdata = new Dat
DatFile datdata = new DatFile
{
FileName = description,
Name = name,
@@ -173,7 +173,7 @@ namespace SabreTools
{
Int32.TryParse(sourcemap[hash], out tempSrcId);
}
DatTools.Parse(file, 0, tempSrcId, ref datdata, _logger);
DatFile.Parse(file, 0, tempSrcId, ref datdata, _logger);
}
// If the dictionary is empty for any reason, tell the user and exit
@@ -188,14 +188,14 @@ namespace SabreTools
List<string> keys = datdata.Files.Keys.ToList();
foreach (string key in keys)
{
List<Rom> temp = new List<Rom>();
List<Rom> newroms = datdata.Files[key];
List<DatItem> temp = new List<DatItem>();
List<DatItem> newroms = datdata.Files[key];
for (int i = 0; i < newroms.Count; i++)
{
Rom rom = newroms[i];
Rom rom = (Rom)newroms[i];
// In the case that the RomData is incomplete, skip it
if (rom.Name == null || rom.Machine.Name == null)
if (rom.Name == null || rom.MachineName == null)
{
continue;
}
@@ -209,27 +209,27 @@ namespace SabreTools
rom.Name = Regex.Replace(rom.Name, @"(.*) \.(.*)", "$1.$2");
// Run the name through the filters to make sure that it's correct
rom.Machine.Name = Style.NormalizeChars(rom.Machine.Name);
rom.Machine.Name = Style.RussianToLatin(rom.Machine.Name);
rom.Machine.Name = Style.SearchPattern(rom.Machine.Name);
rom.MachineName = Style.NormalizeChars(rom.MachineName);
rom.MachineName = Style.RussianToLatin(rom.MachineName);
rom.MachineName = Style.SearchPattern(rom.MachineName);
// WoD gets rid of anything past the first "(" or "[" as the name, we will do the same
string stripPattern = @"(([[(].*[\)\]] )?([^([]+))";
Regex stripRegex = new Regex(stripPattern);
Match stripMatch = stripRegex.Match(rom.Machine.Name);
rom.Machine.Name = stripMatch.Groups[1].Value;
Match stripMatch = stripRegex.Match(rom.MachineName);
rom.MachineName = stripMatch.Groups[1].Value;
rom.Machine.Name = rom.Machine.Name.TrimEnd().TrimStart();
rom.MachineName = rom.MachineName.TrimEnd().TrimStart();
if (!_norename)
{
rom.Machine.Name += " [" + sources[rom.Metadata.SourceID] + "]";
rom.MachineName += " [" + sources[rom.SourceID] + "]";
}
// If a game has source "0" it's Default. Make this Int32.MaxValue for sorting purposes
if (rom.Metadata.SourceID == 0)
if (rom.SourceID == 0)
{
rom.Metadata.SourceID = Int32.MaxValue;
rom.SourceID = Int32.MaxValue;
}
temp.Add(rom);
@@ -238,7 +238,7 @@ namespace SabreTools
}
// Then write out the file
DatTools.WriteDatfile(datdata, _outroot, _logger, _norename);
DatFile.WriteDatfile(datdata, _outroot, _logger, _norename);
return true;
}

View File

@@ -132,7 +132,7 @@ namespace SabreTools
// Now add the information to the database if it's not already there
Rom rom = FileTools.GetSingleFileInfo(newfile);
AddHeaderToDatabase(hstr, rom.HashData.SHA1, type);
AddHeaderToDatabase(hstr, rom.SHA1, type);
}
return true;
@@ -191,7 +191,7 @@ namespace SabreTools
// Then try to pull the corresponding headers from the database
string header = "";
string query = @"SELECT header, type FROM data WHERE sha1='" + rom.HashData.SHA1 + "'";
string query = @"SELECT header, type FROM data WHERE sha1='" + rom.SHA1 + "'";
using (SqliteConnection dbc = new SqliteConnection(Constants.HeadererConnectionString))
{
dbc.Open();

View File

@@ -1,652 +0,0 @@
using Mono.Data.Sqlite;
using SabreTools.Helper;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
namespace SabreTools
{
/// <summary>
/// Import data into the database from existing DATs
/// </summary>
public class Import : IImport
{
// Private instance variables
private string _filepath;
private string _connectionString;
private Logger _logger;
/// <summary>
/// Initialize an Import object with the given information
/// </summary>
/// <param name="filepath">Path to the file that is going to be imported</param>
/// <param name="connectionString">Connection string for SQLite</param>
/// <param name="logger">Logger object for file or console output</param>
public Import(string filepath, string connectionString, Logger logger)
{
_filepath = filepath;
_connectionString = connectionString;
_logger = logger;
}
/// <summary>
/// Import the data from file into the database
/// </summary>
/// <returns>True if the data was imported, false otherwise</returns>
public bool UpdateDatabase()
{
// If file doesn't exist, error and return
if (!File.Exists(_filepath))
{
_logger.Error("File '" + _filepath + "' doesn't exist");
return false;
}
// Determine which dattype we have
string filename = Path.GetFileName(_filepath);
GroupCollection fileinfo;
DatType type = DatType.none;
if (Regex.IsMatch(filename, Constants.NonGoodPattern))
{
fileinfo = Regex.Match(filename, Constants.NonGoodPattern).Groups;
type = DatType.NonGood;
}
else if (Regex.IsMatch(filename, Constants.NonGoodSpecialPattern))
{
fileinfo = Regex.Match(filename, Constants.NonGoodSpecialPattern).Groups;
type = DatType.NonGood;
}
else if (Regex.IsMatch(filename, Constants.GoodPattern))
{
fileinfo = Regex.Match(filename, Constants.GoodPattern).Groups;
type = DatType.Good;
}
else if (Regex.IsMatch(filename, Constants.GoodXmlPattern))
{
fileinfo = Regex.Match(filename, Constants.GoodXmlPattern).Groups;
type = DatType.Good;
}
else if (Regex.IsMatch(filename, Constants.MaybeIntroPattern))
{
fileinfo = Regex.Match(filename, Constants.MaybeIntroPattern).Groups;
type = DatType.MaybeIntro;
}
else if (Regex.IsMatch(filename, Constants.NoIntroPattern))
{
fileinfo = Regex.Match(filename, Constants.NoIntroPattern).Groups;
type = DatType.NoIntro;
}
// For numbered DATs only
else if (Regex.IsMatch(filename, Constants.NoIntroNumberedPattern))
{
fileinfo = Regex.Match(filename, Constants.NoIntroNumberedPattern).Groups;
type = DatType.NoIntro;
}
// For N-Gage and Gizmondo only
else if (Regex.IsMatch(filename, Constants.NoIntroSpecialPattern))
{
fileinfo = Regex.Match(filename, Constants.NoIntroSpecialPattern).Groups;
type = DatType.NoIntro;
}
else if (Regex.IsMatch(filename, Constants.RedumpPattern))
{
fileinfo = Regex.Match(filename, Constants.RedumpPattern).Groups;
type = DatType.Redump;
}
// For special BIOSes only
else if (Regex.IsMatch(filename, Constants.RedumpBiosPattern))
{
fileinfo = Regex.Match(filename, Constants.RedumpBiosPattern).Groups;
type = DatType.Redump;
}
else if (Regex.IsMatch(filename, Constants.TosecPattern))
{
fileinfo = Regex.Match(filename, Constants.TosecPattern).Groups;
type = DatType.TOSEC;
}
else if (Regex.IsMatch(filename, Constants.TruripPattern))
{
fileinfo = Regex.Match(filename, Constants.TruripPattern).Groups;
type = DatType.TruRip;
}
else if (Regex.IsMatch(filename, Constants.ZandroPattern))
{
filename = "Nintendo - Super Nintendo Entertainment System (Zandro " + File.GetLastWriteTime(_filepath).ToString("yyyyMMddHHmmss") + ").dat";
fileinfo = Regex.Match(filename, Constants.DefaultPattern).Groups;
type = DatType.Custom;
}
else if (Regex.IsMatch(filename, Constants.DefaultPattern))
{
fileinfo = Regex.Match(filename, Constants.DefaultPattern).Groups;
type = DatType.Custom;
}
else if (Regex.IsMatch(filename, Constants.DefaultSpecialPattern))
{
fileinfo = Regex.Match(filename, Constants.DefaultSpecialPattern).Groups;
type = DatType.Custom;
}
else if (Regex.IsMatch(filename, Constants.MamePattern))
{
fileinfo = Regex.Match(filename, Constants.MamePattern).Groups;
type = DatType.MAME;
}
// If the type is still unmatched, the data can't be imported yet
else
{
_logger.Warning("File " + filename + " cannot be imported at this time because it is not a known pattern.\nPlease try again with an unrenamed version.");
return false;
}
_logger.Log("Type detected: " + type.ToString());
// Check for and extract import information from the file name based on type
string manufacturer = "";
string system = "";
string source = "";
string datestring = "";
string date = "";
switch (type)
{
case DatType.Good:
if (!Mappings.DatMaps["Good"].ContainsKey(fileinfo[1].Value))
{
_logger.Warning("The filename " + fileinfo[1].Value + " could not be mapped! Please check the mappings and try again");
return false;
}
GroupCollection goodInfo = Regex.Match(Mappings.DatMaps["Good"][fileinfo[1].Value], Constants.RemappedPattern).Groups;
manufacturer = goodInfo[1].Value;
system = goodInfo[2].Value;
source = "Good";
date = File.GetLastWriteTime(_filepath).ToString("yyyy-MM-dd HH:mm:ss");
break;
case DatType.MAME:
if (!Mappings.DatMaps["MAME"].ContainsKey(fileinfo[1].Value))
{
_logger.Warning("The filename " + fileinfo[1].Value + " could not be mapped! Please check the mappings and try again");
return false;
}
GroupCollection mameInfo = Regex.Match(Mappings.DatMaps["MAME"][fileinfo[1].Value], Constants.RemappedPattern).Groups;
manufacturer = mameInfo[1].Value;
system = mameInfo[2].Value;
source = "MAME";
date = File.GetLastWriteTime(_filepath).ToString("yyyy-MM-dd HH:mm:ss");
break;
case DatType.MaybeIntro:
if (!Mappings.DatMaps["MaybeIntro"].ContainsKey(fileinfo[1].Value))
{
_logger.Warning("The filename " + fileinfo[1].Value + " could not be mapped! Please check the mappings and try again");
return false;
}
GroupCollection maybeIntroInfo = Regex.Match(Mappings.DatMaps["MaybeIntro"][fileinfo[1].Value], Constants.RemappedPattern).Groups;
manufacturer = maybeIntroInfo[1].Value;
system = maybeIntroInfo[2].Value;
source = "Maybe-Intro";
datestring = fileinfo[2].Value;
GroupCollection miDateInfo = Regex.Match(datestring, Constants.NoIntroSpecialDatePattern).Groups;
date = miDateInfo[1].Value + "-" + miDateInfo[2].Value + "-" + miDateInfo[3].Value + " 00:00:00";
break;
case DatType.NoIntro:
if (!Mappings.DatMaps["NoIntro"].ContainsKey(fileinfo[1].Value))
{
_logger.Warning("The filename " + fileinfo[1].Value + " could not be mapped! Please check the mappings and try again");
return false;
}
GroupCollection nointroInfo = Regex.Match(Mappings.DatMaps["NoIntro"][fileinfo[1].Value], Constants.RemappedPattern).Groups;
manufacturer = nointroInfo[1].Value;
system = nointroInfo[2].Value;
source = "no-Intro";
if (fileinfo.Count < 2)
{
date = File.GetLastWriteTime(_filepath).ToString("yyyy-MM-dd HH:mm:ss");
}
else if (Regex.IsMatch(fileinfo[2].Value, Constants.NoIntroDatePattern))
{
datestring = fileinfo[2].Value;
GroupCollection niDateInfo = Regex.Match(datestring, Constants.NoIntroDatePattern).Groups;
date = niDateInfo[1].Value + "-" + niDateInfo[2].Value + "-" + niDateInfo[3].Value + " " +
niDateInfo[4].Value + ":" + niDateInfo[5].Value + ":" + niDateInfo[6].Value;
}
else
{
datestring = fileinfo[2].Value;
GroupCollection niDateInfo = Regex.Match(datestring, Constants.NoIntroSpecialDatePattern).Groups;
date = niDateInfo[1].Value + "-" + niDateInfo[2].Value + "-" + niDateInfo[3].Value + " 00:00:00";
}
break;
case DatType.NonGood:
if (!Mappings.DatMaps["NonGood"].ContainsKey(fileinfo[1].Value))
{
_logger.Warning("The filename " + fileinfo[1].Value + " could not be mapped! Please check the mappings and try again");
return false;
}
GroupCollection nonGoodInfo = Regex.Match(Mappings.DatMaps["NonGood"][fileinfo[1].Value], Constants.RemappedPattern).Groups;
manufacturer = nonGoodInfo[1].Value;
system = nonGoodInfo[2].Value;
source = "NonGood";
date = File.GetLastWriteTime(_filepath).ToString("yyyy-MM-dd HH:mm:ss");
break;
case DatType.Redump:
if (!Mappings.DatMaps["Redump"].ContainsKey(fileinfo[1].Value))
{
// Handle special case mappings found only in Redump
fileinfo = Regex.Match(filename, Constants.RedumpBiosPattern).Groups;
if (!Mappings.DatMaps["Redump"].ContainsKey(fileinfo[1].Value))
{
_logger.Warning("The filename " + fileinfo[1].Value + " could not be mapped! Please check the mappings and try again");
return false;
}
}
GroupCollection redumpInfo = Regex.Match(Mappings.DatMaps["Redump"][fileinfo[1].Value], Constants.RemappedPattern).Groups;
manufacturer = redumpInfo[1].Value;
system = redumpInfo[2].Value;
source = "Redump";
datestring = fileinfo[2].Value;
if (Regex.IsMatch(datestring, Constants.RedumpDatePattern))
{
GroupCollection rdDateInfo = Regex.Match(datestring, Constants.RedumpDatePattern).Groups;
date = rdDateInfo[1].Value + "-" + rdDateInfo[2].Value + "-" + rdDateInfo[3].Value + " " +
rdDateInfo[4].Value + ":" + rdDateInfo[5].Value + ":" + rdDateInfo[6].Value;
}
else
{
GroupCollection rdDateInfo = Regex.Match(datestring, Constants.TosecDatePattern).Groups;
date = rdDateInfo[1].Value + "-" + rdDateInfo[2].Value + "-" + rdDateInfo[3].Value + " 00:00:00";
}
break;
case DatType.TOSEC:
if (!Mappings.DatMaps["TOSEC"].ContainsKey(fileinfo[1].Value))
{
// Handle special case mappings found only in TOSEC
fileinfo = Regex.Match(filename, Constants.TosecSpecialPatternA).Groups;
if (!Mappings.DatMaps["TOSEC"].ContainsKey(fileinfo[1].Value))
{
fileinfo = Regex.Match(filename, Constants.TosecSpecialPatternB).Groups;
if (!Mappings.DatMaps["TOSEC"].ContainsKey(fileinfo[1].Value))
{
_logger.Warning("The filename " + fileinfo[1].Value + " could not be mapped! Please check the mappings and try again");
return false;
}
}
}
GroupCollection tosecInfo = Regex.Match(Mappings.DatMaps["TOSEC"][fileinfo[1].Value], Constants.RemappedPattern).Groups;
manufacturer = tosecInfo[1].Value;
system = tosecInfo[2].Value;
source = "TOSEC";
datestring = fileinfo[2].Value;
GroupCollection toDateInfo = Regex.Match(datestring, Constants.TosecDatePattern).Groups;
date = toDateInfo[1].Value + "-" + toDateInfo[2].Value + "-" + toDateInfo[3].Value + " 00:00:00";
break;
case DatType.TruRip:
if (!Mappings.DatMaps["TruRip"].ContainsKey(fileinfo[1].Value))
{
_logger.Warning("The filename " + fileinfo[1].Value + " could not be mapped! Please check the mappings and try again");
return false;
}
GroupCollection truripInfo = Regex.Match(Mappings.DatMaps["TruRip"][fileinfo[1].Value], Constants.RemappedPattern).Groups;
manufacturer = truripInfo[1].Value;
system = truripInfo[2].Value;
source = "trurip";
date = File.GetLastWriteTime(_filepath).ToString("yyyy-MM-dd HH:mm:ss");
break;
case DatType.Custom:
default:
manufacturer = fileinfo[1].Value;
system = fileinfo[2].Value;
source = fileinfo[3].Value;
datestring = fileinfo[4].Value;
GroupCollection cDateInfo = Regex.Match(datestring, Constants.DefaultDatePattern).Groups;
date = cDateInfo[1].Value + "-" + cDateInfo[2].Value + "-" + cDateInfo[3].Value + " " +
cDateInfo[4].Value + ":" + cDateInfo[5].Value + ":" + cDateInfo[6].Value;
break;
}
// Check to make sure that the manufacturer and system are valid according to the database
int sysid = -1;
string query = "SELECT id FROM systems WHERE manufacturer='" + manufacturer + "' AND system='" + system +"'";
//string query = "SELECT id FROM system WHERE manufacturer='" + manufacturer + "' AND name='" + system + "'";
using (SqliteConnection dbc = new SqliteConnection(_connectionString))
{
dbc.Open();
using (SqliteCommand slc = new SqliteCommand(query, dbc))
{
using (SqliteDataReader sldr = slc.ExecuteReader())
{
// If nothing is found, tell the user and exit
if (!sldr.HasRows)
{
_logger.Error("No suitable system for '" + filename + "' (" + manufacturer + " " + system + ") found! Please add the system and then try again.");
return false;
}
// Set the system ID from the first found value
sldr.Read();
sysid = sldr.GetInt32(0);
}
}
}
// Check to make sure that the source is valid according to the database
int srcid = -1;
query = "SELECT id FROM sources WHERE name='" + source + "'";
//query = "SELECT id FROM source WHERE name='" + source + "'";
using (SqliteConnection dbc = new SqliteConnection(_connectionString))
{
dbc.Open();
using (SqliteCommand slc = new SqliteCommand(query, dbc))
{
using (SqliteDataReader sldr = slc.ExecuteReader())
{
// If nothing is found, tell the user and exit
if (!sldr.HasRows)
{
_logger.Error("No suitable source for '" + filename + "' found! Please add the source and then try again.");
return false;
}
// Set the source ID from the first found value
sldr.Read();
srcid = sldr.GetInt32(0);
}
}
}
// Get all roms that are found in the DAT to see what needs to be added
Dat datdata = new Dat();
DatTools.Parse(_filepath, sysid, srcid, ref datdata, _logger);
// Sort inputted roms into games
SortedDictionary<string, List<Rom>> sortable = new SortedDictionary<string, List<Rom>>();
long count = 0;
foreach (List<Rom> roms in datdata.Files.Values)
{
List<Rom> newroms = roms;
if (datdata.MergeRoms)
{
newroms = RomTools.Merge(newroms, _logger);
}
foreach (Rom rom in newroms)
{
count++;
string key = rom.Metadata.SystemID.ToString().PadLeft(10, '0') + "-" + rom.Metadata.SourceID.ToString().PadLeft(10, '0') + "-" + rom.Machine.Name.ToLowerInvariant();
if (sortable.ContainsKey(key))
{
sortable[key].Add(rom);
}
else
{
List<Rom> temp = new List<Rom>();
temp.Add(rom);
sortable.Add(key, temp);
}
}
}
// Loop over all roms, checking for adds
foreach (string key in sortable.Keys)
{
List<Rom> roms = sortable[key];
RomTools.Sort(ref roms, true);
long gameid = -1;
using (SqliteConnection dbc = new SqliteConnection(_connectionString))
{
dbc.Open();
// For each game, check for a new ID
gameid = AddGame(sysid, roms[0].Machine.Name, srcid, dbc);
foreach (Rom rom in roms)
{
// BEGIN COMMENT
// Try to add the rom with the game information
AddRom(rom, gameid, date, dbc);
// END COMMENT
/*
// Try to add the romdata
AddHash(rom, sysid, srcid, date, dbc);
*/
}
}
}
return true;
}
/// <summary>
/// Add a game to the database if it doesn't already exist
/// </summary>
/// <param name="sysid">System ID for the game to be added with</param>
/// <param name="machinename">Name of the game to be added</param>
/// <param name="srcid">Source ID for the game to be added with</param>
/// <param name="dbc">SQLite database connection to use</param>
/// <returns>Game ID of the inserted (or found) game, -1 on error</returns>
private long AddGame(int sysid, string machinename, int srcid, SqliteConnection dbc)
{
// WoD gets rid of anything past the first "(" or "[" as the name, we will do the same
string stripPattern = @"(([[(].*[\)\]] )?([^([]+))";
Regex stripRegex = new Regex(stripPattern);
Match stripMatch = stripRegex.Match(machinename);
machinename = stripMatch.Groups[1].Value;
// Run the name through the filters to make sure that it's correct
machinename = Style.NormalizeChars(machinename);
machinename = Style.RussianToLatin(machinename);
machinename = Style.SearchPattern(machinename);
machinename = machinename.Trim();
long gameid = -1;
string query = "SELECT id FROM games WHERE system=" + sysid +
" AND name='" + machinename.Replace("'", "''") + "'" +
" AND source=" + srcid;
using (SqliteCommand slc = new SqliteCommand(query, dbc))
{
using (SqliteDataReader sldr = slc.ExecuteReader())
{
// If nothing is found, add the game and get the insert ID
if (!sldr.HasRows)
{
query = "INSERT INTO games (system, name, source)" +
" VALUES (" + sysid + ", '" + machinename.Replace("'", "''") + "', " + srcid + ")";
using (SqliteCommand slc2 = new SqliteCommand(query, dbc))
{
slc2.ExecuteNonQuery();
}
query = "SELECT last_insertConstants.Rowid()";
using (SqliteCommand slc2 = new SqliteCommand(query, dbc))
{
gameid = (long)slc2.ExecuteScalar();
}
}
// Otherwise, retrieve the ID
else
{
sldr.Read();
gameid = sldr.GetInt64(0);
}
}
}
return gameid;
}
/// <summary>
/// Add a file to the database if it doesn't already exist
/// </summary>
/// <param name="rom">Rom object representing the rom</param>
/// <param name="gameid">ID of the parent game to be mapped to</param>
/// <param name="date">Last updated date</param>
/// <param name="dbc">SQLite database connection to use</param>
/// <returns>True if the file exists or could be added, false on error</returns>
private bool AddRom(Rom rom, long gameid, string date, SqliteConnection dbc)
{
// WOD origninally stripped out any subdirs from the imported files, we do the same
rom.Name = Path.GetFileName(rom.Name);
// Run the name through the filters to make sure that it's correct
rom.Name = Style.NormalizeChars(rom.Name);
rom.Name = Style.RussianToLatin(rom.Name);
rom.Name = Regex.Replace(rom.Name, @"(.*) \.(.*)", "$1.$2");
if (rom.Type != ItemType.Rom && rom.Type != ItemType.Disk)
{
rom.Type = ItemType.Rom;
}
// Check to see if this exact file is in the database already
string query = @"
SELECT files.id FROM files
JOIN checksums
ON files.id=checksums.file
WHERE files.name='" + rom.Name.Replace("'", "''") + @"'
AND files.type='" + rom.Type + @"'
AND files.setid=" + gameid +
" AND checksums.size=" + rom.HashData.Size +
" AND checksums.crc='" + rom.HashData.CRC + "'" +
" AND checksums.md5='" + rom.HashData.MD5 + "'" +
" AND checksums.sha1='" + rom.HashData.SHA1 + "'";
using (SqliteCommand slc = new SqliteCommand(query, dbc))
{
using (SqliteDataReader sldr = slc.ExecuteReader())
{
// If the file doesn't exist, add it with its checksums
if (!sldr.HasRows)
{
query = @"BEGIN;
INSERT INTO files (setid, name, type, lastupdated)
VALUES (" + gameid + ", '" + rom.Name.Replace("'", "''") + "', '" + rom.Type + "', '" + date + @"');
INSERT INTO checksums (file, size, crc, md5, sha1)
VALUES ((SELECT last_insertConstants.Rowid()), " + rom.HashData.Size + ", '" + rom.HashData.CRC + "'" + ", '" + rom.HashData.MD5 + "'" + ", '" + rom.HashData.SHA1 + @"');
COMMIT;";
using (SqliteCommand slc2 = new SqliteCommand(query, dbc))
{
int affected = slc2.ExecuteNonQuery();
// If the insert was unsuccessful, something bad happened
if (affected < 1)
{
_logger.Error("There was an error adding " + rom.Name + " to the database!");
return false;
}
}
}
}
}
return true;
}
/// <summary>
/// Add a hash to the database if it doesn't exist already
/// </summary>
/// <param name="rom">Rom object representing the rom</param>
/// <param name="sysid">System ID for the game to be added with</param>
/// <param name="srcid">Source ID for the game to be added with</param>
/// <param name="date">Last updated date</param>
/// <param name="dbc">SQLite database connection to use</param>
/// <returns>True if the hash exists or could be added, false on error</returns>
/// <remarks>This is currently unused. It is a test method for the new SabreTools DB schema</remarks>
private bool AddHash(Rom rom, int sysid, int srcid, string date, SqliteConnection dbc)
{
// Process the game name
// WoD gets rid of anything past the first "(" or "[" as the name, we will do the same
string stripPattern = @"(([[(].*[\)\]] )?([^([]+))";
Regex stripRegex = new Regex(stripPattern);
Match stripMatch = stripRegex.Match(rom.Machine.Name);
rom.Machine.Name = stripMatch.Groups[1].Value;
// Run the name through the filters to make sure that it's correct
rom.Machine.Name = Style.NormalizeChars(rom.Machine.Name);
rom.Machine.Name = Style.RussianToLatin(rom.Machine.Name);
rom.Machine.Name = Style.SearchPattern(rom.Machine.Name);
rom.Machine.Name = rom.Machine.Name.Trim();
// Process the rom name
// WOD origninally stripped out any subdirs from the imported files, we do the same
rom.Name = Path.GetFileName(rom.Name);
// Run the name through the filters to make sure that it's correct
rom.Name = Style.NormalizeChars(rom.Name);
rom.Name = Style.RussianToLatin(rom.Name);
rom.Name = Regex.Replace(rom.Name, @"(.*) \.(.*)", "$1.$2");
// Retrieve or insert the hash
long hashid = -1;
string query = "SELECT id FROM hash WHERE size=" + rom.HashData.Size + " AND crc='" + rom.HashData.CRC + "' AND md5='" + rom.HashData.MD5 + "' AND sha1='" + rom.HashData.SHA1 + "'";
using (SqliteCommand slc = new SqliteCommand(query, dbc))
{
using (SqliteDataReader sldr = slc.ExecuteReader())
{
// If nothing is found, add the hash and get the insert ID
if (!sldr.HasRows)
{
query = "INSERT INTO hash (size, crc, md5, sha1)" +
" VALUES (" + rom.HashData.Size + ", '" + rom.HashData.CRC + "', '" + rom.HashData.MD5 + "', '" + rom.HashData.SHA1 + "')";
using (SqliteCommand slc2 = new SqliteCommand(query, dbc))
{
slc2.ExecuteNonQuery();
}
query = "SELECT last_insertConstants.Rowid()";
using (SqliteCommand slc2 = new SqliteCommand(query, dbc))
{
hashid = (long)slc2.ExecuteScalar();
}
}
// Otherwise, retrieve the ID
else
{
sldr.Read();
hashid = sldr.GetInt64(0);
}
}
}
// Ignore or insert the file and game
query = @"BEGIN;
INSERT OR IGNORE INTO hashdata (hashid, key, value) VALUES " +
"(" + hashid + ", 'name', '" + rom.Name.Replace("'", "''") + "'), " +
"(" + hashid + ", 'game', '" + rom.Machine.Name.Replace("'", "''") + "'), " +
"(" + hashid + ", 'type', '" + rom.Type + "'), " +
"(" + hashid + ", 'lastupdated', '" + date + @"');
INSERT OR IGNORE INTO gamesystem (game, systemid) VALUES ('" + rom.Machine.Name.Replace("'", "''") + "', " + sysid + @");
INSERT OR IGNORE INTO gamesource (game, sourceid) VALUES ('" + rom.Machine.Name.Replace("'", "''") + "', " + srcid + @");
COMMIT;";
using (SqliteCommand slc = new SqliteCommand(query, dbc))
{
int ret = slc.ExecuteNonQuery();
if ((SQLiteErrorCode)ret == SQLiteErrorCode.Error)
{
_logger.Error("A SQLite error has occurred: " + ((SQLiteErrorCode)ret).ToString());
return false;
}
}
return true;
}
}
}

View File

@@ -9,7 +9,7 @@ namespace SabreTools.Helper
public class SimpleSort
{
// Private instance variables
private Dat _datdata;
private DatFile _datdata;
private List<string> _inputs;
private string _outDir;
private string _tempDir;
@@ -30,7 +30,7 @@ namespace SabreTools.Helper
// Other private variables
private int _cursorTop;
private int _cursorLeft;
private Dat _matched;
private DatFile _matched;
/// <summary>
/// Create a new SimpleSort object
@@ -51,7 +51,7 @@ namespace SabreTools.Helper
/// <param name="zip">Integer representing the archive handling level for Zip</param>
/// <param name="updateDat">True if the updated DAT should be output, false otherwise</param>
/// <param name="logger">Logger object for file and console output</param>
public SimpleSort(Dat datdata, List<string> inputs, string outDir, string tempDir,
public SimpleSort(DatFile datdata, List<string> inputs, string outDir, string tempDir,
bool quickScan, bool toFolder, bool verify, bool delete, bool? torrentX, bool romba, int sevenzip,
int gz, int rar, int zip, bool updateDat, Logger logger)
{
@@ -74,9 +74,9 @@ namespace SabreTools.Helper
_cursorTop = Console.CursorTop;
_cursorLeft = Console.CursorLeft;
_matched = new Dat
_matched = new DatFile
{
Files = new Dictionary<string, List<Rom>>(),
Files = new Dictionary<string, List<DatItem>>(),
};
}
@@ -144,8 +144,8 @@ namespace SabreTools.Helper
}
// Setup the fixdat
_matched = (Dat)_datdata.CloneHeader();
_matched.Files = new Dictionary<string, List<Rom>>();
_matched = (DatFile)_datdata.CloneHeader();
_matched.Files = new Dictionary<string, List<DatItem>>();
_matched.FileName = "fixDat_" + _matched.FileName;
_matched.Name = "fixDat_" + _matched.Name;
_matched.Description = "fixDat_" + _matched.Description;
@@ -153,22 +153,22 @@ namespace SabreTools.Helper
// Now that all files are parsed, get only files found in directory
bool found = false;
foreach (List<Rom> roms in _datdata.Files.Values)
foreach (List<DatItem> roms in _datdata.Files.Values)
{
List<Rom> newroms = RomTools.Merge(roms, _logger);
List<DatItem> newroms = DatItem.Merge(roms, _logger);
foreach (Rom rom in newroms)
{
if (rom.Metadata.SourceID == 99)
if (rom.SourceID == 99)
{
found = true;
string key = rom.HashData.Size + "-" + rom.HashData.CRC;
string key = rom.Size + "-" + rom.CRC;
if (_matched.Files.ContainsKey(key))
{
_matched.Files[key].Add(rom);
}
else
{
List<Rom> temp = new List<Rom>();
List<DatItem> temp = new List<DatItem>();
temp.Add(rom);
_matched.Files.Add(key, temp);
}
@@ -179,7 +179,7 @@ namespace SabreTools.Helper
// Now output the fixdat to the main folder
if (found)
{
DatTools.WriteDatfile(_matched, "", _logger, stats: true);
DatFile.WriteDatfile(_matched, "", _logger, stats: true);
}
else
{
@@ -273,7 +273,7 @@ namespace SabreTools.Helper
_datdata.Name = "fixDat_" + _datdata.Name;
_datdata.Description = "fixDat_" + _datdata.Description;
_datdata.OutputFormat = OutputFormat.Xml;
DatTools.WriteDatfile(_datdata, "", _logger);
DatFile.WriteDatfile(_datdata, "", _logger);
}
return success;
@@ -341,9 +341,9 @@ namespace SabreTools.Helper
// Now loop through all of the files and check them, DFD style
_logger.User("Getting source file information...");
Dat matchdat = new Dat
DatFile matchdat = new DatFile
{
Files = new Dictionary<string, List<Rom>>(),
Files = new Dictionary<string, List<DatItem>>(),
};
foreach (string file in files)
{
@@ -409,15 +409,15 @@ namespace SabreTools.Helper
#region Find all files to rebuild and bucket by game
// Create a dictionary of from/to Rom mappings
Dictionary<Rom, Rom> toFromMap = new Dictionary<Rom, Rom>();
Dictionary<DatItem, DatItem> toFromMap = new Dictionary<DatItem, DatItem>();
// Now populate it
foreach (string key in matchdat.Files.Keys)
{
foreach (Rom rom in matchdat.Files[key])
foreach (DatItem rom in matchdat.Files[key])
{
List<Rom> matched = RomTools.GetDuplicates(rom, _datdata, _logger, true);
foreach (Rom match in matched)
List<DatItem> matched = DatItem.GetDuplicates(rom, _datdata, _logger, true);
foreach (DatItem match in matched)
{
try
{
@@ -429,7 +429,7 @@ namespace SabreTools.Helper
}
// Then bucket the keys by game for better output
SortedDictionary<string, List<Rom>> keysByGame = DatTools.BucketByGame(toFromMap.Keys.ToList(), false, true, _logger);
SortedDictionary<string, List<DatItem>> keysByGame = DatFile.BucketByGame(toFromMap.Keys.ToList(), false, true, _logger);
#endregion
@@ -456,7 +456,7 @@ namespace SabreTools.Helper
/// <param name="file">Name of the file to attempt to add</param>
/// <param name="matchdat">Reference to the Dat to add to</param>
/// <returns>True if the file could be added, false otherwise</returns>
public bool RebuildToOutputAlternateParseRomHelper(string file, ref Dat matchdat)
public bool RebuildToOutputAlternateParseRomHelper(string file, ref DatFile matchdat)
{
Rom rom = FileTools.GetSingleFileInfo(file);
@@ -467,17 +467,17 @@ namespace SabreTools.Helper
}
// Otherwise, set the machine name as the full path to the file
rom.Machine.Name = Path.GetDirectoryName(Path.GetFullPath(file));
rom.MachineName = Path.GetDirectoryName(Path.GetFullPath(file));
// Add the rom information to the Dat
string key = rom.HashData.Size + "-" + rom.HashData.CRC;
string key = rom.Size + "-" + rom.CRC;
if (matchdat.Files.ContainsKey(key))
{
matchdat.Files[key].Add(rom);
}
else
{
List<Rom> temp = new List<Rom>();
List<DatItem> temp = new List<DatItem>();
temp.Add(rom);
matchdat.Files.Add(key, temp);
}
@@ -494,17 +494,17 @@ namespace SabreTools.Helper
Skippers.TransformStream(input, output, rule, _logger, false, true);
Rom romNH = FileTools.GetSingleStreamInfo(output);
romNH.Name = "HEAD::" + rom.Name;
romNH.Machine.Name = rom.Machine.Name;
romNH.MachineName = rom.MachineName;
// Add the rom information to the Dat
key = romNH.HashData.Size + "-" + romNH.HashData.CRC;
key = romNH.Size + "-" + romNH.CRC;
if (matchdat.Files.ContainsKey(key))
{
matchdat.Files[key].Add(romNH);
}
else
{
List<Rom> temp = new List<Rom>();
List<DatItem> temp = new List<DatItem>();
temp.Add(romNH);
matchdat.Files.Add(key, temp);
}
@@ -548,21 +548,21 @@ namespace SabreTools.Helper
}
// Try to find the matches to the file that was found
List<Rom> foundroms = RomTools.GetDuplicates(rom, _datdata, _logger);
List<DatItem> foundroms = DatItem.GetDuplicates(rom, _datdata, _logger);
_logger.Log("File '" + input + "' had " + foundroms.Count + " matches in the DAT!");
foreach (Rom found in foundroms)
{
_logger.Log("Matched name: " + found.Name);
// Add rom to the matched list
string key = found.HashData.Size + "-" + found.HashData.CRC;
string key = found.Size + "-" + found.CRC;
if (_matched.Files.ContainsKey(key))
{
_matched.Files[key].Add(found);
}
else
{
List<Rom> temp = new List<Rom>();
List<DatItem> temp = new List<DatItem>();
temp.Add(found);
_matched.Files.Add(key, temp);
}
@@ -570,13 +570,13 @@ namespace SabreTools.Helper
if (_toFolder)
{
// Copy file to output directory
string gamedir = Path.Combine(_outDir, found.Machine.Name);
string gamedir = Path.Combine(_outDir, found.MachineName);
if (!Directory.Exists(gamedir))
{
Directory.CreateDirectory(gamedir);
}
_logger.Log("Rebuilding file '" + Path.GetFileName(rom.Name) + "' to '" + (_torrentX == false ? found.HashData.SHA1 : found.Name) + "'");
_logger.Log("Rebuilding file '" + Path.GetFileName(rom.Name) + "' to '" + (_torrentX == false ? found.SHA1 : found.Name) + "'");
try
{
File.Copy(input, Path.Combine(gamedir, Path.GetFileName(found.Name)));
@@ -618,19 +618,19 @@ namespace SabreTools.Helper
}
// Try to find the matches to the file that was found
List<Rom> founddroms = RomTools.GetDuplicates(drom, _datdata, _logger);
List<DatItem> founddroms = DatItem.GetDuplicates(drom, _datdata, _logger);
_logger.Log("File '" + newinput + "' had " + founddroms.Count + " matches in the DAT!");
foreach (Rom found in founddroms)
{
// Add rom to the matched list
string key = found.HashData.Size + "-" + found.HashData.CRC;
string key = found.Size + "-" + found.CRC;
if (_matched.Files.ContainsKey(key))
{
_matched.Files[key].Add(found);
}
else
{
List<Rom> temp = new List<Rom>();
List<DatItem> temp = new List<DatItem>();
temp.Add(found);
_matched.Files.Add(key, temp);
}
@@ -641,13 +641,13 @@ namespace SabreTools.Helper
if (_toFolder)
{
// Copy file to output directory
string gamedir = Path.Combine(_outDir, found.Machine.Name);
string gamedir = Path.Combine(_outDir, found.MachineName);
if (!Directory.Exists(gamedir))
{
Directory.CreateDirectory(gamedir);
}
_logger.Log("Rebuilding file '" + Path.GetFileName(rom.Name) + "' to '" + (_torrentX == false ? found.HashData.SHA1 : found.Name) + "'");
_logger.Log("Rebuilding file '" + Path.GetFileName(rom.Name) + "' to '" + (_torrentX == false ? found.SHA1 : found.Name) + "'");
try
{
File.Copy(newinput, Path.Combine(gamedir, Path.GetFileName(found.Name)));
@@ -672,18 +672,21 @@ namespace SabreTools.Helper
// Then output the headered rom (renamed)
Rom newfound = found;
newfound.Name = Path.GetFileNameWithoutExtension(newfound.Name) + " (" + rom.HashData.CRC + ")" + Path.GetExtension(newfound.Name);
newfound.HashData = rom.HashData;
newfound.Name = Path.GetFileNameWithoutExtension(newfound.Name) + " (" + rom.CRC + ")" + Path.GetExtension(newfound.Name);
newfound.Size = rom.Size;
newfound.CRC = rom.CRC;
newfound.MD5 = rom.MD5;
newfound.SHA1 = rom.SHA1;
// Add rom to the matched list
key = newfound.HashData.Size + "-" + newfound.HashData.CRC;
key = newfound.Size + "-" + newfound.CRC;
if (_matched.Files.ContainsKey(key))
{
_matched.Files[key].Add(newfound);
}
else
{
List<Rom> temp = new List<Rom>();
List<DatItem> temp = new List<DatItem>();
temp.Add(newfound);
_matched.Files.Add(key, temp);
}
@@ -691,7 +694,7 @@ namespace SabreTools.Helper
if (_toFolder)
{
// Copy file to output directory
string gamedir = Path.Combine(_outDir, found.Machine.Name);
string gamedir = Path.Combine(_outDir, found.MachineName);
if (!Directory.Exists(gamedir))
{
Directory.CreateDirectory(gamedir);
@@ -750,19 +753,19 @@ namespace SabreTools.Helper
foreach (Rom rom in internalRomData)
{
// Try to find the matches to the file that was found
List<Rom> foundroms = RomTools.GetDuplicates(rom, _datdata, _logger);
List<DatItem> foundroms = DatItem.GetDuplicates(rom, _datdata, _logger);
_logger.Log("File '" + rom.Name + "' had " + foundroms.Count + " matches in the DAT!");
foreach (Rom found in foundroms)
{
// Add rom to the matched list
string key = found.HashData.Size + "-" + found.HashData.CRC;
string key = found.Size + "-" + found.CRC;
if (_matched.Files.ContainsKey(key))
{
_matched.Files[key].Add(found);
}
else
{
List<Rom> temp = new List<Rom>();
List<DatItem> temp = new List<DatItem>();
temp.Add(found);
_matched.Files.Add(key, temp);
}
@@ -774,7 +777,7 @@ namespace SabreTools.Helper
string outfile = FileTools.ExtractSingleItemFromArchive(input, rom.Name, _tempDir, _logger);
if (File.Exists(outfile))
{
string gamedir = Path.Combine(_outDir, found.Machine.Name);
string gamedir = Path.Combine(_outDir, found.MachineName);
if (!Directory.Exists(gamedir))
{
Directory.CreateDirectory(gamedir);
@@ -790,7 +793,7 @@ namespace SabreTools.Helper
else
{
// Copy file between archives
_logger.Log("Rebuilding file '" + Path.GetFileName(rom.Name) + "' to '" + (_torrentX == false ? found.HashData.SHA1 : found.Name) + "'");
_logger.Log("Rebuilding file '" + Path.GetFileName(rom.Name) + "' to '" + (_torrentX == false ? found.SHA1 : found.Name) + "'");
if (Build.MonoEnvironment || _torrentX == false)
{
@@ -888,7 +891,7 @@ namespace SabreTools.Helper
}
// Now process the inputs (assumed that it's archived sets as of right now
Dictionary<string, List<Rom>> scanned = new Dictionary<string, List<Rom>>();
Dictionary<string, List<DatItem>> scanned = new Dictionary<string, List<DatItem>>();
foreach (string archive in Directory.EnumerateFiles(_outDir, "*", SearchOption.AllDirectories))
{
// If we are in quickscan, get the list of roms that way
@@ -914,14 +917,14 @@ namespace SabreTools.Helper
// Then add each of the found files to the new dictionary
foreach (Rom rom in roms)
{
string key = rom.HashData.Size + "-" + rom.HashData.CRC;
string key = rom.Size + "-" + rom.CRC;
if (scanned.ContainsKey(key))
{
scanned[key].Add(rom);
}
else
{
List<Rom> templist = new List<Rom>();
List<DatItem> templist = new List<DatItem>();
templist.Add(rom);
scanned.Add(key, templist);
}
@@ -935,7 +938,7 @@ namespace SabreTools.Helper
}
// Now that we have all of the from DAT and from folder roms, we try to match them, removing the perfect matches
Dictionary<string, List<Rom>> remove = new Dictionary<string, List<Rom>>();
Dictionary<string, List<DatItem>> remove = new Dictionary<string, List<DatItem>>();
foreach (string key in scanned.Keys)
{
// If the key doesn't even exist in the DAT, then mark the entire key for removal
@@ -953,8 +956,8 @@ namespace SabreTools.Helper
// Otherwise check each of the values individually
else
{
List<Rom> romsList = _datdata.Files[key];
List<Rom> scannedList = scanned[key];
List<DatItem> romsList = _datdata.Files[key];
List<DatItem> scannedList = scanned[key];
foreach (Rom rom in scannedList)
{
if (!romsList.Contains(rom))
@@ -965,7 +968,7 @@ namespace SabreTools.Helper
}
else
{
List<Rom> templist = new List<Rom>();
List<DatItem> templist = new List<DatItem>();
templist.Add(rom);
remove.Add(key, templist);
}

View File

@@ -47,9 +47,9 @@ namespace SabreTools.Helper
{
_logger.Log("Beginning stat collection for '" + filename + "'");
List<String> games = new List<String>();
Dat datdata = new Dat();
DatTools.Parse(filename, 0, 0, ref datdata, _logger);
SortedDictionary<string, List<Rom>> newroms = DatTools.BucketByGame(datdata.Files, false, true, _logger, false);
DatFile datdata = new DatFile();
DatFile.Parse(filename, 0, 0, ref datdata, _logger);
SortedDictionary<string, List<DatItem>> newroms = DatFile.BucketByGame(datdata.Files, false, true, _logger, false);
// Output single DAT stats (if asked)
if (_single)
@@ -76,7 +76,7 @@ namespace SabreTools.Helper
// Output total DAT stats
if (!_single) { _logger.User(""); }
Dat totaldata = new Dat
DatFile totaldata = new DatFile
{
TotalSize = totalSize,
RomCount = totalRom,
@@ -102,7 +102,7 @@ Please check the log folder if the stats scrolled offscreen");
/// <param name="logger">Logger object for file and console writing</param>
/// <param name="recalculate">True if numbers should be recalculated for the DAT, false otherwise (default)</param>
/// <param name="game">Number of games to use, -1 means recalculate games (default)</param>
public static void OutputStats(Dat datdata, Logger logger, bool recalculate = false, long game = -1)
public static void OutputStats(DatFile datdata, Logger logger, bool recalculate = false, long game = -1)
{
if (recalculate)
{
@@ -116,22 +116,22 @@ Please check the log folder if the stats scrolled offscreen");
datdata.NodumpCount = 0;
// Loop through and add
foreach (List<Rom> roms in datdata.Files.Values)
foreach (List<DatItem> roms in datdata.Files.Values)
{
foreach (Rom rom in roms)
{
datdata.RomCount += (rom.Type == ItemType.Rom ? 1 : 0);
datdata.DiskCount += (rom.Type == ItemType.Disk ? 1 : 0);
datdata.TotalSize += (rom.Nodump ? 0 : rom.HashData.Size);
datdata.CRCCount += (String.IsNullOrEmpty(rom.HashData.CRC) ? 0 : 1);
datdata.MD5Count += (String.IsNullOrEmpty(rom.HashData.MD5) ? 0 : 1);
datdata.SHA1Count += (String.IsNullOrEmpty(rom.HashData.SHA1) ? 0 : 1);
datdata.TotalSize += (rom.Nodump ? 0 : rom.Size);
datdata.CRCCount += (String.IsNullOrEmpty(rom.CRC) ? 0 : 1);
datdata.MD5Count += (String.IsNullOrEmpty(rom.MD5) ? 0 : 1);
datdata.SHA1Count += (String.IsNullOrEmpty(rom.SHA1) ? 0 : 1);
datdata.NodumpCount += (rom.Nodump ? 1 : 0);
}
}
}
SortedDictionary<string, List<Rom>> newroms = DatTools.BucketByGame(datdata.Files, false, true, logger, false);
SortedDictionary<string, List<DatItem>> newroms = DatFile.BucketByGame(datdata.Files, false, true, logger, false);
if (datdata.TotalSize < 0)
{
datdata.TotalSize = Int64.MaxValue + datdata.TotalSize;

View File

@@ -101,14 +101,20 @@
<Compile Include="External\Zlib\ZlibConstants.cs" />
<Compile Include="External\Zlib\ZlibStream.cs" />
<Compile Include="Objects\DATFromDir.cs" />
<Compile Include="Objects\Generate.cs" />
<Compile Include="Objects\Dat\Archive.cs" />
<Compile Include="Objects\Dat\BiosSet.cs" />
<Compile Include="Objects\Dat\DatFile.cs" />
<Compile Include="Objects\Dat\DatItem.cs" />
<Compile Include="Objects\Dat\Disk.cs" />
<Compile Include="Objects\Dat\Release.cs" />
<Compile Include="Objects\Dat\Sample.cs" />
<Compile Include="Objects\GenerateTwo.cs" />
<Compile Include="Objects\Headerer.cs" />
<Compile Include="Objects\Import.cs" />
<Compile Include="Objects\ImportTwo.cs" />
<Compile Include="Objects\Dat\Rom.cs" />
<Compile Include="Objects\SimpleSort.cs" />
<Compile Include="Objects\ZipFileEntry.cs" />
<Compile Include="Objects\ZipFile.cs" />
<Compile Include="Objects\Archive\ZipFileEntry.cs" />
<Compile Include="Objects\Archive\ZipFile.cs" />
<Compile Include="Resources\Resources.de-DE.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
@@ -130,7 +136,6 @@
<DependentUpon>Resources.fr-FR.resx</DependentUpon>
</Compile>
<Compile Include="Skippers\Skippers.cs" />
<Compile Include="Tools\DatToolsHash.cs" />
<Compile Include="Tools\FileTools.cs" />
<Compile Include="Tools\DBTools.cs" />
<Compile Include="Data\Enums.cs" />
@@ -139,11 +144,7 @@
<Compile Include="Objects\Logger.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Mappings\Mappings.cs" />
<Compile Include="Tools\DatTools.cs" />
<Compile Include="Data\Structs.cs" />
<Compile Include="Tools\FileToolsHash.cs" />
<Compile Include="Tools\RomTools.cs" />
<Compile Include="Tools\RomToolsHash.cs" />
<Compile Include="Objects\Stats.cs" />
<Compile Include="Tools\Style.cs" />
<Compile Include="Data\Build.cs" />

View File

@@ -10,7 +10,7 @@ namespace SabreTools.Helper
public class Skippers
{
// Local paths
public const string Path = "Skippers";
public const string LocalPath = "Skippers";
// Header skippers represented by a list of skipper objects
private static List<Skipper> _list;
@@ -56,9 +56,9 @@ namespace SabreTools.Helper
_list = new List<Skipper>();
}
foreach (string skipperFile in Directory.EnumerateFiles(Path, "*", SearchOption.AllDirectories))
foreach (string skipperFile in Directory.EnumerateFiles(LocalPath, "*", SearchOption.AllDirectories))
{
_list.Add(PopulateSkippersHelper(System.IO.Path.GetFullPath(skipperFile)));
_list.Add(PopulateSkippersHelper(Path.GetFullPath(skipperFile)));
}
}
@@ -81,7 +81,7 @@ namespace SabreTools.Helper
Logger logger = new Logger(false, "");
logger.Start();
XmlTextReader xtr = DatTools.GetXmlTextReader(filename, logger);
XmlTextReader xtr = DatFile.GetXmlTextReader(filename, logger);
if (xtr == null)
{
@@ -527,9 +527,9 @@ namespace SabreTools.Helper
}
// Create the output directory if it doesn't already
if (!Directory.Exists(System.IO.Path.GetDirectoryName(output)))
if (!Directory.Exists(Path.GetDirectoryName(output)))
{
Directory.CreateDirectory(System.IO.Path.GetDirectoryName(output));
Directory.CreateDirectory(Path.GetDirectoryName(output));
}
logger.User("Attempting to apply rule to '" + input + "'");
@@ -725,7 +725,7 @@ namespace SabreTools.Helper
XmlDocument doc = new XmlDocument();
try
{
doc.LoadXml(File.ReadAllText(System.IO.Path.Combine(Path, skipper + ".xml")));
doc.LoadXml(File.ReadAllText(Path.Combine(LocalPath, skipper + ".xml")));
}
catch (XmlException ex)
{

File diff suppressed because it is too large Load Diff

View File

@@ -63,7 +63,7 @@ namespace SabreTools.Helper
}
// Get the output archive name from the first rebuild rom
string archiveFileName = Path.Combine(outDir, roms[0].Machine.Name + ".zip");
string archiveFileName = Path.Combine(outDir, roms[0].MachineName + ".zip");
// First, open the archive
ZipArchive outarchive = null;
@@ -172,7 +172,7 @@ namespace SabreTools.Helper
}
// Get the output archive name from the first rebuild rom
string archiveFileName = Path.Combine(outDir, roms[0].Machine.Name + ".zip");
string archiveFileName = Path.Combine(outDir, roms[0].MachineName + ".zip");
// Set internal variables
Stream writeStream = null;
@@ -224,7 +224,7 @@ namespace SabreTools.Helper
writeStream.Write(buffer, 0, len);
}
writeStream.Flush();
zipFile.CloseWriteStream(Convert.ToUInt32(rom.HashData.CRC, 16));
zipFile.CloseWriteStream(Convert.ToUInt32(rom.CRC, 16));
}
}
}
@@ -291,7 +291,7 @@ namespace SabreTools.Helper
}
freadStream.Close();
freadStream.Dispose();
zipFile.CloseWriteStream(Convert.ToUInt32(roms[-index - 1].HashData.CRC, 16));
zipFile.CloseWriteStream(Convert.ToUInt32(roms[-index - 1].CRC, 16));
}
// Otherwise, copy the file from the old archive
@@ -372,7 +372,7 @@ namespace SabreTools.Helper
Rom rom = FileTools.GetSingleFileInfo(input);
// If it doesn't exist, create the output file and then write
string outfile = Path.Combine(outDir, rom.HashData.SHA1 + ".gz");
string outfile = Path.Combine(outDir, rom.SHA1 + ".gz");
using (FileStream inputstream = new FileStream(input, FileMode.Open))
using (GZipStream output = new GZipStream(File.Open(outfile, FileMode.Create, FileAccess.Write), CompressionMode.Compress))
{
@@ -386,9 +386,9 @@ namespace SabreTools.Helper
{
// Write standard header and TGZ info
byte[] data = Constants.TorrentGZHeader
.Concat(Style.StringToByteArray(rom.HashData.MD5)) // MD5
.Concat(Style.StringToByteArray(rom.HashData.CRC)) // CRC
.Concat(BitConverter.GetBytes(rom.HashData.Size).Reverse().ToArray()) // Long size (Mirrored)
.Concat(Style.StringToByteArray(rom.MD5)) // MD5
.Concat(Style.StringToByteArray(rom.CRC)) // CRC
.Concat(BitConverter.GetBytes(rom.Size).Reverse().ToArray()) // Long size (Mirrored)
.ToArray();
sw.Write(data);
@@ -414,7 +414,7 @@ namespace SabreTools.Helper
// If we're in romba mode, create the subfolder and move the file
if (romba)
{
string subfolder = Path.Combine(rom.HashData.SHA1.Substring(0, 2), rom.HashData.SHA1.Substring(2, 2), rom.HashData.SHA1.Substring(4, 2), rom.HashData.SHA1.Substring(6, 2));
string subfolder = Path.Combine(rom.SHA1.Substring(0, 2), rom.SHA1.Substring(2, 2), rom.SHA1.Substring(4, 2), rom.SHA1.Substring(6, 2));
outDir = Path.Combine(outDir, subfolder);
if (!Directory.Exists(outDir))
{
@@ -723,13 +723,10 @@ namespace SabreTools.Helper
Rom rom = new Rom
{
Type = ItemType.Rom,
HashData = new Hash
{
Size = input.Length - Math.Abs(offset),
CRC = string.Empty,
MD5 = string.Empty,
SHA1 = string.Empty,
},
Size = input.Length - Math.Abs(offset),
CRC = string.Empty,
MD5 = string.Empty,
SHA1 = string.Empty,
};
try
@@ -760,17 +757,17 @@ namespace SabreTools.Helper
}
crc.Update(buffer, 0, 0);
rom.HashData.CRC = crc.Value.ToString("X8").ToLowerInvariant();
rom.CRC = crc.Value.ToString("X8").ToLowerInvariant();
if (!noMD5)
{
md5.TransformFinalBlock(buffer, 0, 0);
rom.HashData.MD5 = BitConverter.ToString(md5.Hash).Replace("-", "").ToLowerInvariant();
rom.MD5 = BitConverter.ToString(md5.Hash).Replace("-", "").ToLowerInvariant();
}
if (!noSHA1)
{
sha1.TransformFinalBlock(buffer, 0, 0);
rom.HashData.SHA1 = BitConverter.ToString(sha1.Hash).Replace("-", "").ToLowerInvariant();
rom.SHA1 = BitConverter.ToString(sha1.Hash).Replace("-", "").ToLowerInvariant();
}
}
}
@@ -860,15 +857,9 @@ namespace SabreTools.Helper
{
Type = ItemType.Rom,
Name = reader.Entry.Key,
Machine = new Machine
{
Name = gamename,
},
HashData = new Hash
{
Size = (size == 0 ? reader.Entry.Size : size),
CRC = (crc == "" ? reader.Entry.Crc.ToString("X").ToLowerInvariant() : crc),
},
MachineName = gamename,
Size = (size == 0 ? reader.Entry.Size : size),
CRC = (crc == "" ? reader.Entry.Crc.ToString("X").ToLowerInvariant() : crc),
});
}
}
@@ -948,18 +939,12 @@ namespace SabreTools.Helper
Rom rom = new Rom
{
Type = ItemType.Rom,
Machine = new Machine
{
Name = Path.GetFileNameWithoutExtension(input).ToLowerInvariant(),
},
MachineName = Path.GetFileNameWithoutExtension(input).ToLowerInvariant(),
Name = Path.GetFileNameWithoutExtension(input).ToLowerInvariant(),
HashData = new Hash
{
Size = extractedsize,
CRC = gzcrc.ToLowerInvariant(),
MD5 = gzmd5.ToLowerInvariant(),
SHA1 = Path.GetFileNameWithoutExtension(input).ToLowerInvariant(),
},
Size = extractedsize,
CRC = gzcrc.ToLowerInvariant(),
MD5 = gzmd5.ToLowerInvariant(),
SHA1 = Path.GetFileNameWithoutExtension(input).ToLowerInvariant(),
};
return rom;

View File

@@ -1,305 +0,0 @@
using SharpCompress.Archive;
using SharpCompress.Common;
using SharpCompress.Reader;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text.RegularExpressions;
namespace SabreTools.Helper
{
public class FileToolsHash
{
#region Archive Writing
// 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
/// <summary>
/// Copy a file to an output archive
/// </summary>
/// <param name="input">Input filename to be moved</param>
/// <param name="output">Output directory to build to</param>
/// <param name="hash">RomData representing the new information</param>
/// <remarks>This uses the new system that is not implemented anywhere yet</remarks>
public static void WriteToArchive(string input, string output, RomData rom)
{
string archiveFileName = Path.Combine(output, rom.Machine + ".zip");
ZipArchive outarchive = null;
try
{
if (!File.Exists(archiveFileName))
{
outarchive = System.IO.Compression.ZipFile.Open(archiveFileName, ZipArchiveMode.Create);
}
else
{
outarchive = System.IO.Compression.ZipFile.Open(archiveFileName, ZipArchiveMode.Update);
}
if (File.Exists(input))
{
if (outarchive.Mode == ZipArchiveMode.Create || outarchive.GetEntry(rom.Name) == null)
{
outarchive.CreateEntryFromFile(input, rom.Name, CompressionLevel.Optimal);
}
}
else if (Directory.Exists(input))
{
foreach (string file in Directory.EnumerateFiles(input, "*", SearchOption.AllDirectories))
{
if (outarchive.Mode == ZipArchiveMode.Create || outarchive.GetEntry(file) == null)
{
outarchive.CreateEntryFromFile(file, file, CompressionLevel.Optimal);
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
finally
{
outarchive?.Dispose();
}
}
/// <summary>
/// Copy a file to an output archive using SharpCompress
/// </summary>
/// <param name="input">Input filename to be moved</param>
/// <param name="output">Output directory to build to</param>
/// <param name="rom">RomData representing the new information</param>
/// <remarks>This uses the new system that is not implemented anywhere yet</remarks>
public static void WriteToManagedArchive(string input, string output, RomData rom)
{
string archiveFileName = Path.Combine(output, rom.Machine + ".zip");
// Delete an empty file first
if (File.Exists(archiveFileName) && new FileInfo(archiveFileName).Length == 0)
{
File.Delete(archiveFileName);
}
// Get if the file should be written out
bool newfile = File.Exists(archiveFileName) && new FileInfo(archiveFileName).Length != 0;
using (SharpCompress.Archive.Zip.ZipArchive archive = (newfile
? ArchiveFactory.Open(archiveFileName, Options.LookForHeader) as SharpCompress.Archive.Zip.ZipArchive
: ArchiveFactory.Create(ArchiveType.Zip) as SharpCompress.Archive.Zip.ZipArchive))
{
try
{
if (File.Exists(input))
{
archive.AddEntry(rom.Name, input);
}
else if (Directory.Exists(input))
{
archive.AddAllFromDirectory(input, "*", SearchOption.AllDirectories);
}
archive.SaveTo(archiveFileName + ".tmp", CompressionType.Deflate);
}
catch (Exception)
{
// Don't log archive write errors
}
}
if (File.Exists(archiveFileName + ".tmp"))
{
File.Delete(archiveFileName);
File.Move(archiveFileName + ".tmp", archiveFileName);
}
}
#endregion
#region File Information
/// <summary>
/// Generate a list of HashData objects from the header values in an archive
/// </summary>
/// <param name="input">Input file to get data from</param>
/// <param name="logger">Logger object for file and console output</param>
/// <returns>List of HashData objects representing the found data</returns>
/// <remarks>This uses the new system that is not implemented anywhere yet</remarks>
public static List<HashData> GetArchiveFileHashes(string input, Logger logger)
{
List<HashData> hashes = new List<HashData>();
string gamename = Path.GetFileNameWithoutExtension(input);
// First get the archive type
ArchiveType? at = FileTools.GetCurrentArchiveType(input, logger);
// If we got back null, then it's not an archive, so we we return
if (at == null)
{
return hashes;
}
// If we got back GZip, try to get TGZ info first
else if (at == ArchiveType.GZip)
{
HashData possibleTgz = GetTorrentGZFileHash(input, logger);
// If it was, then add it to the outputs and continue
if (possibleTgz.Size != -1)
{
hashes.Add(possibleTgz);
return hashes;
}
}
IReader reader = null;
try
{
logger.Log("Found archive of type: " + at);
long size = 0;
byte[] crc = null;
// If we have a gzip file, get the crc directly
if (at == ArchiveType.GZip)
{
// Get the CRC and size from the file
using (BinaryReader br = new BinaryReader(File.OpenRead(input)))
{
br.BaseStream.Seek(-8, SeekOrigin.End);
crc = br.ReadBytes(4).Reverse().ToArray();
byte[] headersize = br.ReadBytes(4);
size = BitConverter.ToInt32(headersize.Reverse().ToArray(), 0);
}
}
reader = ReaderFactory.Open(File.OpenRead(input));
if (at != ArchiveType.Tar)
{
while (reader.MoveToNextEntry())
{
if (reader.Entry != null && !reader.Entry.IsDirectory)
{
logger.Log("Entry found: '" + reader.Entry.Key + "': "
+ (size == 0 ? reader.Entry.Size : size) + ", "
+ (crc == null ? BitConverter.GetBytes(reader.Entry.Crc) : crc));
RomData temprom = new RomData
{
Type = ItemType.Rom,
Name = reader.Entry.Key,
Machine = new MachineData
{
Name = gamename,
Description = gamename,
},
};
HashData temphash = new HashData
{
Size = (size == 0 ? reader.Entry.Size : size),
CRC = (crc == null ? BitConverter.GetBytes(reader.Entry.Crc) : crc),
MD5 = null,
SHA1 = null,
Roms = new List<RomData>(),
};
temphash.Roms.Add(temprom);
hashes.Add(temphash);
}
}
}
}
catch (Exception ex)
{
logger.Error(ex.ToString());
}
finally
{
reader?.Dispose();
}
return hashes;
}
/// <summary>
/// Retrieve file information for a single torrent GZ file
/// </summary>
/// <param name="input">Filename to get information from</param>
/// <param name="logger">Logger object for file and console output</param>
/// <returns>Populated HashData object if success, empty one on error</returns>
/// <remarks>This uses the new system that is not implemented anywhere yet</remarks>
public static HashData GetTorrentGZFileHash(string input, Logger logger)
{
string datum = Path.GetFileName(input).ToLowerInvariant();
string sha1 = Path.GetFileNameWithoutExtension(input).ToLowerInvariant();
long filesize = new FileInfo(input).Length;
// Check if the name is the right length
if (!Regex.IsMatch(datum, @"^[0-9a-f]{40}\.gz"))
{
logger.Warning("Non SHA-1 filename found, skipping: '" + datum + "'");
return new HashData();
}
// Check if the file is at least the minimum length
if (filesize < 40 /* bytes */)
{
logger.Warning("Possibly corrupt file '" + input + "' with size " + Style.GetBytesReadable(filesize));
return new HashData();
}
// Get the Romba-specific header data
byte[] header; // Get preamble header for checking
byte[] headermd5; // MD5
byte[] headercrc; // CRC
byte[] headersz; // Int64 size
using (BinaryReader br = new BinaryReader(File.OpenRead(input)))
{
header = br.ReadBytes(12);
headermd5 = br.ReadBytes(16);
headercrc = br.ReadBytes(4);
headersz = br.ReadBytes(8);
}
// If the header is not correct, return a blank rom
bool correct = true;
for (int i = 0; i < header.Length; i++)
{
correct &= (header[i] == Constants.TorrentGZHeader[i]);
}
if (!correct)
{
return new HashData();
}
// Now convert the size and get the right position
long extractedsize = (long)BitConverter.ToUInt64(headersz.Reverse().ToArray(), 0);
RomData temprom = new RomData
{
Type = ItemType.Rom,
Name = sha1,
Machine = new MachineData
{
Name = sha1,
Description = sha1,
},
};
HashData temphash = new HashData
{
Size = extractedsize,
CRC = headercrc,
MD5 = headermd5,
SHA1 = Style.StringToByteArray(sha1),
Roms = new List<RomData>(),
};
temphash.Roms.Add(temprom);
return temphash;
}
#endregion
}
}

View File

@@ -1,505 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace SabreTools.Helper
{
public class RomTools
{
#region Rom-based sorting and merging
/// <summary>
/// Determine if a rom should be included based on filters
/// </summary>
/// <param name="romdata">User supplied Rom to check</param>
/// <param name="gamename">Name of the game to match (can use asterisk-partials)</param>
/// <param name="romname">Name of the rom to match (can use asterisk-partials)</param>
/// <param name="romtype">Type of the rom to match</param>
/// <param name="sgt">Find roms greater than or equal to this size</param>
/// <param name="slt">Find roms less than or equal to this size</param>
/// <param name="seq">Find roms equal to this size</param>
/// <param name="crc">CRC of the rom to match (can use asterisk-partials)</param>
/// <param name="md5">MD5 of the rom to match (can use asterisk-partials)</param>
/// <param name="sha1">SHA-1 of the rom to match (can use asterisk-partials)</param>
/// <param name="nodump">Select roms with nodump status as follows: null (match all), true (match Nodump only), false (exclude Nodump)</param>
/// <param name="logger">Logging object for console and file output</param>
/// <returns>Returns true if it should be included, false otherwise</returns>
public static bool Filter(Rom romdata, string gamename, string romname, string romtype, long sgt,
long slt, long seq, string crc, string md5, string sha1, bool? nodump, Logger logger)
{
// Filter on nodump status
if (nodump == true && !romdata.Nodump)
{
return false;
}
if (nodump == false && romdata.Nodump)
{
return false;
}
// Filter on game name
if (!String.IsNullOrEmpty(gamename))
{
if (gamename.StartsWith("*") && gamename.EndsWith("*"))
{
if (!romdata.Machine.Name.ToLowerInvariant().Contains(gamename.ToLowerInvariant().Replace("*", "")))
{
return false;
}
}
else if (gamename.StartsWith("*"))
{
if (!romdata.Machine.Name.EndsWith(gamename.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else if (gamename.EndsWith("*"))
{
if (!romdata.Machine.Name.StartsWith(gamename.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else
{
if (!String.Equals(romdata.Machine.Name, gamename, StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
}
// Filter on rom name
if (!String.IsNullOrEmpty(romname))
{
if (romname.StartsWith("*") && romname.EndsWith("*"))
{
if (!romdata.Name.ToLowerInvariant().Contains(romname.ToLowerInvariant().Replace("*", "")))
{
return false;
}
}
else if (romname.StartsWith("*"))
{
if (!romdata.Name.EndsWith(romname.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else if (romname.EndsWith("*"))
{
if (!romdata.Name.StartsWith(romname.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else
{
if (!String.Equals(romdata.Name, romname, StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
}
// Filter on rom type
if (String.IsNullOrEmpty(romtype) && romdata.Type != ItemType.Rom && romdata.Type != ItemType.Disk)
{
return false;
}
if (!String.IsNullOrEmpty(romtype) && !String.Equals(romdata.Type.ToString(), romtype, StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
// Filter on rom size
if (seq != -1 && romdata.HashData.Size != seq)
{
return false;
}
else
{
if (sgt != -1 && romdata.HashData.Size < sgt)
{
return false;
}
if (slt != -1 && romdata.HashData.Size > slt)
{
return false;
}
}
// Filter on crc
if (!String.IsNullOrEmpty(crc))
{
if (crc.StartsWith("*") && crc.EndsWith("*"))
{
if (!romdata.HashData.CRC.ToLowerInvariant().Contains(crc.ToLowerInvariant().Replace("*", "")))
{
return false;
}
}
else if (crc.StartsWith("*"))
{
if (!romdata.HashData.CRC.EndsWith(crc.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else if (crc.EndsWith("*"))
{
if (!romdata.HashData.CRC.StartsWith(crc.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else
{
if (!String.Equals(romdata.HashData.CRC, crc, StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
}
// Filter on md5
if (!String.IsNullOrEmpty(md5))
{
if (md5.StartsWith("*") && md5.EndsWith("*"))
{
if (!romdata.HashData.MD5.ToLowerInvariant().Contains(md5.ToLowerInvariant().Replace("*", "")))
{
return false;
}
}
else if (md5.StartsWith("*"))
{
if (!romdata.HashData.MD5.EndsWith(md5.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else if (md5.EndsWith("*"))
{
if (!romdata.HashData.MD5.StartsWith(md5.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else
{
if (!String.Equals(romdata.HashData.MD5, md5, StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
}
// Filter on sha1
if (!String.IsNullOrEmpty(sha1))
{
if (sha1.StartsWith("*") && sha1.EndsWith("*"))
{
if (!romdata.HashData.SHA1.ToLowerInvariant().Contains(sha1.ToLowerInvariant().Replace("*", "")))
{
return false;
}
}
else if (sha1.StartsWith("*"))
{
if (!romdata.HashData.SHA1.EndsWith(sha1.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else if (sha1.EndsWith("*"))
{
if (!romdata.HashData.SHA1.StartsWith(sha1.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
else
{
if (!String.Equals(romdata.HashData.SHA1, sha1, StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
}
return true;
}
/// <summary>
/// Merge an arbitrary set of ROMs based on the supplied information
/// </summary>
/// <param name="inroms">List of RomData objects representing the roms to be merged</param>
/// <param name="logger">Logger object for console and/or file output</param>
/// <returns>A List of RomData objects representing the merged roms</returns>
public static List<Rom> Merge(List<Rom> inroms, Logger logger)
{
// Check for null or blank roms first
if (inroms == null || inroms.Count == 0)
{
return new List<Rom>();
}
// Create output list
List<Rom> outroms = new List<Rom>();
// Then deduplicate them by checking to see if data matches previous saved roms
foreach (Rom rom in inroms)
{
// If it's a nodump, add and skip
if (rom.Nodump)
{
outroms.Add(rom);
continue;
}
// If it's the first rom in the list, don't touch it
if (outroms.Count != 0)
{
// Check if the rom is a duplicate
DupeType dupetype = DupeType.None;
Rom savedrom = new Rom();
int pos = -1;
for (int i = 0; i < outroms.Count; i++)
{
Rom lastrom = outroms[i];
// Get the duplicate status
dupetype = GetDuplicateStatus(rom, lastrom, logger);
// If it's a duplicate, skip adding it to the output but add any missing information
if (dupetype != DupeType.None)
{
savedrom = lastrom;
pos = i;
savedrom.HashData.CRC = (String.IsNullOrEmpty(savedrom.HashData.CRC) && !String.IsNullOrEmpty(rom.HashData.CRC) ? rom.HashData.CRC : savedrom.HashData.CRC);
savedrom.HashData.MD5 = (String.IsNullOrEmpty(savedrom.HashData.MD5) && !String.IsNullOrEmpty(rom.HashData.MD5) ? rom.HashData.MD5 : savedrom.HashData.MD5);
savedrom.HashData.SHA1 = (String.IsNullOrEmpty(savedrom.HashData.SHA1) && !String.IsNullOrEmpty(rom.HashData.SHA1) ? rom.HashData.SHA1 : savedrom.HashData.SHA1);
savedrom.Dupe = dupetype;
// If the current system has a lower ID than the previous, set the system accordingly
if (rom.Metadata.SystemID < savedrom.Metadata.SystemID)
{
savedrom.Metadata.SystemID = rom.Metadata.SystemID;
savedrom.Metadata.System = rom.Metadata.System;
savedrom.Machine.Name = rom.Machine.Name;
savedrom.Name = rom.Name;
}
// If the current source has a lower ID than the previous, set the source accordingly
if (rom.Metadata.SourceID < savedrom.Metadata.SourceID)
{
savedrom.Metadata.SourceID = rom.Metadata.SourceID;
savedrom.Metadata.Source = rom.Metadata.Source;
savedrom.Machine.Name = rom.Machine.Name;
savedrom.Name = rom.Name;
}
break;
}
}
// If no duplicate is found, add it to the list
if (dupetype == DupeType.None)
{
outroms.Add(rom);
}
// Otherwise, if a new rom information is found, add that
else
{
outroms.RemoveAt(pos);
outroms.Insert(pos, savedrom);
}
}
else
{
outroms.Add(rom);
}
}
// Then return the result
return outroms;
}
/// <summary>
/// List all duplicates found in a DAT based on a rom
/// </summary>
/// <param name="lastrom">Rom to use as a base</param>
/// <param name="datdata">DAT to match against</param>
/// <param name="logger">Logger object for console and/or file output</param>
/// <param name="remove">True to remove matched roms from the input, false otherwise (default)</param>
/// <returns>List of matched RomData objects</returns>
public static List<Rom> GetDuplicates(Rom lastrom, Dat datdata, Logger logger, bool remove = false)
{
List<Rom> output = new List<Rom>();
// Check for an empty rom list first
if (datdata.Files == null || datdata.Files.Count == 0)
{
return output;
}
// Try to find duplicates
List<string> keys = datdata.Files.Keys.ToList();
foreach (string key in keys)
{
List<Rom> roms = datdata.Files[key];
List<Rom> left = new List<Rom>();
foreach (Rom rom in roms)
{
if (IsDuplicate(rom, lastrom, logger))
{
output.Add(rom);
}
else
{
left.Add(rom);
}
}
// If we're in removal mode, replace the list with the new one
if (remove)
{
datdata.Files[key] = left;
}
}
return output;
}
/// <summary>
/// Determine if a file is a duplicate using partial matching logic
/// </summary>
/// <param name="rom">Rom to check for duplicate status</param>
/// <param name="lastrom">Rom to use as a baseline</param>
/// <param name="logger">Logger object for console and/or file output</param>
/// <returns>True if the roms are duplicates, false otherwise</returns>
public static bool IsDuplicate(Rom rom, Rom lastrom, Logger logger)
{
bool dupefound = rom.Equals(lastrom);
// More wonderful SHA-1 logging that has to be done
if (rom.HashData.SHA1 == lastrom.HashData.SHA1 && rom.HashData.Size != lastrom.HashData.Size)
{
logger.User("SHA-1 mismatch - Hash: " + rom.HashData.SHA1);
}
return dupefound;
}
/// <summary>
/// Return the duplicate status of two roms
/// </summary>
/// <param name="rom">Current rom to check</param>
/// <param name="lastrom">Last rom to check against</param>
/// <param name="logger">Logger object for console and/or file output</param>
/// <returns>The DupeType corresponding to the relationship between the two</returns>
public static DupeType GetDuplicateStatus(Rom rom, Rom lastrom, Logger logger)
{
DupeType output = DupeType.None;
// If we don't have a duplicate at all, return none
if (!IsDuplicate(rom, lastrom, logger))
{
return output;
}
// If the duplicate is external already or should be, set it
if (lastrom.Dupe >= DupeType.ExternalHash || lastrom.Metadata.SystemID != rom.Metadata.SystemID || lastrom.Metadata.SourceID != rom.Metadata.SourceID)
{
if (lastrom.Machine.Name == rom.Machine.Name && lastrom.Name == rom.Name)
{
output = DupeType.ExternalAll;
}
else
{
output = DupeType.ExternalHash;
}
}
// Otherwise, it's considered an internal dupe
else
{
if (lastrom.Machine.Name == rom.Machine.Name && lastrom.Name == rom.Name)
{
output = DupeType.InternalAll;
}
else
{
output = DupeType.InternalHash;
}
}
return output;
}
/// <summary>
/// Sort a list of RomData objects by SystemID, SourceID, Game, and Name (in order)
/// </summary>
/// <param name="roms">List of RomData objects representing the roms to be sorted</param>
/// <param name="norename">True if files are not renamed, false otherwise</param>
/// <returns>True if it sorted correctly, false otherwise</returns>
public static bool Sort(ref List<Rom> roms, bool norename)
{
try
{
roms.Sort(delegate (Rom x, Rom y)
{
if (x.Metadata.SystemID == y.Metadata.SystemID)
{
if (x.Metadata.SourceID == y.Metadata.SourceID)
{
if (x.Machine.Name == y.Machine.Name)
{
if ((x.Type == ItemType.Rom || x.Type == ItemType.Disk) && (y.Type == ItemType.Rom || y.Type == ItemType.Disk))
{
if (Path.GetDirectoryName(x.Name) == Path.GetDirectoryName(y.Name))
{
return Style.CompareNumeric(Path.GetFileName(x.Name), Path.GetFileName(y.Name));
}
return Style.CompareNumeric(Path.GetDirectoryName(x.Name), Path.GetDirectoryName(y.Name));
}
else if ((x.Type == ItemType.Rom || x.Type == ItemType.Disk) && (y.Type != ItemType.Rom && y.Type != ItemType.Disk))
{
return -1;
}
else if ((x.Type != ItemType.Rom && x.Type != ItemType.Disk) && (y.Type == ItemType.Rom || y.Type == ItemType.Disk))
{
return 1;
}
else
{
if (Path.GetDirectoryName(x.Name) == Path.GetDirectoryName(y.Name))
{
return Style.CompareNumeric(Path.GetFileName(x.Name), Path.GetFileName(y.Name));
}
return Style.CompareNumeric(Path.GetDirectoryName(x.Name), Path.GetDirectoryName(y.Name));
}
}
return Style.CompareNumeric(x.Machine.Name, y.Machine.Name);
}
return (norename ? Style.CompareNumeric(x.Machine.Name, y.Machine.Name) : x.Metadata.SourceID - y.Metadata.SourceID);
}
return (norename ? Style.CompareNumeric(x.Machine.Name, y.Machine.Name) : x.Metadata.SystemID - y.Metadata.SystemID);
});
return true;
}
catch (Exception)
{
// Absorb the error
return false;
}
}
#endregion
}
}

View File

@@ -1,225 +0,0 @@
using System.Collections.Generic;
namespace SabreTools.Helper
{
public class RomToolsHash
{
#region HashData-based sorting and merging
/// <summary>
/// Merge an arbitrary set of ROMs based on the supplied information
/// </summary>
/// <param name="inhashes">List of HashData objects representing the roms to be merged</param>
/// <param name="logger">Logger object for console and/or file output</param>
/// <returns>A List of HashData objects representing the merged roms</returns>
public static List<HashData> Merge(List<HashData> inhashes, Logger logger)
{
// Create output list
List<HashData> outroms = new List<HashData>();
// Check for null or blank roms first
if (inhashes == null || inhashes.Count == 0)
{
return outroms;
}
// Then deduplicate them by checking to see if data matches previous saved roms
foreach (HashData hash in inhashes)
{
// If it's a nodump, add and skip
if (hash.Roms[0].Nodump)
{
outroms.Add(hash);
continue;
}
// If it's the first rom in the list, don't touch it
if (outroms.Count != 0)
{
// Check if the rom is a duplicate
DupeType dupetype = DupeType.None;
HashData savedHash = new HashData();
int pos = -1;
for (int i = 0; i < outroms.Count; i++)
{
HashData lastrom = outroms[i];
RomData savedRom = savedHash.Roms[0];
MachineData savedMachine = savedRom.Machine;
// Get the duplicate status
dupetype = GetDuplicateStatus(hash, lastrom, logger);
// If it's a duplicate, skip adding it to the output but add any missing information
if (dupetype != DupeType.None)
{
savedHash = lastrom;
pos = i;
savedHash.CRC = (savedHash.CRC == null && hash.CRC != null ? hash.CRC : savedHash.CRC);
savedHash.MD5 = (savedHash.MD5 == null && hash.MD5 != null ? hash.MD5 : savedHash.MD5);
savedHash.SHA1 = (savedHash.SHA1 == null && hash.SHA1 != null ? hash.SHA1 : savedHash.SHA1);
savedRom.DupeType = dupetype;
// If the current system has a lower ID than the previous, set the system accordingly
if (hash.Roms[0].Machine.SystemID < savedMachine.SystemID)
{
savedMachine.SystemID = hash.Roms[0].Machine.SystemID;
savedMachine.System = hash.Roms[0].Machine.System;
savedMachine.Name = hash.Roms[0].Machine.Name;
savedRom.Name = hash.Roms[0].Name;
}
// If the current source has a lower ID than the previous, set the source accordingly
if (hash.Roms[0].Machine.SourceID < savedMachine.SourceID)
{
savedMachine.SourceID = hash.Roms[0].Machine.SourceID;
savedMachine.Source = hash.Roms[0].Machine.Source;
savedMachine.Name = hash.Roms[0].Machine.Name;
savedRom.Name = hash.Roms[0].Name;
}
break;
}
}
// If no duplicate is found, add it to the list
if (dupetype == DupeType.None)
{
outroms.Add(hash);
}
// Otherwise, if a new rom information is found, add that
else
{
outroms.RemoveAt(pos);
outroms.Insert(pos, savedHash);
}
}
else
{
outroms.Add(hash);
}
}
// Then return the result
return outroms;
}
/*
/// <summary>
/// List all duplicates found in a DAT based on a rom
/// </summary>
/// <param name="lastrom">Hash to use as a base</param>
/// <param name="datdata">DAT to match against</param>
/// <param name="logger">Logger object for console and/or file output</param>
/// <param name="remove">True to remove matched roms from the input, false otherwise (default)</param>
/// <returns>List of matched HashData objects</returns>
public static List<HashData> GetDuplicates(HashData lastrom, DatData datdata, Logger logger, bool remove = false)
{
List<HashData> output = new List<HashData>();
// Check for an empty rom list first
if (datdata.Hashes == null || datdata.Hashes.Count == 0)
{
return output;
}
// Try to find duplicates
for (int i = 0; i < datdata.Hashes.Count; i++)
{
List<Rom> roms = datdata.Files[key];
List<Rom> left = new List<Rom>();
foreach (Rom rom in roms)
{
if (IsDuplicate(rom, lastrom, logger))
{
output.Add(rom);
}
else
{
left.Add(rom);
}
}
// If we're in removal mode, replace the list with the new one
if (remove)
{
datdata.Files[key] = left;
}
}
return output;
}
*/
/// <summary>
/// Determine if a file is a duplicate using partial matching logic
/// </summary>
/// <param name="hash">Hash to check for duplicate status</param>
/// <param name="lastHash">Hash to use as a baseline</param>
/// <param name="logger">Logger object for console and/or file output</param>
/// <returns>True if the hashes are duplicates, false otherwise</returns>
public static bool IsDuplicate(HashData hash, int hashIndex, HashData lastHash, int lastHashIndex, Logger logger)
{
bool dupefound = hash.Equals(lastHash);
// More wonderful SHA-1 logging that has to be done
if (hash.SHA1 == lastHash.SHA1 && hash.Size != lastHash.Size)
{
logger.User("SHA-1 mismatch - Hash: " + hash.SHA1);
}
return dupefound;
}
/// <summary>
/// Return the duplicate status of two hashes
/// </summary>
/// <param name="hash">Current hash to check</param>
/// <param name="lasthash">Last hash to check against</param>
/// <param name="logger">Logger object for console and/or file output</param>
/// <returns>The DupeType corresponding to the relationship between the two</returns>
public static DupeType GetDuplicateStatus(HashData hash, HashData lasthash, Logger logger)
{
DupeType output = DupeType.None;
/*
// If we don't have a duplicate at all, return none
if (!IsDuplicate(hash, lasthash, logger))
{
return output;
}
*/
// If the duplicate is external already or should be, set it
if (lasthash.Roms[0].DupeType >= DupeType.ExternalHash || lasthash.Roms[0].Machine.SystemID != hash.Roms[0].Machine.SystemID || lasthash.Roms[0].Machine.SourceID != hash.Roms[0].Machine.SourceID)
{
if (lasthash.Roms[0].Machine.Name == hash.Roms[0].Machine.Name && lasthash.Roms[0].Name == hash.Roms[0].Name)
{
output = DupeType.ExternalAll;
}
else
{
output = DupeType.ExternalHash;
}
}
// Otherwise, it's considered an internal dupe
else
{
if (lasthash.Roms[0].Machine.Name == hash.Roms[0].Machine.Name && lasthash.Roms[0].Name == hash.Roms[0].Name)
{
output = DupeType.InternalAll;
}
else
{
output = DupeType.InternalHash;
}
}
return output;
}
#endregion
}
}

View File

@@ -154,7 +154,7 @@ namespace SabreTools.Helper
/// <param name="datdata">DAT information</param>
/// <param name="overwrite">True if we ignore existing files (default), false otherwise</param>
/// <returns>Dictionary of output formats mapped to file names</returns>
public static Dictionary<OutputFormat, string> CreateOutfileNames(string outDir, Dat datdata, bool overwrite = true)
public static Dictionary<OutputFormat, string> CreateOutfileNames(string outDir, DatFile datdata, bool overwrite = true)
{
// Create the output dictionary
Dictionary<OutputFormat, string> outfileNames = new Dictionary<OutputFormat, string>();
@@ -214,7 +214,7 @@ namespace SabreTools.Helper
/// <param name="datdata">DAT information</param>
/// <param name="overwrite">True if we ignore existing files, false otherwise</param>
/// <returns>String containing the new filename</returns>
private static string CreateOutfileNamesHelper(string outDir, string extension, Dat datdata, bool overwrite)
private static string CreateOutfileNamesHelper(string outDir, string extension, DatFile datdata, bool overwrite)
{
string filename = (String.IsNullOrEmpty(datdata.FileName) ? datdata.Description : datdata.FileName);
string outfile = outDir + filename + extension;

View File

@@ -78,7 +78,7 @@ namespace SabreTools
}
}
SimpleSort ss = new SimpleSort(new Dat(), newinputs, outDir, tempDir, false, false, false, delete, false, romba, sevenzip, gz, rar, zip, false, logger);
SimpleSort ss = new SimpleSort(new DatFile(), newinputs, outDir, tempDir, false, false, false, delete, false, romba, sevenzip, gz, rar, zip, false, logger);
return ss.Convert();
}
@@ -127,7 +127,7 @@ namespace SabreTools
int maxDegreeOfParallelism)
{
// Create a new DATFromDir object and process the inputs
Dat basedat = new Dat
DatFile basedat = new DatFile
{
FileName = filename,
Name = name,
@@ -140,7 +140,7 @@ namespace SabreTools
OutputFormat = (outputFormat == 0 ? OutputFormat.Xml : outputFormat),
Romba = romba,
Type = (superdat ? "SuperDAT" : ""),
Files = new Dictionary<string, List<Rom>>(),
Files = new Dictionary<string, List<DatItem>>(),
};
// For each input directory, create a DAT
@@ -149,8 +149,8 @@ namespace SabreTools
if (Directory.Exists(path))
{
// Clone the base Dat for information
Dat datdata = (Dat)basedat.Clone();
datdata.Files = new Dictionary<string, List<Rom>>();
DatFile datdata = (DatFile)basedat.Clone();
datdata.Files = new Dictionary<string, List<DatItem>>();
string basePath = Path.GetFullPath(path);
DATFromDir dfd = new DATFromDir(basePath, datdata, noMD5, noSHA1, bare, archivesAsFiles, enableGzip, addBlanks, addDate, tempDir, maxDegreeOfParallelism, _logger);
@@ -159,7 +159,7 @@ namespace SabreTools
// If it was a success, write the DAT out
if (success)
{
DatTools.WriteDatfile(dfd.DatData, "", _logger);
DatFile.WriteDatfile(dfd.DatData, "", _logger);
}
// Otherwise, show the help
@@ -190,13 +190,13 @@ namespace SabreTools
{
if (File.Exists(input))
{
DatTools.SplitByExt(Path.GetFullPath(input), outDir, Path.GetDirectoryName(input), extaList, extbList, _logger);
DatFile.SplitByExt(Path.GetFullPath(input), outDir, Path.GetDirectoryName(input), extaList, extbList, _logger);
}
else if (Directory.Exists(input))
{
foreach (string file in Directory.EnumerateFiles(input, "*", SearchOption.AllDirectories))
{
DatTools.SplitByExt(file, outDir, (input.EndsWith(Path.DirectorySeparatorChar.ToString()) ? input : input + Path.DirectorySeparatorChar), extaList, extbList, _logger);
DatFile.SplitByExt(file, outDir, (input.EndsWith(Path.DirectorySeparatorChar.ToString()) ? input : input + Path.DirectorySeparatorChar), extaList, extbList, _logger);
}
}
else
@@ -271,13 +271,13 @@ namespace SabreTools
{
if (File.Exists(input))
{
DatTools.SplitByHash(Path.GetFullPath(input), outDir, Path.GetDirectoryName(input), _logger);
DatFile.SplitByHash(Path.GetFullPath(input), outDir, Path.GetDirectoryName(input), _logger);
}
else if (Directory.Exists(input))
{
foreach (string file in Directory.EnumerateFiles(input, "*", SearchOption.AllDirectories))
{
DatTools.SplitByHash(file, outDir, (input.EndsWith(Path.DirectorySeparatorChar.ToString()) ? input : input + Path.DirectorySeparatorChar), _logger);
DatFile.SplitByHash(file, outDir, (input.EndsWith(Path.DirectorySeparatorChar.ToString()) ? input : input + Path.DirectorySeparatorChar), _logger);
}
}
else
@@ -384,10 +384,10 @@ namespace SabreTools
bool toFolder, bool verify, bool delete, bool? torrentX, bool romba, int sevenzip, int gz, int rar, int zip, bool updateDat, Logger logger)
{
// Add all of the input DATs into one huge internal DAT
Dat datdata = new Dat();
DatFile datdata = new DatFile();
foreach (string datfile in datfiles)
{
DatTools.Parse(datfile, 99, 99, ref datdata, logger);
DatFile.Parse(datfile, 99, 99, ref datdata, logger);
}
SimpleSort ss = new SimpleSort(datdata, inputs, outDir, tempDir, quickScan, toFolder, verify,
@@ -438,13 +438,13 @@ namespace SabreTools
{
if (File.Exists(input))
{
DatTools.SplitByType(Path.GetFullPath(input), outDir, Path.GetFullPath(Path.GetDirectoryName(input)), _logger);
DatFile.SplitByType(Path.GetFullPath(input), outDir, Path.GetFullPath(Path.GetDirectoryName(input)), _logger);
}
else if (Directory.Exists(input))
{
foreach (string file in Directory.EnumerateFiles(input, "*", SearchOption.AllDirectories))
{
DatTools.SplitByType(file, outDir, Path.GetFullPath((input.EndsWith(Path.DirectorySeparatorChar.ToString()) ? input : input + Path.DirectorySeparatorChar)), _logger);
DatFile.SplitByType(file, outDir, Path.GetFullPath((input.EndsWith(Path.DirectorySeparatorChar.ToString()) ? input : input + Path.DirectorySeparatorChar)), _logger);
}
}
else
@@ -671,7 +671,7 @@ namespace SabreTools
}
// Populate the DatData object
Dat userInputDat = new Dat
DatFile userInputDat = new DatFile
{
FileName = filename,
Name = name,
@@ -705,7 +705,7 @@ namespace SabreTools
XSV = tsv,
};
DatTools.Update(inputs, userInputDat, outputFormat, outDir, merge, diffMode, cascade, inplace, skip, bare, clean, softlist,
DatFile.Update(inputs, userInputDat, outputFormat, outDir, merge, diffMode, cascade, inplace, skip, bare, clean, softlist,
gamename, romname, romtype, sgt, slt, seq, crc, md5, sha1, nodump, trim, single, root, maxDegreeOfParallelism, _logger);
}

View File

@@ -251,10 +251,10 @@ namespace SabreTools
bool toFolder, bool verify, bool delete, bool? torrentX, bool romba, int sevenzip, int gz, int rar, int zip, bool updateDat, Logger logger)
{
// Add all of the input DATs into one huge internal DAT
Dat datdata = new Dat();
DatFile datdata = new DatFile();
foreach (string datfile in datfiles)
{
DatTools.Parse(datfile, 99, 99, ref datdata, logger, keep: true, softlist: true);
DatFile.Parse(datfile, 99, 99, ref datdata, logger, keep: true, softlist: true);
}
SimpleSort ss = new SimpleSort(datdata, inputs, outDir, tempDir, quickScan, toFolder, verify,
@@ -295,7 +295,7 @@ namespace SabreTools
}
}
SimpleSort ss = new SimpleSort(new Dat(), newinputs, outDir, tempDir, false, false, false,
SimpleSort ss = new SimpleSort(new DatFile(), newinputs, outDir, tempDir, false, false, false,
delete, false, romba, sevenzip, gz, rar, zip, false, logger);
return ss.Convert();
}