diff --git a/.gitignore b/.gitignore index 94718f6c..4e1bef9d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,9 @@ /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/DATabaseTwo/App.config b/DATabaseTwo/App.config new file mode 100644 index 00000000..88fa4027 --- /dev/null +++ b/DATabaseTwo/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/DATabaseTwo/DATabaseTwo.cs b/DATabaseTwo/DATabaseTwo.cs new file mode 100644 index 00000000..df9b17d4 --- /dev/null +++ b/DATabaseTwo/DATabaseTwo.cs @@ -0,0 +1,902 @@ +using System; +using System.Collections.Generic; +using Mono.Data.Sqlite; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text.RegularExpressions; + +using SabreTools.Helper; + +namespace SabreTools +{ + /// + /// This is meant to be a replacement for Import and Generate + /// that currently reside in DATabase. Import is no longer + /// going to be a function. Rather, on run, a subfolder called + /// "DATS" is going to be created in the folder the program + /// is run from. Inside, it will create a folder for every + /// System that is in the database at the time. It then audits + /// the files it finds inside of each folder. If the file + /// already exists in the database (by SHA-1 hash) then it + /// is not added. Otherwise, it is added with the System ID + /// of the folder it is in. Along the way, it also checks to + /// see what source each file belongs to for reference. If + /// the source cannot be automatically determined, then the user + /// is prompted to either pick from the list or enter a new + /// source for the DAT. New sources are added to the end + /// of the database. + /// + /// Once the intial setup is done, the user can choose + /// a system to generate a merged DAT for, generate all + /// DATs, or create a merged DAT from all sources. This will + /// use the dictionary-based merging that DATabase has been + /// using for MergeDiff. The files will all be written out + /// as System (merged Date) as is customary. The files will + /// always be written out to "Output" or "Created". + /// + /// The below code still has to sanitize the rom names and + /// game names according to the WoD standard as seen in + /// Import.cs. + /// + /// The database will be set up as follows: + /// dats + /// id + /// sha1 + /// name + /// datsdata + /// id + /// key + /// value + /// system + /// id + /// manufacturer + /// name + /// source + /// id + /// name + /// url + /// + 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; + + // Regex File Name Patterns + private static string _defaultPattern = @"^(.+?) - (.+?) \((.*) (.*)\)\.dat$"; + private static string _defaultSpecialPattern = @"^(.+?) - (.+?) \((.*) (.*)\)\.xml$"; + private static string _goodPattern = @"^(Good.*?)_.*\.dat"; + private static string _goodXmlPattern = @"^(Good.*?)_.*\.xml"; + private static string _mamePattern = @"^(.*)\.xml$"; + private static string _maybeIntroPattern = @"(.*?) \[T-En\].*\((\d{8})\)\.dat$"; + private static string _noIntroPattern = @"^(.*?) \((\d{8}-\d{6})_CM\)\.dat$"; + private static string _noIntroNumberedPattern = @"(.*? - .*?) \(\d.*?_CM\).dat"; + private static string _noIntroSpecialPattern = @"(.*? - .*?) \((\d{8})\)\.dat"; + private static string _nonGoodPattern = @"^(NonGood.*?)( .*?)?.xml"; + private static string _nonGoodSpecialPattern = @"^(NonGood.*?)( .*)?.dat"; + private static string _redumpPattern = @"^(.*?) \((\d{8} \d{2}-\d{2}-\d{2})\)\.dat$"; + private static string _redumpBiosPattern = @"^(.*?) \(\d+\) \((\d{4}-\d{2}-\d{2})\)\.dat$"; + private static string _tosecPattern = @"^(.*?) - .* \(TOSEC-v(\d{4}-\d{2}-\d{2})_CM\)\.dat$"; + private static string _tosecSpecialPatternA = @"^(.*? - .*?) - .* \(TOSEC-v(\d{4}-\d{2}-\d{2})_CM\)\.dat$"; + private static string _tosecSpecialPatternB = @"^(.*? - .*? - .*?) - .* \(TOSEC-v(\d{4}-\d{2}-\d{2})_CM\)\.dat$"; + private static string _truripPattern = @"^(.*) - .* \(trurip_XML\)\.dat$"; + private static string _zandroPattern = @"^SMW-.*.xml"; + + 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(); + + // Call 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, + genall = 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 "-ga": + case "--generate-all": + genall = 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) + { + InitGenerateAll(norename, old); + } + + // If we want to generate a DAT + else + { + 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) Generate System DATs + 3) List all available systems + 4) " + (_logger.ToFile ? "Disable Logging" : "Enable Logging") + @" + 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": + GenerateMenu(); + break; + case "3": + Console.Clear(); + Build.Start("DATabaseTwo"); + ListSystems(); + Console.Write("\nPress any key to continue..."); + Console.ReadKey(); + break; + case "4": + _logger.ToFile = !_logger.ToFile; + break; + case "5": + Console.Clear(); + Build.Credits(); + Console.Write("\nPress any key to continue..."); + Console.ReadKey(); + break; + } + } + } + + /// + /// 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("DATabase"); + 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 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) + { + string name = ""; + string path = _datroot; + + // If the System ID isn't set, then we will merge everything + if (systemid != "") + { + string system = ""; + + // First get the name of the system, if possible + string query = "SELECT manufacturer, name FROM system WHERE id=" + systemid; + using (SqliteConnection dbc = new SqliteConnection(_connectionString)) + { + dbc.Open(); + + using (SqliteCommand slc = new SqliteCommand(query, dbc)) + { + using (SqliteDataReader sldr = slc.ExecuteReader()) + { + if (sldr.Read()) + { + system = sldr.GetString(0) + " - " + sldr.GetString(1); + } + } + } + } + + // If we didn't find anything, then return + if (system == "") + { + _logger.Warning("No system could be found with id " + systemid); + return; + } + + path += Path.DirectorySeparatorChar + system; + name = system; + } + else + { + name = "ALL"; + } + + // Get the rest of the info as well + string date = DateTime.Now.ToString("yyyyMMddHHmmss"); + string description = name + " (merged " + date + ")"; + name += " (merged)"; + + // For good measure, get all sources + Dictionary sources = new Dictionary(); + sources.Add(0, "Default"); + + string squery = "SELECT id, name FROM source"; + using (SqliteConnection dbc = new SqliteConnection(_connectionString)) + { + dbc.Open(); + + using (SqliteCommand slc = new SqliteCommand(squery, dbc)) + { + using (SqliteDataReader sldr = slc.ExecuteReader()) + { + while (sldr.Read()) + { + sources.Add(sldr.GetInt32(0), sldr.GetString(1)); + } + } + } + } + + // Get a list of files to sourceid mappings + Dictionary sourcemap = new Dictionary(); + using (SqliteConnection dbc = new SqliteConnection(_connectionString)) + { + dbc.Open(); + + string tquery = "SELECT DISTINCT dats.name, datsdata.value FROM dats JOIN datsdata ON dats.id=datsdata.id WHERE key='source'"; + using (SqliteCommand slc = new SqliteCommand(tquery, dbc)) + { + using (SqliteDataReader sldr = slc.ExecuteReader()) + { + while (sldr.Read()) + { + string tempname = sldr.GetString(0); + string tempval = sldr.GetString(1); + if (!sourcemap.ContainsKey(tempname)) + { + sourcemap.Add(tempname, tempval); + } + } + } + } + } + + // Now read in all of the files + Dictionary> roms = new Dictionary>(); + foreach (string file in Directory.GetFiles(path, "*", SearchOption.AllDirectories)) + { + int tempSrcId = 0; + if (sourcemap.ContainsKey(file)) + { + Int32.TryParse(sourcemap[file], out tempSrcId); + } + roms = RomManipulation.ParseDict(file, 0, tempSrcId, roms, _logger); + } + + // Now process all of the roms + _logger.Log("Cleaning rom data"); + List keys = roms.Keys.ToList(); + foreach (string key in keys) + { + List temp = new List(); + List newroms = roms[key]; + for (int i = 0; i < newroms.Count; i++) + { + RomData rom = newroms[i]; + + // 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"); + + // 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(); + + if (!norename) + { + rom.Game += " [" + sources[rom.SourceID] + "]"; + } + temp.Add(rom); + } + roms[key] = temp; + } + + // Then write out the file + Output.WriteToDatFromDict(name, description, "", date, "SabreTools", "SabreTools", false, old, true, _outroot, roms, _logger); + } + + /// + /// 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) + { + 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"); + + _logger.Log("Beginning setup..."); + + // 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(); + + Dictionary hashes = new Dictionary(); + string query = "SELECT sha1, id FROM dats"; + using (SqliteCommand slc = new SqliteCommand(query, dbc)) + { + using (SqliteDataReader sldr = slc.ExecuteReader()) + { + while (sldr.Read()) + { + hashes.Add(sldr.GetString(0), sldr.GetInt32(1)); + } + } + } + + SHA1 sha1 = SHA1.Create(); + query = "SELECT * FROM system"; + using (SqliteCommand slc = new SqliteCommand(query, dbc)) + { + using (SqliteDataReader sldr = slc.ExecuteReader()) + { + while (sldr.Read()) + { + int id = sldr.GetInt32(0); + string system = _datroot + Path.DirectorySeparatorChar + sldr.GetString(1) + " - " + sldr.GetString(2); + system = system.Trim(); + + _logger.Log("System: " + system.Remove(0, 5)); + + if (!Directory.Exists(system)) + { + Directory.CreateDirectory(system); + } + + // Audit all DATs in the folder + foreach (string file in Directory.GetFiles(system, "*", SearchOption.AllDirectories)) + { + string hash = ""; + using (FileStream fs = File.Open(file, FileMode.Open)) + { + hash = BitConverter.ToString(sha1.ComputeHash(fs)).Replace("-", ""); + } + + // If the hash isn't in add it and all required information + int hashid = -1; + if (!hashes.ContainsKey(hash)) + { + _logger.Log("Adding file information for " + Path.GetFileName(file)); + + string squery = @"BEGIN; +INSERT INTO dats (size, sha1, name) +VALUES (" + (new FileInfo(file)).Length + ", '" + hash + "', '" + file.Replace("'", "''") + @"'); +SELECT last_insert_rowid(); +COMMIT;"; + using (SqliteCommand sslc = new SqliteCommand(squery, dbc)) + { + using (SqliteDataReader ssldr = sslc.ExecuteReader()) + { + if (ssldr.Read()) + { + hashid = ssldr.GetInt32(0); + } + } + } + + // Add the hash to the temporary Dictionary + hashes.Add(hash, hashid); + + // Now try to determine the source for the file based on the name + string source = GetSourceFromFileName(Path.GetFileName(file)); + int sourceid = 0; + + Dictionary sources = new Dictionary(); + query = "SELECT name, id FROM source"; + using (SqliteCommand sslc = new SqliteCommand(query, dbc)) + { + using (SqliteDataReader ssldr = sslc.ExecuteReader()) + { + while (ssldr.Read()) + { + sources.Add(ssldr.GetString(0), ssldr.GetInt32(1)); + } + } + } + + // If the source is blank, ask the user to supply one + while (source == "" && sourceid == 0) + { + Console.Clear(); + Build.Start("DATabaseTwo"); + + Console.WriteLine("Sources:"); + foreach (KeyValuePair pair in sources) + { + Console.WriteLine(" " + pair.Value + " - " + pair.Key); + } + Console.WriteLine("\nFor file name: " + Path.GetFileName(file)); + Console.Write("Select a source above or enter a new one: "); + source = Console.ReadLine(); + + Int32.TryParse(source, out sourceid); + + // If the value could be parsed, reset the source string + if (sourceid != 0) + { + source = ""; + } + + // If the source ID is set check to see if it's valid + if (sourceid != 0 && !sources.ContainsValue(sourceid)) + { + Console.WriteLine("Invalid selection: " + sourceid); + Console.ReadLine(); + sourceid = 0; + } + } + + // If the source isn't in, add it and get the insert id + if (source != "" && sourceid == 0 && !sources.ContainsKey(source)) + { + string tquery = @"BEGIN; +INSERT INTO source (name, url) +VALUES ('" + source + @"', ''); +SELECT last_insert_rowid(); +COMMIT;"; + using (SqliteCommand sslc = new SqliteCommand(tquery, dbc)) + { + using (SqliteDataReader ssldr = sslc.ExecuteReader()) + { + if (ssldr.Read()) + { + sourceid = ssldr.GetInt32(0); + } + } + } + + // Add the new source to the temporary Dictionary + sources.Add(source, sourceid); + } + // Otherwise, get the ID + else if (source != "" && sourceid == 0 && sources.ContainsKey(source)) + { + sourceid = sources[source]; + } + // Otherwise, we should already have an ID + + // Add the source link to the database + string uquery = "INSERT OR IGNORE INTO datsdata (id, key, value) VALUES (" + hashid + ", 'source', '" + sourceid + "')"; + using (SqliteCommand uslc = new SqliteCommand(uquery, dbc)) + { + uslc.ExecuteNonQuery(); + } + } + } + } + } + } + } + + _logger.Log("Setup complete!"); + } + + /// + /// Determine the source name from the file name, if possible + /// + /// The name of the file to be checked + /// The name of the source if determined, blank otherwise + private static string GetSourceFromFileName (string filename) + { + string source = ""; + + // Determine which dattype we have + GroupCollection fileinfo; + + if (Regex.IsMatch(filename, _nonGoodPattern)) + { + fileinfo = Regex.Match(filename, _nonGoodPattern).Groups; + if (!Remapping.NonGood.ContainsKey(fileinfo[1].Value)) + { + _logger.Warning("The filename " + fileinfo[1].Value + " was matched as NonGood but could not be mapped."); + return source; + } + source = "NonGood"; + } + else if (Regex.IsMatch(filename, _nonGoodSpecialPattern)) + { + fileinfo = Regex.Match(filename, _nonGoodSpecialPattern).Groups; + if (!Remapping.NonGood.ContainsKey(fileinfo[1].Value)) + { + _logger.Warning("The filename " + fileinfo[1].Value + " was matched as NonGood but could not be mapped."); + return source; + } + source = "NonGood"; + } + else if (Regex.IsMatch(filename, _goodPattern)) + { + fileinfo = Regex.Match(filename, _goodPattern).Groups; + if (!Remapping.Good.ContainsKey(fileinfo[1].Value)) + { + _logger.Warning("The filename " + fileinfo[1].Value + " was matched as Good but could not be mapped."); + return source; + } + source = "Good"; + } + else if (Regex.IsMatch(filename, _goodXmlPattern)) + { + fileinfo = Regex.Match(filename, _goodXmlPattern).Groups; + } + else if (Regex.IsMatch(filename, _maybeIntroPattern)) + { + fileinfo = Regex.Match(filename, _maybeIntroPattern).Groups; + if (!Remapping.MaybeIntro.ContainsKey(fileinfo[1].Value)) + { + _logger.Warning("The filename " + fileinfo[1].Value + " was matched as Maybe-Intro but could not be mapped."); + return source; + } + source = "Maybe-Intro"; + } + else if (Regex.IsMatch(filename, _noIntroPattern)) + { + fileinfo = Regex.Match(filename, _noIntroPattern).Groups; + if (!Remapping.NoIntro.ContainsKey(fileinfo[1].Value)) + { + _logger.Warning("The filename " + fileinfo[1].Value + " was matched as No-Intro but could not be mapped."); + return source; + } + source = "no-Intro"; + } + // For numbered DATs only + else if (Regex.IsMatch(filename, _noIntroNumberedPattern)) + { + fileinfo = Regex.Match(filename, _noIntroNumberedPattern).Groups; + if (!Remapping.NoIntro.ContainsKey(fileinfo[1].Value)) + { + _logger.Warning("The filename " + fileinfo[1].Value + " was matched as No-Intro but could not be mapped."); + return source; + } + source = "no-Intro"; + } + // For N-Gage and Gizmondo only + else if (Regex.IsMatch(filename, _noIntroSpecialPattern)) + { + fileinfo = Regex.Match(filename, _noIntroSpecialPattern).Groups; + if (!Remapping.NoIntro.ContainsKey(fileinfo[1].Value)) + { + _logger.Warning("The filename " + fileinfo[1].Value + " was matched as No-Intro but could not be mapped."); + return source; + } + source = "no-Intro"; + } + else if (Regex.IsMatch(filename, _redumpPattern)) + { + fileinfo = Regex.Match(filename, _redumpPattern).Groups; + if (!Remapping.Redump.ContainsKey(fileinfo[1].Value)) + { + _logger.Warning("The filename " + fileinfo[1].Value + " was matched as Redump but could not be mapped."); + return source; + } + source = "Redump"; + } + // For special BIOSes only + else if (Regex.IsMatch(filename, _redumpBiosPattern)) + { + fileinfo = Regex.Match(filename, _redumpBiosPattern).Groups; + if (!Remapping.Redump.ContainsKey(fileinfo[1].Value)) + { + _logger.Warning("The filename " + fileinfo[1].Value + " was matched as Redump but could not be mapped."); + return source; + } + source = "Redump"; + } + else if (Regex.IsMatch(filename, _tosecPattern)) + { + fileinfo = Regex.Match(filename, _tosecPattern).Groups; + if (!Remapping.TOSEC.ContainsKey(fileinfo[1].Value)) + { + // Handle special case mappings found only in TOSEC + fileinfo = Regex.Match(filename, _tosecSpecialPatternA).Groups; + + if (!Remapping.TOSEC.ContainsKey(fileinfo[1].Value)) + { + fileinfo = Regex.Match(filename, _tosecSpecialPatternB).Groups; + + if (!Remapping.TOSEC.ContainsKey(fileinfo[1].Value)) + { + _logger.Warning("The filename " + fileinfo[1].Value + " was matched as TOSEC but could not be mapped."); + return source; + } + } + } + source = "TOSEC"; + } + else if (Regex.IsMatch(filename, _truripPattern)) + { + fileinfo = Regex.Match(filename, _truripPattern).Groups; + if (!Remapping.TruRip.ContainsKey(fileinfo[1].Value)) + { + _logger.Warning("The filename " + fileinfo[1].Value + " was matched as TruRip but could not be mapped."); + return source; + } + source = "trurip"; + } + else if (Regex.IsMatch(filename, _zandroPattern)) + { + source = "Zandro"; + } + else if (Regex.IsMatch(filename, _defaultPattern)) + { + fileinfo = Regex.Match(filename, _defaultPattern).Groups; + source = fileinfo[3].Value; + } + else if (Regex.IsMatch(filename, _defaultSpecialPattern)) + { + fileinfo = Regex.Match(filename, _defaultSpecialPattern).Groups; + source = fileinfo[3].Value; + } + else if (Regex.IsMatch(filename, _mamePattern)) + { + fileinfo = Regex.Match(filename, _mamePattern).Groups; + if (!Remapping.MAME.ContainsKey(fileinfo[1].Value)) + { + _logger.Warning("The filename " + fileinfo[1].Value + " was matched as MAME but could not be mapped."); + return source; + } + source = "MAME"; + } + + return source; + } + + #endregion + } +} diff --git a/DATabaseTwo/DATabaseTwo.csproj b/DATabaseTwo/DATabaseTwo.csproj new file mode 100644 index 00000000..e8c572e2 --- /dev/null +++ b/DATabaseTwo/DATabaseTwo.csproj @@ -0,0 +1,105 @@ + + + + + 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 new file mode 100644 index 00000000..6a28bc87 --- /dev/null +++ b/DATabaseTwo/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +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 new file mode 100644 index 00000000..2e7f170d --- /dev/null +++ b/DATabaseTwo/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/OfflineMerge/OfflineMerge.cs b/OfflineMerge/OfflineMerge.cs index 70d8e9c9..9d16dec9 100644 --- a/OfflineMerge/OfflineMerge.cs +++ b/OfflineMerge/OfflineMerge.cs @@ -145,8 +145,6 @@ namespace SabreTools return false; } - Console.WriteLine(_currentAllMerged + " " + _currentMissingMerged + " " + _currentNewMerged); - // If we have all three DATs, then generate everything if (_currentAllMerged != "" && _currentMissingMerged != "" && _currentNewMerged != "") { diff --git a/SabreHelper/Build.cs b/SabreHelper/Build.cs index d9352177..f266db6c 100644 --- a/SabreHelper/Build.cs +++ b/SabreHelper/Build.cs @@ -192,6 +192,19 @@ 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 + -ga, --generate-all Start tool in generate all mode + -lsy, --list-systems List all systems (id <= name) + -o, --old Output DAT in CMP format instead of XML + -sys=, --system= System ID to generate from +"); + break; default: Console.Write("This is the default help output"); break; @@ -207,7 +220,7 @@ Credits Programmer / Lead: Matt Nadareski (darksabre76) Additional code: emuLOAD, @tractivo Testing: emuLOAD, @tractivo, Kludge, Obiwantje -Suggestions: edc, AcidX +Suggestions: edc, AcidX Based on work by: The Wizard of DATz"); } } diff --git a/SabreHelper/DBTools.cs b/SabreHelper/DBTools.cs index a01ce247..4e888aed 100644 --- a/SabreHelper/DBTools.cs +++ b/SabreHelper/DBTools.cs @@ -161,6 +161,46 @@ CREATE TABLE IF NOT EXISTS gamesource ( 'game' TEXT NOT NULL, 'sourceid' INTEGER NOT NULL, PRIMARY KEY (game, sourceid) +)"; + slc = new SqliteCommand(query, dbc); + slc.ExecuteNonQuery(); + } + else if (type == "dats") + { + string query = @" +CREATE TABLE IF NOT EXISTS dats ( + 'id' INTEGER PRIMARY KEY NOT NULL, + 'size' INTEGER NOT NULL DEFAULT -1, + 'sha1' TEXT NOT NULL, + 'name' TEXT NOT NULL +)"; + SqliteCommand slc = new SqliteCommand(query, dbc); + slc.ExecuteNonQuery(); + + query = @" +CREATE TABLE IF NOT EXISTS datsdata ( + 'id' INTEGER NOT NULL, + 'key' TEXT NOT NULL, + 'value' TEXT, + PRIMARY KEY (id, key, value) +)"; + slc = new SqliteCommand(query, dbc); + slc.ExecuteNonQuery(); + + query = @" +CREATE TABLE IF NOT EXISTS source ( + 'id' INTEGER PRIMARY KEY NOT NULL, + 'name' TEXT NOT NULL UNIQUE, + 'url' TEXT NOT NULL +)"; + slc = new SqliteCommand(query, dbc); + slc.ExecuteNonQuery(); + + query = @" +CREATE TABLE IF NOT EXISTS system ( + 'id' INTEGER PRIMARY KEY NOT NULL, + 'manufacturer' TEXT NOT NULL, + 'name' TEXT NOT NULL )"; slc = new SqliteCommand(query, dbc); slc.ExecuteNonQuery(); diff --git a/SabreHelper/Mappings/MAME.xml b/SabreHelper/Mappings/MAME.xml index 7b205a58..865a6910 100644 --- a/SabreHelper/Mappings/MAME.xml +++ b/SabreHelper/Mappings/MAME.xml @@ -144,14 +144,14 @@ - + - + @@ -244,7 +244,7 @@ - + @@ -252,8 +252,8 @@ - - + + @@ -278,7 +278,7 @@ - + @@ -414,8 +414,8 @@ - - + + diff --git a/SabreHelper/Mappings/MaybeIntro.xml b/SabreHelper/Mappings/MaybeIntro.xml index b634be3d..2c88832b 100644 --- a/SabreHelper/Mappings/MaybeIntro.xml +++ b/SabreHelper/Mappings/MaybeIntro.xml @@ -1,14 +1,14 @@  - + - + @@ -18,8 +18,8 @@ - - + + @@ -30,7 +30,7 @@ - + \ No newline at end of file diff --git a/SabreHelper/Mappings/NoIntro.xml b/SabreHelper/Mappings/NoIntro.xml index fc3fec45..f8bd303a 100644 --- a/SabreHelper/Mappings/NoIntro.xml +++ b/SabreHelper/Mappings/NoIntro.xml @@ -6,8 +6,8 @@ - - + + @@ -35,14 +35,14 @@ - + - - - - - + + + + + @@ -79,8 +79,8 @@ - - + + diff --git a/SabreHelper/Mappings/NonGood.xml b/SabreHelper/Mappings/NonGood.xml index c5e3312b..a6849a2f 100644 --- a/SabreHelper/Mappings/NonGood.xml +++ b/SabreHelper/Mappings/NonGood.xml @@ -8,9 +8,9 @@ - - - + + + @@ -25,9 +25,9 @@ - - - + + + @@ -37,7 +37,7 @@ - - - + + + \ No newline at end of file diff --git a/SabreHelper/Mappings/Redump.xml b/SabreHelper/Mappings/Redump.xml index f8bac1e1..c00a756d 100644 --- a/SabreHelper/Mappings/Redump.xml +++ b/SabreHelper/Mappings/Redump.xml @@ -18,7 +18,7 @@ - + diff --git a/SabreHelper/Mappings/TOSEC.xml b/SabreHelper/Mappings/TOSEC.xml index 4dfb1740..6ea650e9 100644 --- a/SabreHelper/Mappings/TOSEC.xml +++ b/SabreHelper/Mappings/TOSEC.xml @@ -26,7 +26,7 @@ - + @@ -35,8 +35,8 @@ - - + + @@ -158,7 +158,7 @@ - + @@ -169,8 +169,8 @@ - - + + @@ -212,9 +212,9 @@ - - - + + + diff --git a/SabreHelper/Mappings/TruRip.xml b/SabreHelper/Mappings/TruRip.xml index 2ac857a1..76b5e3d1 100644 --- a/SabreHelper/Mappings/TruRip.xml +++ b/SabreHelper/Mappings/TruRip.xml @@ -10,12 +10,12 @@ - + - - + + @@ -37,7 +37,7 @@ - + @@ -47,13 +47,13 @@ - + - + diff --git a/SabreHelper/SabreHelper.csproj b/SabreHelper/SabreHelper.csproj index 24014296..a1b47597 100644 --- a/SabreHelper/SabreHelper.csproj +++ b/SabreHelper/SabreHelper.csproj @@ -107,6 +107,9 @@ PreserveNewest + + PreserveNewest + Always diff --git a/SabreHelper/dats.sqlite b/SabreHelper/dats.sqlite new file mode 100644 index 00000000..8890d7f9 Binary files /dev/null and b/SabreHelper/dats.sqlite differ diff --git a/SabreHelper/sqlite3.dll b/SabreHelper/sqlite3.dll index fcac1b2d..2797682c 100644 Binary files a/SabreHelper/sqlite3.dll and b/SabreHelper/sqlite3.dll differ diff --git a/SabreTools.sln b/SabreTools.sln index b83b9f8a..c8c8d42b 100644 --- a/SabreTools.sln +++ b/SabreTools.sln @@ -17,6 +17,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OfflineMerge", "OfflineMerg EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UncompressedSize", "UncompressedSize\UncompressedSize.csproj", "{E21ABB36-C6D9-4FD6-802E-EC0D05284E0A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DATabaseTwo", "DATabaseTwo\DATabaseTwo.csproj", "{C7732A05-1F96-43ED-AC8C-0E388F37EBC1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -82,6 +84,14 @@ Global {E21ABB36-C6D9-4FD6-802E-EC0D05284E0A}.Release|Any CPU.Build.0 = Release|Any CPU {E21ABB36-C6D9-4FD6-802E-EC0D05284E0A}.Release|x64.ActiveCfg = Release|x64 {E21ABB36-C6D9-4FD6-802E-EC0D05284E0A}.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 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/UncompressedSize/UncompressedSize.cs b/UncompressedSize/UncompressedSize.cs index c03a1fe9..be077308 100644 --- a/UncompressedSize/UncompressedSize.cs +++ b/UncompressedSize/UncompressedSize.cs @@ -1,9 +1,5 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using SabreTools.Helper; @@ -13,6 +9,8 @@ namespace SabreTools { public static void Main(string[] args) { + Build.Start("UncompressedSize"); + List inputs = new List(); foreach (string arg in args)