using System; using System.Collections.Generic; using SabreTools.Library.Data; using SabreTools.Library.Help; using SabreTools.Library.Tools; #if MONO using System.IO; #else using Alphaleonis.Win32.Filesystem; #endif namespace RombaSharp { /// /// Entry class for the RombaSharp application /// /// /// In the database, we want to enable "offline mode". That is, when a user does an operation /// that needs to read from the depot themselves, if the depot folder cannot be found, the /// user is prompted to reconnect the depot OR skip that depot entirely. /// public partial class RombaSharp { // General settings private static string _logdir; // Log folder location private static string _tmpdir; // Temp folder location private static string _webdir; // Web frontend location private static string _baddir; // Fail-to-unpack file folder location private static int _verbosity; // Verbosity of the output private static int _cores; // Forced CPU cores // DatRoot settings private static string _dats; // DatRoot folder location private static string _db; // Database name // Depot settings private static Dictionary> _depots; // Folder location, Max size // Server settings private static int _port; // Web server port // Other private variables private static string _config = "config.xml"; private static string _dbSchema = "rombasharp"; private static string _connectionString; private static Help _help; /// /// Entry class for the RombaSharp application /// public static void Main(string[] args) { // Perform initial setup and verification Globals.Logger = new Logger(true, "romba.log"); InitializeConfiguration(); DatabaseTools.EnsureDatabase(_dbSchema, _db, _connectionString); // Create a new Help object for this program _help = RetrieveHelp(); // If output is being redirected, don't allow clear screens if (!Console.IsOutputRedirected) { Console.Clear(); } // Credits take precidence over all if ((new List(args)).Contains("--credits")) { _help.OutputCredits(); Globals.Logger.Close(); return; } // If there's no arguments, show help if (args.Length == 0) { _help.OutputGenericHelp(); Globals.Logger.Close(); return; } // Feature flags bool archive = false, build = false, dbstats = false, depotRescan = false, diffdat = false, dir2dat = false, export = false, fixdat = false, import = false, lookup = false, memstats = false, merge = false, miss = false, progress = false, purgeBackup = false, purgeDelete = false, refreshDats = false, shutdown = false; // User flags bool copy = false, logOnly = false, onlyNeeded = false; // User inputs string depotPath = "", newdat = "", outdat = ""; List inputs = new List(); // Get the first argument as a feature flag string feature = args[0]; // Verify that the flag is valid if (!_help.TopLevelFlag(feature)) { Globals.Logger.User("'{0}' is not valid feature flag", feature); _help.OutputIndividualFeature(feature); Globals.Logger.Close(); return; } // Now get the proper name for the feature feature = _help.GetFeatureName(feature); // If we had the help feature first if (feature == "Help") { // If we had something else after help if (args.Length > 1) { _help.OutputIndividualFeature(args[1]); Globals.Logger.Close(); return; } // Otherwise, show generic help else { _help.OutputGenericHelp(); Globals.Logger.Close(); return; } } // Now verify that all other flags are valid for (int i = 1; i < args.Length; i++) { // Verify that the current flag is proper for the feature if (!_help[feature].ValidateInput(args[i])) { Globals.Logger.Error("Invalid input detected: {0}", args[i]); _help.OutputIndividualFeature(feature); Globals.Logger.Close(); return; } // Special precautions for files and directories if (File.Exists(args[i]) || Directory.Exists(args[i])) { inputs.Add(args[i]); } } // Now loop through all inputs Dictionary features = _help.GetEnabledFeatures(); foreach (KeyValuePair feat in features) { // Check all of the flag names and translate to arguments switch (feat.Key) { // Top-level features case "Help": // No-op as this should be caught break; case "Archive": archive = true; break; case "Build": build = true; break; case "Stats": dbstats = true; break; case "Rescan Depots": depotRescan = true; break; case "Diffdat": diffdat = true; break; case "Dir2Dat": dir2dat = true; break; case "Export": export = true; break; case "Fixdat": fixdat = true; break; case "Import": import = true; break; case "Lookup": lookup = true; break; case "Memstats": memstats = true; break; case "Merge": merge = true; break; case "Miss": miss = true; break; case "Purge Backup": purgeBackup = true; break; case "Purge Delete": purgeDelete = true; break; case "Refresh DATs": refreshDats = true; break; case "Progress": progress = true; break; case "Shutdown": shutdown = true; break; // User flags case "copy": copy = true; break; case "log-only": logOnly = true; break; case "only-needed": onlyNeeded = true; break; // User inputs case "depot": depotPath = (string)feat.Value.GetValue(); break; case "new": newdat = (string)feat.Value.GetValue(); break; case "out": outdat = (string)feat.Value.GetValue(); break; } } // If a switch that requires a filename is set and no file is, show the help screen if (inputs.Count == 0 && (archive || build || depotRescan || dir2dat || fixdat || import || lookup || merge || miss)) { Globals.Logger.Error("This feature requires at least one input"); _help.OutputGenericHelp(); Globals.Logger.Close(); return; } // Now take care of each mode in succesion // Adds ROM files from the specified directories to the ROM archive if (archive) { InitArchive(inputs, onlyNeeded); } // For each specified DAT file it creates the torrentzip files else if (build) { InitBuild(inputs, copy); } // Prints db stats else if (dbstats) { DisplayDBStats(); } // Rescan a specific depot else if (depotRescan) { foreach (string input in inputs) { Rescan(input); } } // Creates a DAT file with those entries that are in new DAT else if (diffdat) { InitDiffDat(newdat); } // Creates a DAT file for the specified input directory else if (dir2dat) { InitDir2Dat(inputs); } // Export the database to file else if (export) { ExportDatabase(); } // For each specified DAT file it creates a fix DAT else if (fixdat) { InitFixdat(inputs); } // Import a CSV into the database else if (import) { InitImport(inputs); } // For each specified hash it looks up any available information else if (lookup) { InitLookup(inputs); } // Prints memory stats else if (memstats) { DisplayMemoryStats(); } // Merges depots else if (merge) { InitMerge(inputs, depotPath, onlyNeeded); } // For each specified DAT file it creates a miss file and a have file else if (miss) { InitMiss(inputs); } // Shows progress of the currently running command else if (progress) { Globals.Logger.User("This feature is not used in RombaSharp: progress"); } // Moves DAT index entries for orphaned DATs else if (purgeBackup) { PurgeBackup(logOnly); } // Deletes DAT index entries for orphaned DATs else if (purgeDelete) { PurgeDelete(logOnly); } // Refreshes the DAT index from the files in the DAT master directory tree else if (refreshDats) { RefreshDatabase(); } // Gracefully shuts down server else if (shutdown) { Globals.Logger.User("This feature is not used in RombaSharp: shutdown"); } // If nothing is set, show the help else { _help.OutputGenericHelp(); } Globals.Logger.Close(); return; } } }