diff --git a/.gitignore b/.gitignore index 259b6791..c70037b5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,9 +2,6 @@ /DATabase/obj /DATabase/obj/Debug /DATabase/obj/Release -/DATabaseTwo/obj -/DATabaseTwo/obj/Debug -/DATabaseTwo/obj/Release /DATFromDir/obj /DATFromDir/obj/Debug /DATFromDir/obj/Release diff --git a/DATabase/DATabase.cs b/DATabase/DATabase.cs index 7d5017cf..5488acbe 100644 --- a/DATabase/DATabase.cs +++ b/DATabase/DATabase.cs @@ -11,13 +11,29 @@ namespace SabreTools /// /// Entry class for the DATabase application /// + /// + /// The following features are missing from DATabaseTwo with respect to the original DATabase: + /// - Source merging + /// - Custom DATs based on a system and a source + /// - Multi-source and multi-system DATs + /// + /// The following features need to (want to) be implemented in DATabaseTwo for further stability + /// - Import updating file locations and names when SHA-1 hashes are matched + /// - True duplicate DATs being removed from the import folder (SHA-1 matches) + /// - Generate All only generating DATs that have been recently updated + /// + This requires implementing a "last updated" data point for all DATs and tracking for "last generate" somewhere + /// - Impelement a ToSort folder for DATs that will place DATs in the correct subfolder on Import + /// public class DATabase { - private static Logger logger; - private static string _dbName = "DATabase.sqlite"; - //private static string _dbName = "SabreTools.sqlite"; + // Private required variables + private static string _datroot = "DATS"; + private static string _outroot = "Output"; + private static string _dbName = "dats.sqlite"; private static string _connectionString = "Data Source=" + _dbName + ";Version = 3;"; + private static Logger _logger; + /// /// Start menu or use supplied parameters /// @@ -25,8 +41,8 @@ namespace SabreTools public static void Main(string[] args) { // Perform initial setup and verification - logger = new Logger(true, "database.log"); - logger.Start(); + _logger = new Logger(true, "database.log"); + _logger.Start(); DBTools.EnsureDatabase(_dbName, _connectionString); Remapping.CreateRemappings(); Console.Clear(); @@ -35,7 +51,7 @@ namespace SabreTools if ((new List(args)).Contains("--credits")) { Build.Credits(); - logger.Close(); + _logger.Close(); return; } @@ -43,7 +59,7 @@ namespace SabreTools if (args.Length == 0) { ShowMainMenu(); - logger.Close(); + _logger.Close(); return; } @@ -66,6 +82,7 @@ namespace SabreTools generate = false, genall = false, hashsplit = false, + ignore = false, import = false, inplace = false, listsrc = false, @@ -179,6 +196,10 @@ namespace SabreTools case "--import": import = true; break; + case "-ig": + case "--ignore": + ignore = true; + break; case "-ip": case "--inplace": inplace = true; @@ -321,10 +342,10 @@ namespace SabreTools } else { - logger.Error("Invalid input detected: " + arg); + _logger.Error("Invalid input detected: " + arg); Console.WriteLine(); Build.Help(); - logger.Close(); + _logger.Close(); return; } break; @@ -341,9 +362,9 @@ namespace SabreTools if (help || !(add ^ (convertMiss || romba) ^ convertCMP ^ convertRC ^ convertSD ^ convertXml ^ extsplit ^ generate ^ genall ^ hashsplit ^ import ^ listsrc ^ listsys ^ (merge || diff) ^ rem ^ stats ^ trim)) { - logger.Error("Only one feature switch is allowed at a time"); + _logger.Error("Only one feature switch is allowed at a time"); Build.Help(); - logger.Close(); + _logger.Close(); return; } @@ -351,9 +372,9 @@ namespace SabreTools if (inputs.Count == 0 && ((convertMiss || romba) || convertCMP || convertRC || convertSD || convertXml || extsplit || hashsplit || import || (merge || diff) || stats || trim)) { - logger.Error("This feature requires at least one input"); + _logger.Error("This feature requires at least one input"); Build.Help(); - logger.Close(); + _logger.Close(); return; } @@ -362,22 +383,21 @@ namespace SabreTools // Import a file or folder if (import) { - foreach (string input in inputs) - { - InitImport(input); - } + InitImport(ignore); } // Generate a DAT else if (generate) { - InitGenerate(systems, sources, outdir, norename, old); + InitImport(ignore); + InitGenerate(systems, norename, old); } // Generate all DATs else if (genall) { - InitGenerateAll(outdir, norename, old); + InitImport(ignore); + InitGenerateAll(norename, old); } // List all available sources @@ -507,7 +527,7 @@ namespace SabreTools InitStats(inputs, single); } - logger.Close(); + _logger.Close(); return; } @@ -529,8 +549,8 @@ namespace SabreTools Make a selection: 1) Show command line usage - 2) Import a DAT file or folder - 3) Generate DAT files + 2) Check for new or changed DATs + 3) Generate System DATs 4) DAT file tools 5) List all available sources 6) List all available systems @@ -593,21 +613,33 @@ Make a selection: private static void ImportMenu() { string selection = ""; + bool ignore = false; while (selection.ToLowerInvariant() != "b") { Console.Clear(); - Build.Start("DATabase"); + Build.Start("DATabaseTwo"); Console.WriteLine(@"IMPORT MENU =========================== -Enter the name of a DAT file or folder containing DAT files -or 'b' to go back to the previous menu:"); +Make a selection: + + 1) " + (ignore ? "Enable new source prompt" : "Disable new source prompt") + @" + 2) Begin import process + B) Go back to the previous menu +"); Console.Write("Enter selection: "); selection = Console.ReadLine(); - if (selection.ToLowerInvariant() != "b") + switch (selection) { - InitImport(selection); - Console.Write("\nPress any key to continue..."); - Console.ReadKey(); + case "1": + ignore = !ignore; + break; + case "2": + Console.Clear(); + InitImport(ignore); + Console.Write("\nPress any key to continue..."); + Console.ReadKey(); + ignore = false; + break; } } return; @@ -618,23 +650,21 @@ or 'b' to go back to the previous menu:"); /// private static void GenerateMenu() { - string selection = "", systems = "", sources = "", outdir = ""; + string selection = "", system = ""; bool norename = false, old = false; while (selection.ToLowerInvariant() != "b") { Console.Clear(); - Build.Start("DATabase"); + Build.Start("DATabaseTwo"); Console.WriteLine(@"GENERATE MENU =========================== Make a selection: 1) " + (norename ? "Enable game renaming" : "Disable game renaming") + @" 2) " + (old ? "Enable XML output" : "Enable ClrMamePro output") + @" - 3) List of systems to generate from" + (systems != "" ? ": " + systems : "") + @" - 4) List of sources to generate from" + (sources != "" ? ": " + sources : "") + @" - 5) Enter an output folder" + (outdir != "" ? ":\n\t" + outdir : "") + @" - 6) Generate the DAT file - 7) Generate all available DAT files + 3) System ID to generate from" + (system != "" ? ": " + system : "") + @" + 4) Generate the DAT file for the specified system + 5) Generate all DAT files B) Go back to the previous menu "); Console.Write("Enter selection: "); @@ -650,34 +680,23 @@ Make a selection: case "3": Console.Clear(); ListSystems(); - Console.Write("Please enter the systems separated by commas: "); - systems = Console.ReadLine(); + Console.Write("Please enter the System ID: "); + system = Console.ReadLine(); break; case "4": Console.Clear(); - ListSources(); - Console.Write("Please enter the sources separated by commas: "); - sources = Console.ReadLine(); + InitGenerate(system, norename, old); + Console.Write("\nPress any key to continue..."); + Console.ReadKey(); + system = ""; + norename = false; old = false; break; case "5": Console.Clear(); - Console.Write("Please enter a folder name: "); - outdir = Console.ReadLine(); - break; - case "6": - Console.Clear(); - InitGenerate(systems, sources, outdir, norename, old); + InitGenerateAll(norename, old); Console.Write("\nPress any key to continue..."); Console.ReadKey(); - systems = ""; sources = ""; outdir = ""; - norename = false; old = false; - break; - case "7": - Console.Clear(); - InitGenerateAll(outdir, norename, old); - Console.Write("\nPress any key to continue..."); - Console.ReadKey(); - systems = ""; sources = ""; outdir = ""; + system = ""; norename = false; old = false; break; } @@ -1267,7 +1286,7 @@ Make a selection: break; case "4": Console.Clear(); - ListSystems(true); + ListSystems(); Console.Write("Please enter the system: "); InitRemoveSystem(Console.ReadLine()); Console.Write("\nPress any key to continue..."); @@ -1284,73 +1303,38 @@ Make a selection: #region Init Methods /// - /// Wrap importing a file or folder into the database + /// Wrap importing and updating DATs /// - /// File or folder to be imported - private static void InitImport(string filename) + /// + private static void InitImport(bool ignore) { - Console.Clear(); - - // Drag and drop means quotes; we don't want quotes - filename = filename.Replace("\"", ""); - - // Check to see if the second argument is a file that exists - if (filename != "" && File.Exists(filename)) - { - logger.User("Beginning import of " + filename); - IImport imp = new Import(filename, _connectionString, logger); - bool success = imp.ImportData(); - logger.User(filename + (success ? "" : " not") + " imported!"); - } - // Check to see if the second argument is a directory that exists - else if (filename != "" && Directory.Exists(filename)) - { - foreach (string file in Directory.GetFiles(filename, "*", SearchOption.AllDirectories)) - { - logger.User("Beginning import of " + file); - IImport imp = new Import(file, _connectionString, logger); - bool success = imp.ImportData(); - logger.User(file + (success ? "" : " not") + " imported!"); - } - } - else - { - logger.Error("I'm sorry but " + filename + " doesn't exist!"); - } - return; + IImport imp = new ImportTwo(_datroot, _connectionString, _logger, ignore); + imp.ImportData(); } /// - /// Wrap generating a DAT from the database + /// Wrap generating a DAT from the library /// - /// Comma-separated list of systems to be included in the DAT (blank means all) - /// Comma-separated list of sources to be included in the DAT (blank means all) + /// System ID to be used in the DAT (blank means all) /// True if files should not be renamed with system and/or source in merged mode (default false) /// True if the output file should be in ClrMamePro format (default false) - private static void InitGenerate(string systems, string sources, string outdir, bool norename, bool old) + private static void InitGenerate(string systemid, bool norename, bool old) { - IGenerate gen = new Generate(systems, sources, outdir, _connectionString, logger, norename, old); + IGenerate gen = new GenerateTwo(systemid, "" /* sourceid */, _datroot, _outroot, _connectionString, _logger, norename, old); gen.Export(); - return; } /// - /// Wrap generating all standard DATs from the database + /// Wrap generating all standard DATs from the library /// - /// True if files should not be renamed with system and/or source in merged mode (default false) - /// True if the output file should be in ClrMamePro format (default false) - private static void InitGenerateAll(string outdir, bool norename, bool old) + private static void InitGenerateAll(bool norename, bool old) { - string actualdir = (outdir == "" ? Environment.CurrentDirectory + Path.DirectorySeparatorChar : - (!outdir.EndsWith(Path.DirectorySeparatorChar.ToString()) ? outdir + Path.DirectorySeparatorChar : outdir)); - outdir = actualdir + "temp" + Path.DirectorySeparatorChar; - - // Generate system-merged - string query = "SELECT DISTINCT systems.id FROM systems JOIN games ON systems.id=games.system ORDER BY systems.manufacturer, systems.system"; - //string query = "SELECT DISTINCT system.id FROM system JOIN gamesystem ON system.id=gamesystem.systemid ORDER BY system.manufacturer, system.name"; + List systems = new List(); using (SqliteConnection dbc = new SqliteConnection(_connectionString)) { dbc.Open(); + + string query = "SELECT id FROM system"; using (SqliteCommand slc = new SqliteCommand(query, dbc)) { using (SqliteDataReader sldr = slc.ExecuteReader()) @@ -1358,103 +1342,24 @@ Make a selection: // If nothing is found, tell the user and exit if (!sldr.HasRows) { - logger.Error("No systems found! Please add a source and then try again."); + _logger.Warning("No systems found! Please add a system and then try again."); return; } while (sldr.Read()) { - InitGenerate(sldr.GetInt32(0).ToString(), "", outdir, norename, old); - - // Generate custom - string squery = @"SELECT DISTINCT sources.id - FROM systems - JOIN games - ON systems.id=games.system - JOIN sources - ON games.source=sources.id - WHERE systems.id=" + sldr.GetInt32(0).ToString() + @" - ORDER BY sources.name"; - /* - string squery = @"SELECT DISTINCT source.id - FROM system - JOIN gamesystem - ON system.id=gamesystem.systemid - JOIN gamesource - ON gamesystem.game=gamesource.game - JOIN source - ON gamesource.sourceid=source.id - WHERE system.id=" + sldr.GetInt32(0).ToString() + @" - ORDER BY source.name"; - */ - - using (SqliteCommand sslc = new SqliteCommand(squery, dbc)) - { - using (SqliteDataReader ssldr = sslc.ExecuteReader()) - { - // If nothing is found, tell the user and exit - if (!ssldr.HasRows) - { - logger.Error("No sources found! Please add a source and then try again."); - return; - } - - while (ssldr.Read()) - { - InitGenerate(sldr.GetInt32(0).ToString(), ssldr.GetInt32(0).ToString(), outdir, norename, old); - } - } - } + systems.Add(sldr.GetInt32(0).ToString()); } } } - // Generate source-merged - query = "SELECT DISTINCT sources.id, sources.name FROM sources JOIN games ON sources.id=games.source ORDER BY sources.name"; - //query = "SELECT DISTINCT source.id, source.name FROM source JOIN gamesource ON source.id=gamesource.sourceid ORDER BY source.name"; - - using (SqliteCommand slc = new SqliteCommand(query, dbc)) + // Loop through the inputs + foreach (string system in systems) { - using (SqliteDataReader sldr = slc.ExecuteReader()) - { - // If nothing is found, tell the user and exit - if (!sldr.HasRows) - { - logger.Error("No sources found! Please add a source and then try again."); - return; - } - - while (sldr.Read()) - { - InitGenerate("", sldr.GetInt32(0).ToString(), outdir, norename, old); - } - } + _logger.User("Generating DAT for system id " + system); + InitGenerate(system, norename, old); } } - - // Generate MEGAMERGED - InitGenerate("", "", outdir, norename, old); - - // Zip up all of the files that were generated - logger.User("Creating zip archive"); - ZipArchive zip = ZipFile.Open(actualdir + "dats-" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".zip", ZipArchiveMode.Create); - foreach (String filename in Directory.EnumerateFiles(outdir)) - { - if (filename.EndsWith(".xml") || filename.EndsWith(".dat")) - { - string internalFolder = (filename.Contains("ALL (Merged") ? "" : - filename.Contains("Merged") ? "merged-system/" : - filename.Contains("ALL") ? "merged-source/" : "custom/"); - zip.CreateEntryFromFile(filename, internalFolder + Path.GetFileName(filename), CompressionLevel.Optimal); - } - } - zip.Dispose(); - logger.User("Zip archive created!"); - - // Remove all of the DATs from the folder - Directory.Delete(outdir, true); - - return; } /// @@ -1474,13 +1379,13 @@ Make a selection: if (File.Exists(filename)) { - logger.User("Converting \"" + Path.GetFileName(filename) + "\""); + _logger.User("Converting \"" + Path.GetFileName(filename) + "\""); DatData datdata = new DatData { OutputFormat = outputFormat, MergeRoms = false, }; - datdata = RomManipulation.Parse(filename, 0, 0, datdata, logger, true); + datdata = RomManipulation.Parse(filename, 0, 0, datdata, _logger, true); // Sometimes the description doesn't match the filename, change this if (datdata.Description != Path.GetFileNameWithoutExtension(filename)) @@ -1495,7 +1400,7 @@ Make a selection: datdata.Description += ".new"; } - Output.WriteDatfile(datdata, (outdir == "" ? Path.GetDirectoryName(filename) : outdir), logger); + Output.WriteDatfile(datdata, (outdir == "" ? Path.GetDirectoryName(filename) : outdir), _logger); } else if (Directory.Exists(filename)) { @@ -1503,13 +1408,13 @@ Make a selection: foreach (string file in Directory.EnumerateFiles(filename, "*", SearchOption.AllDirectories)) { - logger.User("Converting \"" + Path.GetFullPath(file).Remove(0, filename.Length) + "\""); + _logger.User("Converting \"" + Path.GetFullPath(file).Remove(0, filename.Length) + "\""); DatData datdata = new DatData { OutputFormat = outputFormat, MergeRoms = false, }; - datdata = RomManipulation.Parse(file, 0, 0, datdata, logger, true); + datdata = RomManipulation.Parse(file, 0, 0, datdata, _logger, true); // If the extension matches, append ".new" to the filename string extension = (datdata.OutputFormat == OutputFormat.Xml || datdata.OutputFormat == OutputFormat.SabreDat ? ".xml" : ".dat"); @@ -1518,12 +1423,12 @@ Make a selection: datdata.FileName += ".new"; } - Output.WriteDatfile(datdata, (outdir == "" ? Path.GetDirectoryName(file) : outdir + Path.GetDirectoryName(file).Remove(0, filename.Length - 1)), logger); + Output.WriteDatfile(datdata, (outdir == "" ? Path.GetDirectoryName(file) : outdir + Path.GetDirectoryName(file).Remove(0, filename.Length - 1)), _logger); } } else { - logger.Error("I'm sorry but " + filename + " doesn't exist!"); + _logger.Error("I'm sorry but " + filename + " doesn't exist!"); } return; } @@ -1554,7 +1459,7 @@ Make a selection: string name = Path.GetFileNameWithoutExtension(input) + "-miss"; // Read in the roms from the DAT and then write them to the file - logger.User("Converting " + input); + _logger.User("Converting " + input); DatData datdata = new DatData { OutputFormat = OutputFormat.MissFile, @@ -1568,7 +1473,7 @@ Make a selection: GameName = gamename, Romba = romba, }; - datdata = RomManipulation.Parse(input, 0, 0, datdata, logger); + datdata = RomManipulation.Parse(input, 0, 0, datdata, _logger); datdata.FileName += "-miss"; datdata.Name += "-miss"; datdata.Description += "-miss"; @@ -1577,13 +1482,13 @@ Make a selection: addext = (addext == "" || addext.StartsWith(".") ? addext : "." + addext); repext = (repext == "" || repext.StartsWith(".") ? repext : "." + repext); - Output.WriteDatfile(datdata, Path.GetDirectoryName(input), logger); - logger.User(input + " converted to: " + name); + Output.WriteDatfile(datdata, Path.GetDirectoryName(input), _logger); + _logger.User(input + " converted to: " + name); return; } else { - logger.Error("I'm sorry but " + input + "doesn't exist!"); + _logger.Error("I'm sorry but " + input + "doesn't exist!"); } } @@ -1601,7 +1506,7 @@ Make a selection: if (input != "" && (File.Exists(input) || Directory.Exists(input))) { - TrimMerge sg = new TrimMerge(input, root, rename, force, logger); + TrimMerge sg = new TrimMerge(input, root, rename, force, _logger); sg.Process(); return; } @@ -1641,7 +1546,7 @@ Make a selection: } catch (PathTooLongException) { - logger.Warning("The path for " + file + " was too long"); + _logger.Warning("The path for " + file + " was too long"); } } } @@ -1653,12 +1558,12 @@ Make a selection: } catch (PathTooLongException) { - logger.Warning("The path for " + input.Replace("\"", "") + " was too long"); + _logger.Warning("The path for " + input.Replace("\"", "") + " was too long"); } } } - MergeDiff md = new MergeDiff(newInputs, name, desc, cat, version, author, diff, dedup, bare, forceunpack, old, superdat, cascade, inplace, outdir, logger); + MergeDiff md = new MergeDiff(newInputs, name, desc, cat, version, author, diff, dedup, bare, forceunpack, old, superdat, cascade, inplace, outdir, _logger); md.Process(); } @@ -1681,16 +1586,16 @@ Make a selection: { if (exta == "" || extb == "") { - logger.Warning("Two extensions are needed to split a DAT!"); + _logger.Warning("Two extensions are needed to split a DAT!"); return; } - ExtSplit es = new ExtSplit(input, exta, extb, outdir, logger); + ExtSplit es = new ExtSplit(input, exta, extb, outdir, _logger); es.Split(); return; } else { - logger.Log("I'm sorry but " + input + "doesn't exist!"); + _logger.Log("I'm sorry but " + input + "doesn't exist!"); } } @@ -1709,7 +1614,7 @@ Make a selection: { if (!File.Exists(input.Replace("\"", "")) && !Directory.Exists(input.Replace("\"", ""))) { - logger.Error(input + " is not a valid file or folder!"); + _logger.Error(input + " is not a valid file or folder!"); Console.WriteLine(); Build.Help(); return; @@ -1717,7 +1622,7 @@ Make a selection: } // If so, run the program - HashSplit hs = new HashSplit(inputs, outdir, logger); + HashSplit hs = new HashSplit(inputs, outdir, _logger); hs.Split(); } @@ -1761,11 +1666,11 @@ Make a selection: { if (DBTools.AddSource(name, url, _connectionString)) { - logger.Log("Source " + name + " added!"); + _logger.Log("Source " + name + " added!"); } else { - logger.Error("Source " + name + " could not be added!"); + _logger.Error("Source " + name + " could not be added!"); } } @@ -1780,16 +1685,16 @@ Make a selection: { if (DBTools.RemoveSource(srcid, _connectionString)) { - logger.Log("Source '" + srcid + "' removed!"); + _logger.Log("Source '" + srcid + "' removed!"); } else { - logger.Error("Source with id '" + srcid + "' could not be removed."); + _logger.Error("Source with id '" + srcid + "' could not be removed."); } } else { - logger.Error("Invalid input"); + _logger.Error("Invalid input"); } } @@ -1802,11 +1707,11 @@ Make a selection: { if (DBTools.AddSystem(manufacturer, system, _connectionString)) { - logger.Log("System " + manufacturer + " - " + system + " added!"); + _logger.Log("System " + manufacturer + " - " + system + " added!"); } else { - logger.Error("System " + manufacturer + " - " + system + " could not be added!"); + _logger.Error("System " + manufacturer + " - " + system + " could not be added!"); } } @@ -1821,27 +1726,72 @@ Make a selection: { if (DBTools.RemoveSystem(sysid, _connectionString)) { - logger.Log("System '" + sysid + "' removed!"); + _logger.Log("System '" + sysid + "' removed!"); } else { - logger.Error("System with id '" + sysid + "' could not be removed."); + _logger.Error("System with id '" + sysid + "' could not be removed."); } } else { - logger.Error("Invalid input"); + _logger.Error("Invalid input"); } } #endregion - #region Listing Methods + #region Helper methods + + /// + /// Perform initial setup for the program + /// + private static void Setup() + { + Remapping.CreateRemappings(); + Build.Start("DATabaseTwo"); + + // Perform initial database and folder setup + if (!Directory.Exists(_datroot)) + { + Directory.CreateDirectory(_datroot); + } + if (!Directory.Exists(_outroot)) + { + Directory.CreateDirectory(_outroot); + } + DBTools.EnsureDatabase(_dbName, _connectionString); + + using (SqliteConnection dbc = new SqliteConnection(_connectionString)) + { + dbc.Open(); + + string query = "SELECT * FROM system"; + using (SqliteCommand slc = new SqliteCommand(query, dbc)) + { + using (SqliteDataReader sldr = slc.ExecuteReader()) + { + while (sldr.Read()) + { + int systemid = sldr.GetInt32(0); + string system = _datroot + Path.DirectorySeparatorChar + sldr.GetString(1) + " - " + sldr.GetString(2); + system = system.Trim(); + + if (!Directory.Exists(system)) + { + Directory.CreateDirectory(system); + } + } + } + } + } + } /// /// List sources in the database /// /// True to list all sources regardless if there is a game associated or not + /// This does not have an analogue in DATabaseTwo private static void ListSources(bool all = false) { string query = @" @@ -1858,7 +1808,7 @@ ORDER BY sources.name COLLATE NOCASE"; // If nothing is found, tell the user and exit if (!sldr.HasRows) { - logger.Warning("No sources found! Please add a source and then try again."); + _logger.Warning("No sources found! Please add a source and then try again."); return; } @@ -1876,13 +1826,12 @@ ORDER BY sources.name COLLATE NOCASE"; /// /// List systems in the database /// - /// True to list all systems regardless if there is a game associated or not - private static void ListSystems(bool all = false) + private static void ListSystems() { string query = @" -SELECT DISTINCT systems.id, systems.manufacturer, systems.system -FROM systems " + (!all ? "JOIN games ON systems.id=games.system" : "") + @" -ORDER BY systems.manufacturer, systems.system"; +SELECT DISTINCT system.id, system.manufacturer, system.name +FROM system +ORDER BY system.manufacturer, system.name"; using (SqliteConnection dbc = new SqliteConnection(_connectionString)) { dbc.Open(); @@ -1893,7 +1842,7 @@ ORDER BY systems.manufacturer, systems.system"; // If nothing is found, tell the user and exit if (!sldr.HasRows) { - logger.Warning("No systems found! Please add a system and then try again."); + _logger.Warning("No systems found! Please add a system and then try again."); return; } diff --git a/DATabase/DATabase.csproj b/DATabase/DATabase.csproj index ee7dd6f9..b138ca68 100644 --- a/DATabase/DATabase.csproj +++ b/DATabase/DATabase.csproj @@ -105,10 +105,12 @@ - + + - + + diff --git a/DATabase/Generate.cs b/DATabase/ImportExport/Generate.cs similarity index 100% rename from DATabase/Generate.cs rename to DATabase/ImportExport/Generate.cs diff --git a/DATabaseTwo/GenerateTwo.cs b/DATabase/ImportExport/GenerateTwo.cs similarity index 100% rename from DATabaseTwo/GenerateTwo.cs rename to DATabase/ImportExport/GenerateTwo.cs diff --git a/DATabase/Import.cs b/DATabase/ImportExport/Import.cs similarity index 97% rename from DATabase/Import.cs rename to DATabase/ImportExport/Import.cs index 8c5b1e50..fe7b778c 100644 --- a/DATabase/Import.cs +++ b/DATabase/ImportExport/Import.cs @@ -1,653 +1,653 @@ -using System.Collections.Generic; -using Mono.Data.Sqlite; -using System.IO; -using System.Text.RegularExpressions; - -using SabreTools.Helper; - -namespace SabreTools -{ - /// - /// Import data into the database from existing DATs - /// - public class Import : IImport - { - // Private instance variables - private string _filepath; - private string _connectionString; - private Logger _logger; - - /// - /// Initialize an Import object with the given information - /// - /// Path to the file that is going to be imported - /// Connection string for SQLite - /// Logger object for file or console output - public Import(string filepath, string connectionString, Logger logger) - { - _filepath = filepath.Replace("\"", ""); - _connectionString = connectionString; - _logger = logger; - } - - /// - /// Import the data from file into the database - /// - /// True if the data was imported, false otherwise - public bool ImportData() - { - // 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 (!Remapping.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(Remapping.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 (!Remapping.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(Remapping.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 (!Remapping.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(Remapping.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 (!Remapping.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(Remapping.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 (!Remapping.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(Remapping.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 (!Remapping.Redump.ContainsKey(fileinfo[1].Value)) - { - // Handle special case mappings found only in Redump - fileinfo = Regex.Match(filename, Constants.RedumpBiosPattern).Groups; - - if (!Remapping.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(Remapping.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 (!Remapping.TOSEC.ContainsKey(fileinfo[1].Value)) - { - // Handle special case mappings found only in TOSEC - fileinfo = Regex.Match(filename, Constants.TosecSpecialPatternA).Groups; - - if (!Remapping.TOSEC.ContainsKey(fileinfo[1].Value)) - { - fileinfo = Regex.Match(filename, Constants.TosecSpecialPatternB).Groups; - - if (!Remapping.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(Remapping.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 (!Remapping.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(Remapping.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 - DatData datdata = new DatData(); - datdata = RomManipulation.Parse(_filepath, sysid, srcid, datdata, _logger); - - // Sort inputted roms into games - SortedDictionary> sortable = new SortedDictionary>(); - long count = 0; - foreach (List roms in datdata.Roms.Values) - { - List newroms = roms; - if (datdata.MergeRoms) - { - newroms = RomManipulation.Merge(newroms); - } - - foreach (RomData rom in newroms) - { - count++; - string key = rom.SystemID.ToString().PadLeft(10, '0') + "-" + rom.SourceID.ToString().PadLeft(10, '0') + "-" + rom.Game.ToLowerInvariant(); - if (sortable.ContainsKey(key)) - { - sortable[key].Add(rom); - } - else - { - List temp = new List(); - temp.Add(rom); - sortable.Add(key, temp); - } - } - } - - // Loop over all roms, checking for adds - foreach (string key in sortable.Keys) - { - List roms = sortable[key]; - RomManipulation.Sort(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].Game, srcid, dbc); - - foreach (RomData 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; - } - - /// - /// Add a game to the database if it doesn't already exist - /// - /// System ID for the game to be added with - /// Name of the game to be added - /// Source ID for the game to be added with - /// SQLite database connection to use - /// Game ID of the inserted (or found) game, -1 on error - 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; - } - - /// - /// Add a file to the database if it doesn't already exist - /// - /// RomData object representing the rom - /// ID of the parent game to be mapped to - /// Last updated date - /// SQLite database connection to use - /// True if the file exists or could be added, false on error - private bool AddRom(RomData 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 != "rom" && rom.Type != "disk") - { - rom.Type = "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.Size + - " AND checksums.crc='" + rom.CRC + "'" + - " AND checksums.md5='" + rom.MD5 + "'" + - " AND checksums.sha1='" + rom.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.Size + ", '" + rom.CRC + "'" + ", '" + rom.MD5 + "'" + ", '" + rom.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; - } - - /// - /// Add a hash to the database if it doesn't exist already - /// - /// RomData object representing the rom - /// System ID for the game to be added with - /// Source ID for the game to be added with - /// Last updated date - /// SQLite database connection to use - /// True if the hash exists or could be added, false on error - /// This is currently unused. It is a test method for the new SabreTools DB schema - private bool AddHash(RomData 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.Game); - rom.Game = stripMatch.Groups[1].Value; - - // Run the name through the filters to make sure that it's correct - rom.Game = Style.NormalizeChars(rom.Game); - rom.Game = Style.RussianToLatin(rom.Game); - rom.Game = Style.SearchPattern(rom.Game); - rom.Game = rom.Game.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.Size + " AND crc='" + rom.CRC + "' AND md5='" + rom.MD5 + "' AND sha1='" + rom.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.Size + ", '" + rom.CRC + "', '" + rom.MD5 + "', '" + rom.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.Game.Replace("'", "''") + "'), " + - "(" + hashid + ", 'type', '" + rom.Type + "'), " + - "(" + hashid + ", 'lastupdated', '" + date + @"'); -INSERT OR IGNORE INTO gamesystem (game, systemid) VALUES ('" + rom.Game.Replace("'", "''") + "', " + sysid + @"); -INSERT OR IGNORE INTO gamesource (game, sourceid) VALUES ('" + rom.Game.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; - } - } -} +using System.Collections.Generic; +using Mono.Data.Sqlite; +using System.IO; +using System.Text.RegularExpressions; + +using SabreTools.Helper; + +namespace SabreTools +{ + /// + /// Import data into the database from existing DATs + /// + public class Import : IImport + { + // Private instance variables + private string _filepath; + private string _connectionString; + private Logger _logger; + + /// + /// Initialize an Import object with the given information + /// + /// Path to the file that is going to be imported + /// Connection string for SQLite + /// Logger object for file or console output + public Import(string filepath, string connectionString, Logger logger) + { + _filepath = filepath.Replace("\"", ""); + _connectionString = connectionString; + _logger = logger; + } + + /// + /// Import the data from file into the database + /// + /// True if the data was imported, false otherwise + public bool ImportData() + { + // 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 (!Remapping.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(Remapping.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 (!Remapping.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(Remapping.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 (!Remapping.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(Remapping.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 (!Remapping.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(Remapping.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 (!Remapping.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(Remapping.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 (!Remapping.Redump.ContainsKey(fileinfo[1].Value)) + { + // Handle special case mappings found only in Redump + fileinfo = Regex.Match(filename, Constants.RedumpBiosPattern).Groups; + + if (!Remapping.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(Remapping.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 (!Remapping.TOSEC.ContainsKey(fileinfo[1].Value)) + { + // Handle special case mappings found only in TOSEC + fileinfo = Regex.Match(filename, Constants.TosecSpecialPatternA).Groups; + + if (!Remapping.TOSEC.ContainsKey(fileinfo[1].Value)) + { + fileinfo = Regex.Match(filename, Constants.TosecSpecialPatternB).Groups; + + if (!Remapping.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(Remapping.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 (!Remapping.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(Remapping.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 + DatData datdata = new DatData(); + datdata = RomManipulation.Parse(_filepath, sysid, srcid, datdata, _logger); + + // Sort inputted roms into games + SortedDictionary> sortable = new SortedDictionary>(); + long count = 0; + foreach (List roms in datdata.Roms.Values) + { + List newroms = roms; + if (datdata.MergeRoms) + { + newroms = RomManipulation.Merge(newroms); + } + + foreach (RomData rom in newroms) + { + count++; + string key = rom.SystemID.ToString().PadLeft(10, '0') + "-" + rom.SourceID.ToString().PadLeft(10, '0') + "-" + rom.Game.ToLowerInvariant(); + if (sortable.ContainsKey(key)) + { + sortable[key].Add(rom); + } + else + { + List temp = new List(); + temp.Add(rom); + sortable.Add(key, temp); + } + } + } + + // Loop over all roms, checking for adds + foreach (string key in sortable.Keys) + { + List roms = sortable[key]; + RomManipulation.Sort(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].Game, srcid, dbc); + + foreach (RomData 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; + } + + /// + /// Add a game to the database if it doesn't already exist + /// + /// System ID for the game to be added with + /// Name of the game to be added + /// Source ID for the game to be added with + /// SQLite database connection to use + /// Game ID of the inserted (or found) game, -1 on error + 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; + } + + /// + /// Add a file to the database if it doesn't already exist + /// + /// RomData object representing the rom + /// ID of the parent game to be mapped to + /// Last updated date + /// SQLite database connection to use + /// True if the file exists or could be added, false on error + private bool AddRom(RomData 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 != "rom" && rom.Type != "disk") + { + rom.Type = "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.Size + + " AND checksums.crc='" + rom.CRC + "'" + + " AND checksums.md5='" + rom.MD5 + "'" + + " AND checksums.sha1='" + rom.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.Size + ", '" + rom.CRC + "'" + ", '" + rom.MD5 + "'" + ", '" + rom.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; + } + + /// + /// Add a hash to the database if it doesn't exist already + /// + /// RomData object representing the rom + /// System ID for the game to be added with + /// Source ID for the game to be added with + /// Last updated date + /// SQLite database connection to use + /// True if the hash exists or could be added, false on error + /// This is currently unused. It is a test method for the new SabreTools DB schema + private bool AddHash(RomData 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.Game); + rom.Game = stripMatch.Groups[1].Value; + + // Run the name through the filters to make sure that it's correct + rom.Game = Style.NormalizeChars(rom.Game); + rom.Game = Style.RussianToLatin(rom.Game); + rom.Game = Style.SearchPattern(rom.Game); + rom.Game = rom.Game.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.Size + " AND crc='" + rom.CRC + "' AND md5='" + rom.MD5 + "' AND sha1='" + rom.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.Size + ", '" + rom.CRC + "', '" + rom.MD5 + "', '" + rom.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.Game.Replace("'", "''") + "'), " + + "(" + hashid + ", 'type', '" + rom.Type + "'), " + + "(" + hashid + ", 'lastupdated', '" + date + @"'); +INSERT OR IGNORE INTO gamesystem (game, systemid) VALUES ('" + rom.Game.Replace("'", "''") + "', " + sysid + @"); +INSERT OR IGNORE INTO gamesource (game, sourceid) VALUES ('" + rom.Game.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; + } + } +} diff --git a/DATabaseTwo/ImportTwo.cs b/DATabase/ImportExport/ImportTwo.cs similarity index 100% rename from DATabaseTwo/ImportTwo.cs rename to DATabase/ImportExport/ImportTwo.cs diff --git a/DATabaseTwo/App.config b/DATabaseTwo/App.config deleted file mode 100644 index 88fa4027..00000000 --- a/DATabaseTwo/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/DATabaseTwo/DATabaseTwo.cs b/DATabaseTwo/DATabaseTwo.cs deleted file mode 100644 index 0a89f4fa..00000000 --- a/DATabaseTwo/DATabaseTwo.cs +++ /dev/null @@ -1,452 +0,0 @@ -using System; -using System.Collections.Generic; -using Mono.Data.Sqlite; -using System.IO; - -using SabreTools.Helper; - -namespace SabreTools -{ - /// - /// The following features are missing from DATabaseTwo with respect to the original DATabase: - /// - Source merging - /// - Custom DATs based on a system and a source - /// - Multi-source and multi-system DATs - /// - /// The following features need to (want to) be implemented in DATabaseTwo for further stability - /// - Import updating file locations and names when SHA-1 hashes are matched - /// - True duplicate DATs being removed from the import folder (SHA-1 matches) - /// - Generate All only generating DATs that have been recently updated - /// + This requires implementing a "last updated" data point for all DATs and tracking for "last generate" somewhere - /// - Impelement a ToSort folder for DATs that will place DATs in the correct subfolder on Import - /// - public class DATabaseTwo - { - // Private required variables - private static string _datroot = "DATS"; - private static string _outroot = "Output"; - private static string _dbName = "dats.sqlite"; - private static string _connectionString = "Data Source=" + _dbName + ";Version = 3;"; - private static Logger _logger; - - public static void Main(string[] args) - { - Console.Clear(); - - // Credits take precidence over all - if ((new List(args)).Contains("--credits")) - { - Build.Credits(); - return; - } - - _logger = new Logger(true, "database2.log"); - _logger.Start(); - - // Perform initial setup - Setup(); - - // If there's no arguments, show the menu - if (args.Length == 0) - { - _logger.ToFile = true; - ShowMainMenu(); - _logger.Close(); - return; - } - - // Set all default values - bool help = false, - gen = false, - genall = false, - ignore = false, - listsys = false, - norename = false, - old = false; - string system = ""; - - // Determine which switches are enabled (with values if necessary) - foreach (string arg in args) - { - switch (arg) - { - case "-?": - case "-h": - case "--help": - help = true; - break; - case "-g": - case "--generate": - gen = true; - break; - case "-ga": - case "--generate-all": - genall = true; - break; - case "-i": - case "--ignore": - ignore = true; - break; - case "-lsy": - case "--list-systems": - listsys = true; - break; - case "-nr": - case "--no-rename": - norename = true; - break; - case "-o": - case "--old": - old = true; - break; - default: - if (arg.StartsWith("-sys=") || arg.StartsWith("--system=")) - { - system = arg.Split('=')[1]; - } - else - { - _logger.Warning("Invalid input detected: " + arg); - Console.WriteLine(); - Build.Help(); - _logger.Close(); - return; - } - break; - } - } - - // If help is set or system is blank, show the help screen - if (help || (system == "" && !listsys)) - { - Build.Help(); - _logger.Close(); - return; - } - - // If we want a list of systems - if (listsys) - { - ListSystems(); - } - - // If we want to generate all DATs - else if (genall) - { - InitImport(ignore); - InitGenerateAll(norename, old); - } - - // If we want to generate a DAT - else if (gen) - { - InitImport(ignore); - InitGenerate(system, norename, old); - } - - _logger.Close(); - } - - #region Menus - - /// - /// Show the text-based main menu - /// - private static void ShowMainMenu() - { - string selection = ""; - while (selection.ToLowerInvariant() != "x") - { - Console.Clear(); - Build.Start("DATabaseTwo"); - Console.WriteLine(@"MAIN MENU -=========================== -Make a selection: - - 1) Show command line usage - 2) Check for new or changed DATs - 3) Generate System DATs - 4) List all available systems - 5) Show credits - X) Exit Program -"); - Console.Write("Enter selection: "); - selection = Console.ReadLine(); - - switch (selection) - { - case "1": - Console.Clear(); - Build.Help(); - Console.Write("\nPress any key to continue..."); - Console.ReadKey(); - break; - case "2": - ImportMenu(); - break; - case "3": - GenerateMenu(); - break; - case "4": - Console.Clear(); - Build.Start("DATabaseTwo"); - ListSystems(); - Console.Write("\nPress any key to continue..."); - Console.ReadKey(); - break; - case "5": - Console.Clear(); - Build.Credits(); - Console.Write("\nPress any key to continue..."); - Console.ReadKey(); - break; - } - } - } - - /// - /// Show the text-based import menu - /// - private static void ImportMenu() - { - string selection = ""; - bool ignore = false; - while (selection.ToLowerInvariant() != "b") - { - Console.Clear(); - Build.Start("DATabaseTwo"); - Console.WriteLine(@"IMPORT MENU -=========================== -Make a selection: - - 1) " + (ignore ? "Enable new source prompt" : "Disable new source prompt") + @" - 2) Begin import process - B) Go back to the previous menu -"); - Console.Write("Enter selection: "); - selection = Console.ReadLine(); - switch (selection) - { - case "1": - ignore = !ignore; - break; - case "2": - Console.Clear(); - InitImport(ignore); - Console.Write("\nPress any key to continue..."); - Console.ReadKey(); - ignore = false; - break; - } - } - return; - } - - /// - /// Show the text-based generate menu - /// - private static void GenerateMenu() - { - string selection = "", system = ""; - bool norename = false, old = false; - while (selection.ToLowerInvariant() != "b") - { - Console.Clear(); - Build.Start("DATabaseTwo"); - Console.WriteLine(@"GENERATE MENU -=========================== -Make a selection: - - 1) " + (norename ? "Enable game renaming" : "Disable game renaming") + @" - 2) " + (old ? "Enable XML output" : "Enable ClrMamePro output") + @" - 3) System ID to generate from" + (system != "" ? ": " + system : "") + @" - 4) Generate the DAT file for the specified system - 5) Generate all DAT files - B) Go back to the previous menu -"); - Console.Write("Enter selection: "); - selection = Console.ReadLine(); - switch (selection) - { - case "1": - norename = !norename; - break; - case "2": - old = !old; - break; - case "3": - Console.Clear(); - ListSystems(); - Console.Write("Please enter the System ID: "); - system = Console.ReadLine(); - break; - case "4": - Console.Clear(); - InitGenerate(system, norename, old); - Console.Write("\nPress any key to continue..."); - Console.ReadKey(); - system = ""; - norename = false; old = false; - break; - case "5": - Console.Clear(); - InitGenerateAll(norename, old); - Console.Write("\nPress any key to continue..."); - Console.ReadKey(); - system = ""; - norename = false; old = false; - break; - } - } - return; - } - - #endregion - - #region Function Methods - - /// - /// Wrap importing and updating DATs - /// - /// - private static void InitImport(bool ignore) - { - Import imp = new Import(_datroot, _connectionString, _logger, ignore); - imp.ImportData(); - } - - /// - /// Wrap generating a DAT from the library - /// - /// System ID to be used in the DAT (blank means all) - /// True if files should not be renamed with system and/or source in merged mode (default false) - /// True if the output file should be in ClrMamePro format (default false) - private static void InitGenerate(string systemid, bool norename, bool old) - { - Generate gen = new Generate(systemid, "" /* sourceid */, _datroot, _outroot, _connectionString, _logger, norename, old); - gen.Export(); - } - - /// - /// Wrap generating all standard DATs from the library - /// - private static void InitGenerateAll(bool norename, bool old) - { - List systems = new List(); - using (SqliteConnection dbc = new SqliteConnection(_connectionString)) - { - dbc.Open(); - - string query = "SELECT id FROM system"; - 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.Warning("No systems found! Please add a system and then try again."); - return; - } - - while (sldr.Read()) - { - systems.Add(sldr.GetInt32(0).ToString()); - } - } - } - - // Loop through the inputs - foreach (string system in systems) - { - _logger.User("Generating DAT for system id " + system); - InitGenerate(system, norename, old); - } - } - } - - /// - /// List systems in the database - /// - private static void ListSystems() - { - string query = @" -SELECT DISTINCT system.id, system.manufacturer, system.name -FROM system -ORDER BY system.manufacturer, system.name"; - 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.Warning("No systems found! Please add a system and then try again."); - return; - } - - Console.WriteLine("Available Systems (id <= name):\n"); - while (sldr.Read()) - { - Console.WriteLine(sldr.GetInt32(0) + "\t<=\t" + sldr.GetString(1) + " - " + sldr.GetString(2)); - } - } - } - } - return; - } - - #endregion - - #region Helper Methods - - /// - /// Perform initial setup for the program - /// - private static void Setup() - { - Remapping.CreateRemappings(); - Build.Start("DATabaseTwo"); - - // Perform initial database and folder setup - if (!Directory.Exists(_datroot)) - { - Directory.CreateDirectory(_datroot); - } - if (!Directory.Exists(_outroot)) - { - Directory.CreateDirectory(_outroot); - } - DBTools.EnsureDatabase(_dbName, _connectionString); - - using (SqliteConnection dbc = new SqliteConnection(_connectionString)) - { - dbc.Open(); - - string query = "SELECT * FROM system"; - using (SqliteCommand slc = new SqliteCommand(query, dbc)) - { - using (SqliteDataReader sldr = slc.ExecuteReader()) - { - while (sldr.Read()) - { - int systemid = sldr.GetInt32(0); - string system = _datroot + Path.DirectorySeparatorChar + sldr.GetString(1) + " - " + sldr.GetString(2); - system = system.Trim(); - - if (!Directory.Exists(system)) - { - Directory.CreateDirectory(system); - } - } - } - } - } - } - - #endregion - } -} diff --git a/DATabaseTwo/DATabaseTwo.csproj b/DATabaseTwo/DATabaseTwo.csproj deleted file mode 100644 index 0be5871c..00000000 --- a/DATabaseTwo/DATabaseTwo.csproj +++ /dev/null @@ -1,107 +0,0 @@ - - - - - Debug - AnyCPU - {C7732A05-1F96-43ED-AC8C-0E388F37EBC1} - Exe - Properties - DATabaseTwo - DATabaseTwo - v4.5.2 - 512 - true - - - AnyCPU - true - full - false - ..\..\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - ..\..\Release\ - TRACE - prompt - 4 - - - true - ..\..\Debug-x64\ - DEBUG;TRACE - full - x64 - prompt - MinimumRecommendedRules.ruleset - true - - - ..\..\Release-x64\ - TRACE - true - pdbonly - x64 - prompt - MinimumRecommendedRules.ruleset - true - - - - ..\packages\Mono.Data.Sqlite.Portable.1.0.3.5\lib\net4\Mono.Data.Sqlite.dll - True - - - - - ..\packages\Mono.Data.Sqlite.Portable.1.0.3.5\lib\net4\System.Data.Portable.dll - True - - - - ..\packages\Mono.Data.Sqlite.Portable.1.0.3.5\lib\net4\System.Transactions.Portable.dll - True - - - - - - - - - - - - - - - - - - - - - {225a1afd-0890-44e8-b779-7502665c23a5} - SabreHelper - - - - - - - - - - \ No newline at end of file diff --git a/DATabaseTwo/Properties/AssemblyInfo.cs b/DATabaseTwo/Properties/AssemblyInfo.cs deleted file mode 100644 index 6a28bc87..00000000 --- a/DATabaseTwo/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("DATabaseTwo")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("DATabaseTwo")] -[assembly: AssemblyCopyright("Copyright © 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("c7732a05-1f96-43ed-ac8c-0e388f37ebc1")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/DATabaseTwo/packages.config b/DATabaseTwo/packages.config deleted file mode 100644 index 2e7f170d..00000000 --- a/DATabaseTwo/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/SabreHelper/Data/Build.cs b/SabreHelper/Data/Build.cs index 4ad47e34..fd18c4fb 100644 --- a/SabreHelper/Data/Build.cs +++ b/SabreHelper/Data/Build.cs @@ -99,18 +99,16 @@ Options: -extb= Second extension to split by -out= Output directory -g, --generate Start tool in generate mode - -system= Comma-separated list of system IDs - -source= Comma-separated list of source IDs - -out= Output directory + -system= System ID to generate from -nr, --no-rename Don't auto-rename games -o, --old Output DAT in CMP format instead of XML -ga, --generate-all Start tool in generate all mode - -out= Output directory -nr, --no-rename Don't auto-rename games -o, --old Output DAT in CMP format instead of XML -hs, --hash-split Split a DAT or folder by best-available hashes -out= Output directory -i, --import Start tool in import mode + -ig, --ignore Don't prompt for new sources -lso, --list-sources List all sources (id <= name) -lsy, --list-systems List all systems (id <= name) -m, --merge Merge one or more DATs @@ -195,22 +193,6 @@ This program will output the following DATs: (d) Have - (NewComplete)-(New Missing) OR (Complete or NewComplete)-(Missing) if one is missing"); break; - case "DATabaseTwo": - Console.WriteLine(@"DATabaseTwo - Catalog and merge DATs by system ------------------------------------------ -Usage: DATabaseTwo [options] - -Options: - -h, -?, --help Show this help dialog - -g, --generate Start tool in generate mode - -ga, --generate-all Start tool in generate all mode - -i, --ignore Don't prompt for new sources - -lsy, --list-systems List all systems (id <= name) - -nr, --no-rename Don't auto-rename games by source/system - -o, --old Output DAT in CMP format instead of XML - -sys=, --system= System ID to generate from -"); - break; case "Filter": Console.WriteLine(@"Filter - Filter DATs by inputted criteria ----------------------------------------- diff --git a/SabreTools.sln b/SabreTools.sln index a95a0a87..eb7d263d 100644 --- a/SabreTools.sln +++ b/SabreTools.sln @@ -15,8 +15,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DATFromDir", "DATFromDir\DA EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OfflineMerge", "OfflineMerge\OfflineMerge.csproj", "{88310DB9-3B64-4268-AD48-2E0358D4CA5F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DATabaseTwo", "DATabaseTwo\DATabaseTwo.csproj", "{C7732A05-1F96-43ED-AC8C-0E388F37EBC1}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Filter", "Filter\Filter.csproj", "{136AA0D0-9234-4680-B593-A32C0762972E}" EndProject Global @@ -76,14 +74,6 @@ Global {88310DB9-3B64-4268-AD48-2E0358D4CA5F}.Release|Any CPU.Build.0 = Release|Any CPU {88310DB9-3B64-4268-AD48-2E0358D4CA5F}.Release|x64.ActiveCfg = Release|x64 {88310DB9-3B64-4268-AD48-2E0358D4CA5F}.Release|x64.Build.0 = Release|x64 - {C7732A05-1F96-43ED-AC8C-0E388F37EBC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C7732A05-1F96-43ED-AC8C-0E388F37EBC1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C7732A05-1F96-43ED-AC8C-0E388F37EBC1}.Debug|x64.ActiveCfg = Debug|x64 - {C7732A05-1F96-43ED-AC8C-0E388F37EBC1}.Debug|x64.Build.0 = Debug|x64 - {C7732A05-1F96-43ED-AC8C-0E388F37EBC1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C7732A05-1F96-43ED-AC8C-0E388F37EBC1}.Release|Any CPU.Build.0 = Release|Any CPU - {C7732A05-1F96-43ED-AC8C-0E388F37EBC1}.Release|x64.ActiveCfg = Release|x64 - {C7732A05-1F96-43ED-AC8C-0E388F37EBC1}.Release|x64.Build.0 = Release|x64 {136AA0D0-9234-4680-B593-A32C0762972E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {136AA0D0-9234-4680-B593-A32C0762972E}.Debug|Any CPU.Build.0 = Debug|Any CPU {136AA0D0-9234-4680-B593-A32C0762972E}.Debug|x64.ActiveCfg = Debug|x64