From c034df4266546c3d45c2827b86f6710c19c712fe Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Thu, 5 Jul 2018 21:34:04 -0700 Subject: [PATCH] More and more cleanup (#86) * Namespace cleanups * Make dump validation instanced * Add note to Tasks * Move stuff to DumpEnvironment Most of the stuff in Tasks.cs acted on a single input parameter, namely a DumpEnvironment. Since that's the case, it was more logical to wrap those into DumpEnvironment and make them instance methods rather than keep them static. Due to this change, quite a few methods changed access, and some had to be marked internal due to wanting them to be tested separately. * Gut Tasks * One less thing in MainWindow * Remove explicit cast * Wrong check * Create helper method * Disable scan button on dump * Remove unnecessary getters/setters * Method name/description cleanup * Address TODO * Namespace cleanups * Make dump validation instanced * Add note to Tasks * Move stuff to DumpEnvironment Most of the stuff in Tasks.cs acted on a single input parameter, namely a DumpEnvironment. Since that's the case, it was more logical to wrap those into DumpEnvironment and make them instance methods rather than keep them static. Due to this change, quite a few methods changed access, and some had to be marked internal due to wanting them to be tested separately. * Gut Tasks * One less thing in MainWindow * Remove explicit cast * Wrong check * Create helper method * Disable scan button on dump * Remove unnecessary getters/setters * Method name/description cleanup * Address TODO * Clean up OnContentRendered * Namespace cleanups * Make dump validation instanced * Add note to Tasks * Move stuff to DumpEnvironment Most of the stuff in Tasks.cs acted on a single input parameter, namely a DumpEnvironment. Since that's the case, it was more logical to wrap those into DumpEnvironment and make them instance methods rather than keep them static. Due to this change, quite a few methods changed access, and some had to be marked internal due to wanting them to be tested separately. * Gut Tasks * One less thing in MainWindow * Remove explicit cast * Wrong check * Create helper method * Disable scan button on dump * Remove unnecessary getters/setters * Method name/description cleanup * Address TODO * Clean up OnContentRendered * Update event handlers --- DICUI.Test/DICUI.Test.csproj | 1 - DICUI.Test/ResultTest.cs | 3 +- DICUI.Test/TasksTest.cs | 30 - DICUI.Test/Utilities/DumpEnvironmentTest.cs | 25 +- DICUI/DICUI.csproj | 2 +- DICUI/External/EVORE.cs | 3 - DICUI/MainWindow.xaml | 6 +- DICUI/MainWindow.xaml.cs | 206 +++---- DICUI/Properties/AssemblyInfo.cs | 3 + DICUI/Tasks.cs | 316 ---------- DICUI/Utilities/DumpEnvironment.cs | 621 ++++++++++++++------ DICUI/Utilities/Result.cs | 27 + DICUI/Utilities/Validators.cs | 215 ++++--- 13 files changed, 726 insertions(+), 732 deletions(-) delete mode 100644 DICUI.Test/TasksTest.cs delete mode 100644 DICUI/Tasks.cs create mode 100644 DICUI/Utilities/Result.cs diff --git a/DICUI.Test/DICUI.Test.csproj b/DICUI.Test/DICUI.Test.csproj index 334dd565..21118fa4 100644 --- a/DICUI.Test/DICUI.Test.csproj +++ b/DICUI.Test/DICUI.Test.csproj @@ -63,7 +63,6 @@ - diff --git a/DICUI.Test/ResultTest.cs b/DICUI.Test/ResultTest.cs index ce41a96f..3fa02e4a 100644 --- a/DICUI.Test/ResultTest.cs +++ b/DICUI.Test/ResultTest.cs @@ -1,4 +1,5 @@ -using Xunit; +using DICUI.Utilities; +using Xunit; namespace DICUI.Test { diff --git a/DICUI.Test/TasksTest.cs b/DICUI.Test/TasksTest.cs deleted file mode 100644 index 85dc6137..00000000 --- a/DICUI.Test/TasksTest.cs +++ /dev/null @@ -1,30 +0,0 @@ -using DICUI.Data; -using DICUI.Utilities; -using Xunit; - -namespace DICUI.Test -{ - public class TasksTest - { - [Fact] - public void EjectDiscTest() - { - // TODO: Implement - Assert.True(true); - } - - [Fact] - public void CancelDumpingTest() - { - // TODO: Implement - Assert.True(true); - } - - [Fact] - public void StartDumpingTest() - { - // TODO: Implement - Assert.True(true); - } - } -} diff --git a/DICUI.Test/Utilities/DumpEnvironmentTest.cs b/DICUI.Test/Utilities/DumpEnvironmentTest.cs index c592d5c3..4f37b3e2 100644 --- a/DICUI.Test/Utilities/DumpEnvironmentTest.cs +++ b/DICUI.Test/Utilities/DumpEnvironmentTest.cs @@ -13,7 +13,7 @@ namespace DICUI.Test [InlineData("fd A test.img", 'A', true, MediaType.Floppy, true)] [InlineData("dvd X test.iso 8 /raw", 'X', false, MediaType.Floppy, false)] [InlineData("stop D", 'D', false, MediaType.DVD, true)] - public void IsConfigurationValidTest(string parameters, char letter, bool isFloppy, MediaType? mediaType, bool expected) + public void ParametersValidTest(string parameters, char letter, bool isFloppy, MediaType? mediaType, bool expected) { var env = new DumpEnvironment { @@ -22,7 +22,7 @@ namespace DICUI.Test Type = mediaType, }; - bool actual = env.IsConfigurationValid(); + bool actual = env.ParametersValid(); Assert.Equal(expected, actual); } @@ -123,5 +123,26 @@ namespace DICUI.Test // TODO: Implement Assert.True(true); } + + [Fact] + public void EjectDiscTest() + { + // TODO: Implement + Assert.True(true); + } + + [Fact] + public void CancelDumpingTest() + { + // TODO: Implement + Assert.True(true); + } + + [Fact] + public void StartDumpingTest() + { + // TODO: Implement + Assert.True(true); + } } } diff --git a/DICUI/DICUI.csproj b/DICUI/DICUI.csproj index 769f01ad..4ef001e4 100644 --- a/DICUI/DICUI.csproj +++ b/DICUI/DICUI.csproj @@ -94,12 +94,12 @@ - + diff --git a/DICUI/External/EVORE.cs b/DICUI/External/EVORE.cs index 192ff527..f8aecb83 100644 --- a/DICUI/External/EVORE.cs +++ b/DICUI/External/EVORE.cs @@ -16,13 +16,10 @@ //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. using System; -using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Linq; using System.Text; using System.Threading; -using System.Threading.Tasks; namespace DICUI.External { diff --git a/DICUI/MainWindow.xaml b/DICUI/MainWindow.xaml index e6ab823e..7e8008b0 100644 --- a/DICUI/MainWindow.xaml +++ b/DICUI/MainWindow.xaml @@ -27,13 +27,13 @@ - + - + - + diff --git a/DICUI/MainWindow.xaml.cs b/DICUI/MainWindow.xaml.cs index 9371249b..2474a75d 100644 --- a/DICUI/MainWindow.xaml.cs +++ b/DICUI/MainWindow.xaml.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; -using System.Text.RegularExpressions; using System.Windows; using System.Windows.Controls; using WinForms = System.Windows.Forms; @@ -16,10 +14,11 @@ namespace DICUI public partial class MainWindow : Window { // Private UI-related variables - private List _drives { get; set; } - private MediaType? _currentMediaType { get; set; } - private List _systems { get; set; } - private List _mediaTypes { get; set; } + private List _drives; + private MediaType? _currentMediaType; + private List _systems; + private List _mediaTypes; + private bool _alreadyShown; private DumpEnvironment _env; @@ -27,24 +26,6 @@ namespace DICUI private Options _options; private OptionsWindow _optionsWindow; - bool _shown; - - protected override void OnContentRendered(EventArgs e) - { - base.OnContentRendered(e); - - if (_shown) - return; - - _shown = true; - - // Populate the list of systems - PopulateSystems(); - - // Populate the list of drives - PopulateDrives(); - } - public MainWindow() { InitializeComponent(); @@ -53,11 +34,32 @@ namespace DICUI _options = new Options(); _options.Load(); - + // Disable buttons until we load fully + btn_StartStop.IsEnabled = false; + btn_Search.IsEnabled = false; + btn_Scan.IsEnabled = false; } #region Events + protected override void OnContentRendered(EventArgs e) + { + base.OnContentRendered(e); + + if (_alreadyShown) + return; + + _alreadyShown = true; + + // Populate the list of systems + lbl_Status.Content = "Creating system list, please wait!"; + PopulateSystems(); + + // Populate the list of drives + lbl_Status.Content = "Creating drive list, please wait!"; + PopulateDrives(); + } + private void btn_StartStop_Click(object sender, RoutedEventArgs e) { // Dump or stop the dump @@ -67,12 +69,11 @@ namespace DICUI } else if ((string)btn_StartStop.Content == UIElements.StopDumping) { - Tasks.CancelDumping(_env); + _env.CancelDumping(); + btn_Scan.IsEnabled = true; if (chk_EjectWhenDone.IsChecked == true) - { - Tasks.EjectDisc(_env); - } + _env.EjectDisc(); } } @@ -101,7 +102,7 @@ namespace DICUI return; } - PopulateMediaTypeAccordingToChosenSystem(); + PopulateMediaType(); } private void cmb_MediaType_SelectionChanged(object sender, SelectionChangedEventArgs e) @@ -119,6 +120,7 @@ namespace DICUI private void cmb_DriveLetter_SelectionChanged(object sender, SelectionChangedEventArgs e) { + CacheCurrentDiscType(); SetCurrentDiscType(); GetOutputNames(); SetSupportedDriveSpeed(); @@ -129,7 +131,33 @@ namespace DICUI EnsureDiscInformation(); } - private void tbr_Options_Click(object sender, RoutedEventArgs e) + private void txt_OutputFilename_TextChanged(object sender, TextChangedEventArgs e) + { + EnsureDiscInformation(); + } + + private void txt_OutputDirectory_TextChanged(object sender, TextChangedEventArgs e) + { + EnsureDiscInformation(); + } + + // Toolbar Events + + private void AppExitClick(object sender, RoutedEventArgs e) + { + Application.Current.Shutdown(); + } + + private void AboutClick(object sender, RoutedEventArgs e) + { + MessageBox.Show($"ReignStumble - Project Lead / UI Design{Environment.NewLine}" + + $"darksabre76 - Project Co-Lead / Backend Design{Environment.NewLine}" + + $"Jakz - Feature Contributor{Environment.NewLine}" + + $"NHellFire - Feature Contributor{Environment.NewLine}" + + $"Dizzzy - Concept/Ideas/Beta tester{Environment.NewLine}", "About", MessageBoxButton.OK, MessageBoxImage.Information); + } + + private void OptionsClick(object sender, RoutedEventArgs e) { // lazy initialization if (_optionsWindow == null) @@ -147,20 +175,10 @@ namespace DICUI _optionsWindow.Show(); } - private void txt_OutputFilename_TextChanged(object sender, TextChangedEventArgs e) - { - EnsureDiscInformation(); - } - - private void txt_OutputDirectory_TextChanged(object sender, TextChangedEventArgs e) - { - EnsureDiscInformation(); - } - public void OnOptionsUpdated() { GetOutputNames(); - //TODO: here we should adjust maximum speed if it changed in options + SetSupportedDriveSpeed(); } #endregion @@ -168,9 +186,9 @@ namespace DICUI #region Helpers /// - /// Populate disc type according to system type + /// Populate media type according to system type /// - private void PopulateMediaTypeAccordingToChosenSystem() + private void PopulateMediaType() { KnownSystem? currentSystem = cmb_SystemType.SelectedItem as KnownSystemComboBoxItem; @@ -293,16 +311,17 @@ namespace DICUI _env = DetermineEnvironment(); btn_StartStop.Content = UIElements.StopDumping; + btn_Scan.IsEnabled = false; lbl_Status.Content = "Beginning dumping process"; - var task = Tasks.StartDumping(_env); - Result result = await task; + Result result = await _env.StartDumping(); lbl_Status.Content = result ? "Dumping complete!" : result.Message; btn_StartStop.Content = UIElements.StartDumping; + btn_Scan.IsEnabled = true; if (chk_EjectWhenDone.IsChecked == true) - Tasks.EjectDisc(_env); + _env.EjectDisc(); } /// @@ -310,32 +329,29 @@ namespace DICUI /// private void EnsureDiscInformation() { - // Get the selected system info - KnownSystem? selectedSystem = (KnownSystem?)(cmb_SystemType.SelectedItem as KnownSystemComboBoxItem) ?? KnownSystem.NONE; - MediaType? selectedMediaType = cmb_MediaType.SelectedItem as MediaType? ?? MediaType.NONE; + // Get the current environment information + _env = DetermineEnvironment(); - Result result = Validators.GetSupportStatus(selectedSystem, selectedMediaType); - string resultMessage = result.Message; - if (result && _currentMediaType != null && _currentMediaType != MediaType.NONE) - { - // If the current media type is still supported, change the index to that - int index = _mediaTypes.IndexOf(_currentMediaType); - if (index != -1 && cmb_MediaType.SelectedIndex != index) - cmb_MediaType.SelectedIndex = index; + // Take care of null cases + if (_env.System == null) + _env.System = KnownSystem.NONE; + if (_env.Type == null) + _env.Type = MediaType.NONE; - // Otherwise, we tell the user that the disc/system combo is not supported - else - resultMessage = $"Disc of type {_currentMediaType.Name()} found, but the current system does not support it!"; - }; + // Get the status to write out + Result result = Validators.GetSupportStatus(_env.System, _env.Type); + lbl_Status.Content = result.Message; + + // Set the index for the current disc type + SetCurrentDiscType(); - lbl_Status.Content = resultMessage; btn_StartStop.IsEnabled = result && (_drives != null && _drives.Count > 0 ? true : false); // If we're in a type that doesn't support drive speeds - cmb_DriveSpeed.IsEnabled = selectedMediaType.DoesSupportDriveSpeed() && selectedSystem.DoesSupportDriveSpeed(); + cmb_DriveSpeed.IsEnabled = _env.Type.DoesSupportDriveSpeed() && _env.System.DoesSupportDriveSpeed(); // Special case for Custom input - if (selectedSystem == KnownSystem.Custom) + if (_env.System == KnownSystem.Custom) { txt_Parameters.IsEnabled = true; txt_OutputFilename.IsEnabled = false; @@ -354,28 +370,10 @@ namespace DICUI btn_OutputDirectoryBrowse.IsEnabled = true; cmb_DriveLetter.IsEnabled = true; - // Populate with the correct params for inputs (if we're not on the default option) - if (selectedSystem != KnownSystem.NONE && selectedMediaType != MediaType.NONE) - { - Drive drive = cmb_DriveLetter.SelectedValue as Drive; - - // If drive letter is invalid, skip this - if (drive == null) - return; - - string command = Converters.KnownSystemAndMediaTypeToBaseCommand(selectedSystem, selectedMediaType); - List defaultParams = Converters.KnownSystemAndMediaTypeToParameters(selectedSystem, selectedMediaType); - txt_Parameters.Text = command - + " " + drive.Letter - + " \"" + Path.Combine(txt_OutputDirectory.Text, txt_OutputFilename.Text) + "\" " - + (selectedMediaType != MediaType.Floppy - && selectedMediaType != MediaType.BluRay - && selectedSystem != KnownSystem.MicrosoftXBOX - && selectedSystem != KnownSystem.MicrosoftXBOX360XDG2 - && selectedSystem != KnownSystem.MicrosoftXBOX360XDG3 - ? (int?)cmb_DriveSpeed.SelectedItem + " " : "") - + string.Join(" ", defaultParams); - } + // Generate the full parameters from the environment + string generated = _env.GetFullParameters((int?)cmb_DriveSpeed.SelectedItem); + if (generated != null) + txt_Parameters.Text = generated; } } @@ -385,7 +383,7 @@ namespace DICUI private void GetOutputNames() { Drive drive = cmb_DriveLetter.SelectedItem as Drive; - KnownSystem? systemType = (KnownSystem?)(cmb_SystemType.SelectedItem as KnownSystemComboBoxItem); + KnownSystem? systemType = cmb_SystemType.SelectedItem as KnownSystemComboBoxItem; MediaType? mediaType = cmb_MediaType.SelectedItem as MediaType?; if (drive != null @@ -418,7 +416,7 @@ namespace DICUI btn_Search.IsEnabled = false; btn_Scan.IsEnabled = false; - string protections = await Tasks.RunProtectionScan(env.Drive.Letter + ":\\"); + string protections = await Validators.RunProtectionScanOnPath(env.Drive.Letter + ":\\"); MessageBox.Show(protections, "Detected Protection", MessageBoxButton.OK, MessageBoxImage.Information); lbl_Status.Content = tempContent; @@ -439,10 +437,10 @@ namespace DICUI cmb_DriveSpeed.SelectedIndex = values.Count / 2; // Get the current environment - var env = DetermineEnvironment(); + _env = DetermineEnvironment(); // Get the drive speed - int speed = await Tasks.GetDiscSpeed(env); + int speed = await _env.GetDiscSpeed(); // If we have an invalid speed, we need to jump out // TODO: Should we disable dumping in this case? @@ -459,9 +457,9 @@ namespace DICUI } /// - /// Set the current disc type in the combo box + /// Cache the current disc type to internal variable /// - private void SetCurrentDiscType() + private void CacheCurrentDiscType() { // Get the drive letter from the selected item Drive drive = cmb_DriveLetter.SelectedItem as Drive; @@ -470,35 +468,25 @@ namespace DICUI // Get the current optical disc type _currentMediaType = Validators.GetDiscType(drive.Letter); + } + /// + /// Set the current disc type in the combo box + /// + private void SetCurrentDiscType() + { // If we have an invalid current type, we don't care and return if (_currentMediaType == null || _currentMediaType == MediaType.NONE) - { return; - } // Now set the selected item, if possible int index = _mediaTypes.FindIndex(kvp => kvp.Value == _currentMediaType); if (index != -1) - { cmb_MediaType.SelectedIndex = index; - } else - { lbl_Status.Content = $"Disc of type '{Converters.MediaTypeToString(_currentMediaType)}' found, but the current system does not support it!"; - } } #endregion - - private void AppExit_Click(object sender, RoutedEventArgs e) - { - System.Windows.Application.Current.Shutdown(); - } - - private void About_Click(object sender, RoutedEventArgs e) - { - MessageBox.Show("Hello, world!", "My App", MessageBoxButton.OK, MessageBoxImage.Information); - } } } diff --git a/DICUI/Properties/AssemblyInfo.cs b/DICUI/Properties/AssemblyInfo.cs index 3d4c56e4..e60a5cce 100644 --- a/DICUI/Properties/AssemblyInfo.cs +++ b/DICUI/Properties/AssemblyInfo.cs @@ -53,3 +53,6 @@ using System.Windows; // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] + +// Anything marked as internal can be used by the test methods +[assembly: InternalsVisibleTo("DICUI.Test")] \ No newline at end of file diff --git a/DICUI/Tasks.cs b/DICUI/Tasks.cs deleted file mode 100644 index aa1086c5..00000000 --- a/DICUI/Tasks.cs +++ /dev/null @@ -1,316 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using System.Windows; -using DICUI.Data; -using DICUI.External; -using DICUI.Utilities; - -namespace DICUI -{ - /// - /// Generic success/failure result object, with optional message - /// - public class Result - { - private bool success; - public string Message { get; private set; } - - private Result(bool success, string message) - { - this.success = success; - this.Message = message; - } - - public static Result Success() => new Result(true, ""); - public static Result Success(string message) => new Result(true, message); - public static Result Success(string message, params object[] args) => new Result(true, string.Format(message, args)); - - public static Result Failure() => new Result(false, ""); - public static Result Failure(string message) => new Result(false, message); - public static Result Failure(string message, params object[] args) => new Result(false, string.Format(message, args)); - - public static implicit operator bool(Result result) => result.success; - } - - /// - /// Class containing dumping tasks - /// - public class Tasks - { - /// - /// Get disc speed using DIC - /// - /// Drive speed if possible, -1 on error - public static async Task GetDiscSpeed(DumpEnvironment env) - { - // Validate that the required program exists - if (!File.Exists(env.DICPath)) - return -1; - - // Validate that the drive is set up - if (env.Drive == null) - return -1; - - // Validate we're not trying to get the speed for a floppy disk - if (env.IsFloppy) - return -1; - - // Get the drive speed directly - //int speed = Validators.GetDriveSpeed((char)selected?.Key); - //int speed = Validators.GetDriveSpeedEx((char)selected?.Key, _currentMediaType); - - // Get the drive speed from DIC, if possible - Process childProcess; - string output = await Task.Run(() => - { - childProcess = new Process() - { - StartInfo = new ProcessStartInfo() - { - FileName = env.DICPath, - Arguments = DICCommands.DriveSpeed + " " + env.Drive.Letter, - CreateNoWindow = true, - UseShellExecute = false, - RedirectStandardOutput = true, - }, - }; - childProcess.Start(); - childProcess.WaitForExit(); - return childProcess.StandardOutput.ReadToEnd(); - }); - - // If we get that the firmware is out of date, tell the user - if (output.Contains("[ERROR] This drive isn't latest firmware. Please update.")) - { - MessageBox.Show($"DiscImageCreator has reported that drive {env.Drive.Letter} is not updated to the most recent firmware. Please update the firmware for your drive and try again.", "Outdated Firmware", MessageBoxButton.OK, MessageBoxImage.Error); - return -1; - } - // Otherwise, if we find the maximum read speed as reported - else if (output.Contains("ReadSpeedMaximum:")) - { - int index = output.IndexOf("ReadSpeedMaximum:"); - string readspeed = Regex.Match(output.Substring(index), @"ReadSpeedMaximum: [0-9]+KB/sec \(([0-9]*)x\)").Groups[1].Value; - if (!Int32.TryParse(readspeed, out int speed) || speed <= 0) - { - return -1; - } - - return speed; - } - - return -1; - } - - /// - /// Eject the disc using DIC - /// - public static async void EjectDisc(DumpEnvironment env) - { - // Validate that the required program exists - if (!File.Exists(env.DICPath)) - return; - - CancelDumping(env); - - // Validate we're not trying to eject a floppy disk - if (env.IsFloppy) - return; - - Process childProcess; - await Task.Run(() => - { - childProcess = new Process() - { - StartInfo = new ProcessStartInfo() - { - FileName = env.DICPath, - Arguments = DICCommands.Eject + " " + env.Drive.Letter, - CreateNoWindow = true, - UseShellExecute = false, - RedirectStandardOutput = true, - }, - }; - childProcess.Start(); - childProcess.WaitForExit(); - }); - } - - /// - /// Cancel an in-progress dumping process - /// - public static void CancelDumping(DumpEnvironment env) - { - try - { - if (env.dicProcess != null && !env.dicProcess.HasExited) - env.dicProcess.Kill(); - } - catch - { } - } - - /// - /// This executes the complete dump workflow on a DumpEnvironment - /// - public static async Task StartDumping(DumpEnvironment env) - { - Result result = ValidateEnvironment(env); - - // is something is wrong in environment return - if (!result) - return result; - - // execute DIC - await Task.Run(() => ExecuteDiskImageCreator(env)); - - // execute additional tools - result = Tasks.ExecuteAdditionalToolsAfterDIC(env); - - // is something is wrong with additional tools report and return - // TODO: don't return, just keep generating output from DIC - /*if (!result.Item1) - { - lbl_Status.Content = result.Item2; - btn_StartStop.Content = UIElements.StartDumping; - return; - }*/ - - // verify dump output and save it - result = Tasks.VerifyAndSaveDumpOutput(env); - - return result; - } - - /// - /// Validate the current DumpEnvironment - /// - /// DumpEnvirionment containing all required information - /// Result instance with the outcome - private static Result ValidateEnvironment(DumpEnvironment env) - { - // Validate that everything is good - if (!env.IsConfigurationValid()) - return Result.Failure("Error! Current configuration is not supported!"); - - env.AdjustForCustomConfiguration(); - env.FixOutputPaths(); - - // Validate that the required program exists - if (!File.Exists(env.DICPath)) - return Result.Failure("Error! Could not find DiscImageCreator!"); - - // If a complete dump already exists - if (env.FoundAllFiles()) - { - MessageBoxResult result = MessageBox.Show("A complete dump already exists! Are you sure you want to overwrite?", "Overwrite?", MessageBoxButton.YesNo, MessageBoxImage.Exclamation); - if (result == MessageBoxResult.No || result == MessageBoxResult.Cancel || result == MessageBoxResult.None) - { - return Result.Failure("Dumping aborted!"); - } - } - - return Result.Success(); - } - - /// - /// Run DiscImageCreator with the given DumpEnvironment - /// - /// DumpEnvirionment containing all required information - private static void ExecuteDiskImageCreator(DumpEnvironment env) - { - env.dicProcess = new Process() - { - StartInfo = new ProcessStartInfo() - { - FileName = env.DICPath, - Arguments = env.DICParameters, - }, - }; - env.dicProcess.Start(); - env.dicProcess.WaitForExit(); - } - - /// - /// Run any additional tools given a DumpEnvironment - /// - /// DumpEnvirionment containing all required information - /// Result instance with the outcome - private static Result ExecuteAdditionalToolsAfterDIC(DumpEnvironment env) - { - // Special cases - switch (env.System) - { - case KnownSystem.SegaSaturn: - if (!File.Exists(env.SubdumpPath)) - return Result.Failure("Error! Could not find subdump!"); - - ExecuteSubdump(env); - break; - } - - return Result.Success(); - } - - /// - /// Execute subdump for a (potential) Sega Saturn dump - /// - /// DumpEnvirionment containing all required information - private static async void ExecuteSubdump(DumpEnvironment env) - { - await Task.Run(() => - { - Process childProcess = new Process() - { - StartInfo = new ProcessStartInfo() - { - FileName = env.SubdumpPath, - Arguments = "-i " + env.Drive.Letter + ": -f " + Path.Combine(env.OutputDirectory, Path.GetFileNameWithoutExtension(env.OutputFilename) + "_subdump.sub") + "-mode 6 -rereadnum 25 -fix 2", - }, - }; - childProcess.Start(); - childProcess.WaitForExit(); - }); - } - - /// - /// Run protection scan on a given dump environment - /// - /// DumpEnvirionment containing all required information - /// Copy protection detected in the envirionment, if any - public static async Task RunProtectionScan(string path) - { - var found = await Task.Run(() => - { - return ProtectionFind.Scan(path); - }); - - if (found == null) - return "None found"; - - return string.Join("\n", found.Select(kvp => kvp.Key + ": " + kvp.Value).ToArray()); - } - - /// - /// Verify that the current environment has a complete dump and create submission info is possible - /// - /// DumpEnvirionment containing all required information - /// Result instance with the outcome - private static Result VerifyAndSaveDumpOutput(DumpEnvironment env) - { - // Check to make sure that the output had all the correct files - if (!env.FoundAllFiles()) - return Result.Failure("Error! Please check output directory as dump may be incomplete!"); - - Dictionary templateValues = env.ExtractOutputInformation(); - List formattedValues = env.FormatOutputData(templateValues); - bool success = env.WriteOutputData(formattedValues); - - return Result.Success(); - } - } -} diff --git a/DICUI/Utilities/DumpEnvironment.cs b/DICUI/Utilities/DumpEnvironment.cs index 37efc088..2878816c 100644 --- a/DICUI/Utilities/DumpEnvironment.cs +++ b/DICUI/Utilities/DumpEnvironment.cs @@ -52,23 +52,188 @@ namespace DICUI.Utilities public string DICParameters; // External process information - public Process dicProcess; + private Process dicProcess; + + #region Public Functionality /// - /// Checks if the configuration is valid + /// Cancel an in-progress dumping process /// - /// True if the configuration is valid, false otherwise - public bool IsConfigurationValid() + public void CancelDumping() { - return !((string.IsNullOrWhiteSpace(DICParameters) - || !Validators.ValidateParameters(DICParameters) - || (IsFloppy ^ Type == MediaType.Floppy))); + try + { + if (dicProcess != null && !dicProcess.HasExited) + dicProcess.Kill(); + } + catch + { } } + /// + /// Eject the disc using DIC + /// + public async void EjectDisc() + { + // Validate that the required program exists + if (!File.Exists(DICPath)) + return; + + CancelDumping(); + + // Validate we're not trying to eject a floppy disk + if (IsFloppy) + return; + + Process childProcess; + await Task.Run(() => + { + childProcess = new Process() + { + StartInfo = new ProcessStartInfo() + { + FileName = DICPath, + Arguments = DICCommands.Eject + " " + Drive.Letter, + CreateNoWindow = true, + UseShellExecute = false, + RedirectStandardOutput = true, + }, + }; + childProcess.Start(); + childProcess.WaitForExit(); + }); + } + + /// + /// Get disc speed using DIC + /// + /// Drive speed if possible, -1 on error + public async Task GetDiscSpeed() + { + // Validate that the required program exists + if (!File.Exists(DICPath)) + return -1; + + // Validate that the drive is set up + if (Drive == null) + return -1; + + // Validate we're not trying to get the speed for a floppy disk + if (IsFloppy) + return -1; + + // Get the drive speed directly + //int speed = Validators.GetDriveSpeed((char)selected?.Key); + //int speed = Validators.GetDriveSpeedEx((char)selected?.Key, _currentMediaType); + + // Get the drive speed from DIC, if possible + Process childProcess; + string output = await Task.Run(() => + { + childProcess = new Process() + { + StartInfo = new ProcessStartInfo() + { + FileName = DICPath, + Arguments = DICCommands.DriveSpeed + " " + Drive.Letter, + CreateNoWindow = true, + UseShellExecute = false, + RedirectStandardOutput = true, + }, + }; + childProcess.Start(); + childProcess.WaitForExit(); + return childProcess.StandardOutput.ReadToEnd(); + }); + + // If we get that the firmware is out of date, tell the user + if (output.Contains("[ERROR] This drive isn't latest firmware. Please update.")) + { + MessageBox.Show($"DiscImageCreator has reported that drive {Drive.Letter} is not updated to the most recent firmware. Please update the firmware for your drive and try again.", "Outdated Firmware", MessageBoxButton.OK, MessageBoxImage.Error); + return -1; + } + // Otherwise, if we find the maximum read speed as reported + else if (output.Contains("ReadSpeedMaximum:")) + { + int index = output.IndexOf("ReadSpeedMaximum:"); + string readspeed = Regex.Match(output.Substring(index), @"ReadSpeedMaximum: [0-9]+KB/sec \(([0-9]*)x\)").Groups[1].Value; + if (!Int32.TryParse(readspeed, out int speed) || speed <= 0) + { + return -1; + } + + return speed; + } + + return -1; + } + + /// + /// Get the full parameter string for DIC + /// + /// Nullable int representing the drive speed + /// String representing the params, null on error + public string GetFullParameters(int? driveSpeed) + { + // Populate with the correct params for inputs (if we're not on the default option) + if (System != KnownSystem.NONE && Type != MediaType.NONE) + { + // If drive letter is invalid, skip this + if (Drive == null) + return null; + + string command = Converters.KnownSystemAndMediaTypeToBaseCommand(System, Type); + List defaultParams = Converters.KnownSystemAndMediaTypeToParameters(System, Type); + return command + + " " + Drive.Letter + + " \"" + Path.Combine(OutputDirectory, OutputFilename) + "\" " + + (Type.DoesSupportDriveSpeed() && System.DoesSupportDriveSpeed() ? driveSpeed + " " : "") + + string.Join(" ", defaultParams); + } + + return null; + } + + /// + /// Execute a complete dump workflow + /// + public async Task StartDumping() + { + Result result = IsValidForDump(); + + // is something is wrong in environment return + if (!result) + return result; + + // execute DIC + await Task.Run(() => ExecuteDiskImageCreator()); + + // execute additional tools + result = ExecuteAdditionalToolsAfterDIC(); + + // is something is wrong with additional tools report and return + // TODO: don't return, just keep generating output from DIC + /*if (!result.Item1) + { + lbl_Status.Content = result.Item2; + btn_StartStop.Content = UIElements.StartDumping; + return; + }*/ + + // verify dump output and save it + result = VerifyAndSaveDumpOutput(); + + return result; + } + + #endregion + + #region Internal for Testing Purposes + /// /// Adjust the current environment if we are given custom parameters /// - public void AdjustForCustomConfiguration() + internal void AdjustForCustomConfiguration() { // If we have a custom configuration, we need to extract the best possible information from it if (System == KnownSystem.Custom) @@ -89,7 +254,7 @@ namespace DICUI.Utilities /// /// TODO: Investigate why the `&` replacement is needed /// - public void FixOutputPaths() + internal void FixOutputPaths() { // Only fix OutputDirectory if it's not blank or null if (!String.IsNullOrWhiteSpace(OutputDirectory)) @@ -101,96 +266,75 @@ namespace DICUI.Utilities } /// - /// Attempts to find the first track of a dumped disc based on the inputs + /// Checks if the parameters are valid /// - /// Proper path to first track, null on error - /// - /// By default, this assumes that the outputFilename doesn't contain a proper path, and just a name. - /// This can lead to a situation where the outputFilename contains a path, but only the filename gets - /// used in the processing and can lead to a "false null" return - /// - public string GetFirstTrack() + /// True if the configuration is valid, false otherwise + internal bool ParametersValid() { - // First, sanitized the output filename to strip off any potential extension - string outputFilename = Path.GetFileNameWithoutExtension(OutputFilename); + return !((string.IsNullOrWhiteSpace(DICParameters) + || !Validators.ValidateParameters(DICParameters) + || (IsFloppy ^ Type == MediaType.Floppy))); + } - // Go through all standard output naming schemes - string combinedBase = Path.Combine(OutputDirectory, outputFilename); - if (File.Exists(combinedBase + ".bin")) + #endregion + + #region Private Helpers + + /// + /// Run any additional tools given a DumpEnvironment + /// + /// Result instance with the outcome + private Result ExecuteAdditionalToolsAfterDIC() + { + // Special cases + switch (System) { - return combinedBase + ".bin"; - } - if (File.Exists(combinedBase + " (Track 1).bin")) - { - return combinedBase + " (Track 1).bin"; - } - if (File.Exists(combinedBase + " (Track 01).bin")) - { - return combinedBase + " (Track 01).bin"; - } - if (File.Exists(combinedBase + ".iso")) - { - return Path.Combine(combinedBase + ".iso"); + case KnownSystem.SegaSaturn: + if (!File.Exists(SubdumpPath)) + return Result.Failure("Error! Could not find subdump!"); + + ExecuteSubdump(); + break; } - return null; + return Result.Success(); } /// - /// Ensures that all required output files have been created + /// Run DiscImageCreator /// - /// - public bool FoundAllFiles() + private void ExecuteDiskImageCreator() { - // First, sanitized the output filename to strip off any potential extension - string outputFilename = Path.GetFileNameWithoutExtension(OutputFilename); - - // Now ensure that all required files exist - string combinedBase = Path.Combine(OutputDirectory, outputFilename); - switch (Type) + dicProcess = new Process() { - case MediaType.CD: - case MediaType.GDROM: // TODO: Verify GD-ROM outputs this - return File.Exists(combinedBase + ".c2") - && File.Exists(combinedBase + ".ccd") - && File.Exists(combinedBase + ".cue") - && File.Exists(combinedBase + ".dat") - && File.Exists(combinedBase + ".img") - && File.Exists(combinedBase + ".img_EdcEcc.txt") - && File.Exists(combinedBase + ".scm") - && File.Exists(combinedBase + ".sub") - && File.Exists(combinedBase + "_c2Error.txt") - && File.Exists(combinedBase + "_cmd.txt") - && File.Exists(combinedBase + "_disc.txt") - && File.Exists(combinedBase + "_drive.txt") - && File.Exists(combinedBase + "_img.cue") - && File.Exists(combinedBase + "_mainError.txt") - && File.Exists(combinedBase + "_mainInfo.txt") - && File.Exists(combinedBase + "_subError.txt") - && File.Exists(combinedBase + "_subInfo.txt") - // && File.Exists(combinedBase + "_subIntention.txt") - && File.Exists(combinedBase + "_subReadable.txt") - && File.Exists(combinedBase + "_volDesc.txt"); - case MediaType.DVD: - case MediaType.HDDVD: - case MediaType.BluRay: - case MediaType.GameCubeGameDisc: - case MediaType.WiiOpticalDisc: - return File.Exists(combinedBase + ".dat") - && File.Exists(combinedBase + "_cmd.txt") - && File.Exists(combinedBase + "_disc.txt") - && File.Exists(combinedBase + "_drive.txt") - && File.Exists(combinedBase + "_mainError.txt") - && File.Exists(combinedBase + "_mainInfo.txt") - && File.Exists(combinedBase + "_volDesc.txt"); - case MediaType.Floppy: - return File.Exists(combinedBase + ".dat") - && File.Exists(combinedBase + "_cmd.txt") - && File.Exists(combinedBase + "_disc.txt"); - default: - // Non-dumping commands will usually produce no output, so this is irrelevant - return true; - } + StartInfo = new ProcessStartInfo() + { + FileName = DICPath, + Arguments = DICParameters, + }, + }; + dicProcess.Start(); + dicProcess.WaitForExit(); + } + + /// + /// Execute subdump for a (potential) Sega Saturn dump + /// + private async void ExecuteSubdump() + { + await Task.Run(() => + { + Process childProcess = new Process() + { + StartInfo = new ProcessStartInfo() + { + FileName = SubdumpPath, + Arguments = "-i " + Drive.Letter + ": -f " + Path.Combine(OutputDirectory, Path.GetFileNameWithoutExtension(OutputFilename) + "_subdump.sub") + "-mode 6 -rereadnum 25 -fix 2", + }, + }; + childProcess.Start(); + childProcess.WaitForExit(); + }); } /// @@ -199,7 +343,7 @@ namespace DICUI.Utilities /// Drive letter to check /// Dictionary containing mapped output values, null on error /// TODO: Make sure that all special formats are accounted for - public Dictionary ExtractOutputInformation() + private Dictionary ExtractOutputInformation() { // Ensure the current disc combination should exist if (!Validators.GetValidMediaTypes(System).Contains(Type)) @@ -293,7 +437,7 @@ namespace DICUI.Utilities mappings[Template.SubIntentionField] = GetFullFile(combinedBase + "_subIntention.txt") ?? ""; } } - + break; case KnownSystem.SonyPlayStation2: mappings[Template.PlaystationEXEDateField] = GetPlayStationEXEDate(Drive.Letter) ?? ""; @@ -306,7 +450,7 @@ namespace DICUI.Utilities case MediaType.HDDVD: case MediaType.BluRay: string layerbreak = GetLayerbreak(combinedBase + "_disc.txt") ?? ""; - + // If we have a single-layer disc if (String.IsNullOrWhiteSpace(layerbreak)) { @@ -387,14 +531,13 @@ namespace DICUI.Utilities return mappings; } - /// /// Format the output data in a human readable way, separating each printed line into a new item in the list /// /// Information dictionary that should contain normalized values /// List of strings representing each line of an output file, null on error /// TODO: Get full list of customizable stuff for other systems - public List FormatOutputData(Dictionary info) + private List FormatOutputData(Dictionary info) { // Check to see if the inputs are valid if (info == null) @@ -543,55 +686,118 @@ namespace DICUI.Utilities } /// - /// Write the data to the output folder + /// Ensures that all required output files have been created /// - /// Preformatted list of lines to write out to the file - /// True on success, false on error - public bool WriteOutputData(List lines) + /// + private bool FoundAllFiles() { - // Check to see if the inputs are valid - if (lines == null) - { - return false; - } - - // Then, sanitized the output filename to strip off any potential extension + // First, sanitized the output filename to strip off any potential extension string outputFilename = Path.GetFileNameWithoutExtension(OutputFilename); - // Now write out to a generic file - try + // Now ensure that all required files exist + string combinedBase = Path.Combine(OutputDirectory, outputFilename); + switch (Type) { - using (StreamWriter sw = new StreamWriter(File.Open(Path.Combine(OutputDirectory, "!submissionInfo.txt"), FileMode.Create, FileAccess.Write))) - { - foreach (string line in lines) - { - sw.WriteLine(line); - } - } + case MediaType.CD: + case MediaType.GDROM: // TODO: Verify GD-ROM outputs this + return File.Exists(combinedBase + ".c2") + && File.Exists(combinedBase + ".ccd") + && File.Exists(combinedBase + ".cue") + && File.Exists(combinedBase + ".dat") + && File.Exists(combinedBase + ".img") + && File.Exists(combinedBase + ".img_EdcEcc.txt") + && File.Exists(combinedBase + ".scm") + && File.Exists(combinedBase + ".sub") + && File.Exists(combinedBase + "_c2Error.txt") + && File.Exists(combinedBase + "_cmd.txt") + && File.Exists(combinedBase + "_disc.txt") + && File.Exists(combinedBase + "_drive.txt") + && File.Exists(combinedBase + "_img.cue") + && File.Exists(combinedBase + "_mainError.txt") + && File.Exists(combinedBase + "_mainInfo.txt") + && File.Exists(combinedBase + "_subError.txt") + && File.Exists(combinedBase + "_subInfo.txt") + // && File.Exists(combinedBase + "_subIntention.txt") + && File.Exists(combinedBase + "_subReadable.txt") + && File.Exists(combinedBase + "_volDesc.txt"); + case MediaType.DVD: + case MediaType.HDDVD: + case MediaType.BluRay: + case MediaType.GameCubeGameDisc: + case MediaType.WiiOpticalDisc: + return File.Exists(combinedBase + ".dat") + && File.Exists(combinedBase + "_cmd.txt") + && File.Exists(combinedBase + "_disc.txt") + && File.Exists(combinedBase + "_drive.txt") + && File.Exists(combinedBase + "_mainError.txt") + && File.Exists(combinedBase + "_mainInfo.txt") + && File.Exists(combinedBase + "_volDesc.txt"); + case MediaType.Floppy: + return File.Exists(combinedBase + ".dat") + && File.Exists(combinedBase + "_cmd.txt") + && File.Exists(combinedBase + "_disc.txt"); + default: + // Non-dumping commands will usually produce no output, so this is irrelevant + return true; } - catch - { - // We don't care what the error is right now - return false; - } - - return true; } /// - /// Get the full lines from the input file, if possible + /// Get the existance of an anti-modchip string from the input file, if possible /// - /// file location - /// Full text of the file, null on error - private string GetFullFile(string filename) + /// _disc.txt file location + /// Antimodchip existance if possible, false on error + private bool GetAntiModchipDetected(string disc) { // If the file doesn't exist, we can't get info from it - if (!File.Exists(filename)) + if (!File.Exists(disc)) { - return null; + return false; } - return string.Join("\n", File.ReadAllLines(filename)); + using (StreamReader sr = File.OpenText(disc)) + { + try + { + // Check for either antimod string + string line = sr.ReadLine().Trim(); + while (!sr.EndOfStream) + { + if (line.StartsWith("Detected anti-mod string")) + { + return true; + } + else if (line.StartsWith("No anti-mod string")) + { + return false; + } + + line = sr.ReadLine().Trim(); + } + + return false; + } + catch + { + // We don't care what the exception is right now + return false; + } + } + } + + /// + /// Get the current copy protection scheme, if possible + /// + /// Copy protection scheme if possible, null on error + private string GetCopyProtection() + { + MessageBoxResult result = MessageBox.Show("Would you like to scan for copy protection? Warning: This may take a long time depending on the size of the disc!", "Copy Protection Scan", MessageBoxButton.YesNo, MessageBoxImage.Question); + if (result == MessageBoxResult.No || result == MessageBoxResult.Cancel || result == MessageBoxResult.None) + { + return "(CHECK WITH PROTECTIONID)"; + } + + return Task.Run(() => Validators.RunProtectionScanOnPath(Drive.Letter + ":\\")).Result; } /// @@ -699,61 +905,55 @@ namespace DICUI.Utilities } /// - /// Get the existance of an anti-modchip string from the input file, if possible + /// Attempts to find the first track of a dumped disc based on the inputs /// - /// _disc.txt file location - /// Antimodchip existance if possible, false on error - private bool GetAntiModchipDetected(string disc) + /// Proper path to first track, null on error + /// + /// By default, this assumes that the outputFilename doesn't contain a proper path, and just a name. + /// This can lead to a situation where the outputFilename contains a path, but only the filename gets + /// used in the processing and can lead to a "false null" return + /// + private string GetFirstTrack() { - // If the file doesn't exist, we can't get info from it - if (!File.Exists(disc)) + // First, sanitized the output filename to strip off any potential extension + string outputFilename = Path.GetFileNameWithoutExtension(OutputFilename); + + // Go through all standard output naming schemes + string combinedBase = Path.Combine(OutputDirectory, outputFilename); + if (File.Exists(combinedBase + ".bin")) { - return false; + return combinedBase + ".bin"; + } + if (File.Exists(combinedBase + " (Track 1).bin")) + { + return combinedBase + " (Track 1).bin"; + } + if (File.Exists(combinedBase + " (Track 01).bin")) + { + return combinedBase + " (Track 01).bin"; + } + if (File.Exists(combinedBase + ".iso")) + { + return Path.Combine(combinedBase + ".iso"); } - using (StreamReader sr = File.OpenText(disc)) - { - try - { - // Check for either antimod string - string line = sr.ReadLine().Trim(); - while (!sr.EndOfStream) - { - if (line.StartsWith("Detected anti-mod string")) - { - return true; - } - else if (line.StartsWith("No anti-mod string")) - { - return false; - } - - line = sr.ReadLine().Trim(); - } - - return false; - } - catch - { - // We don't care what the exception is right now - return false; - } - } + return null; } /// - /// Get the current copy protection scheme, if possible + /// Get the full lines from the input file, if possible /// - /// Copy protection scheme if possible, null on error - private string GetCopyProtection() + /// file location + /// Full text of the file, null on error + private string GetFullFile(string filename) { - MessageBoxResult result = MessageBox.Show("Would you like to scan for copy protection? Warning: This may take a long time depending on the size of the disc!", "Copy Protection Scan", MessageBoxButton.YesNo, MessageBoxImage.Question); - if (result == MessageBoxResult.No || result == MessageBoxResult.Cancel || result == MessageBoxResult.None) + // If the file doesn't exist, we can't get info from it + if (!File.Exists(filename)) { - return "(CHECK WITH PROTECTIONID)"; + return null; } - return Task.Run(() => Tasks.RunProtectionScan(Drive.Letter + ":\\")).Result; + return string.Join("\n", File.ReadAllLines(filename)); } /// @@ -1120,5 +1320,90 @@ namespace DICUI.Utilities } } } + + /// + /// Validate the current environment is ready for a dump + /// + /// Result instance with the outcome + private Result IsValidForDump() + { + // Validate that everything is good + if (!ParametersValid()) + return Result.Failure("Error! Current configuration is not supported!"); + + AdjustForCustomConfiguration(); + FixOutputPaths(); + + // Validate that the required program exists + if (!File.Exists(DICPath)) + return Result.Failure("Error! Could not find DiscImageCreator!"); + + // If a complete dump already exists + if (FoundAllFiles()) + { + MessageBoxResult result = MessageBox.Show("A complete dump already exists! Are you sure you want to overwrite?", "Overwrite?", MessageBoxButton.YesNo, MessageBoxImage.Exclamation); + if (result == MessageBoxResult.No || result == MessageBoxResult.Cancel || result == MessageBoxResult.None) + { + return Result.Failure("Dumping aborted!"); + } + } + + return Result.Success(); + } + + /// + /// Verify that the current environment has a complete dump and create submission info is possible + /// + /// Result instance with the outcome + private Result VerifyAndSaveDumpOutput() + { + // Check to make sure that the output had all the correct files + if (!FoundAllFiles()) + return Result.Failure("Error! Please check output directory as dump may be incomplete!"); + + Dictionary templateValues = ExtractOutputInformation(); + List formattedValues = FormatOutputData(templateValues); + bool success = WriteOutputData(formattedValues); + + return Result.Success(); + } + + /// + /// Write the data to the output folder + /// + /// Preformatted list of lines to write out to the file + /// True on success, false on error + private bool WriteOutputData(List lines) + { + // Check to see if the inputs are valid + if (lines == null) + { + return false; + } + + // Then, sanitized the output filename to strip off any potential extension + string outputFilename = Path.GetFileNameWithoutExtension(OutputFilename); + + // Now write out to a generic file + try + { + using (StreamWriter sw = new StreamWriter(File.Open(Path.Combine(OutputDirectory, "!submissionInfo.txt"), FileMode.Create, FileAccess.Write))) + { + foreach (string line in lines) + { + sw.WriteLine(line); + } + } + } + catch + { + // We don't care what the error is right now + return false; + } + + return true; + } + + #endregion } } diff --git a/DICUI/Utilities/Result.cs b/DICUI/Utilities/Result.cs new file mode 100644 index 00000000..d50deb49 --- /dev/null +++ b/DICUI/Utilities/Result.cs @@ -0,0 +1,27 @@ +namespace DICUI.Utilities +{ + /// + /// Generic success/failure result object, with optional message + /// + public class Result + { + private bool success; + public string Message { get; private set; } + + private Result(bool success, string message) + { + this.success = success; + this.Message = message; + } + + public static Result Success() => new Result(true, ""); + public static Result Success(string message) => new Result(true, message); + public static Result Success(string message, params object[] args) => new Result(true, string.Format(message, args)); + + public static Result Failure() => new Result(false, ""); + public static Result Failure(string message) => new Result(false, message); + public static Result Failure(string message, params object[] args) => new Result(false, string.Format(message, args)); + + public static implicit operator bool(Result result) => result.success; + } +} diff --git a/DICUI/Utilities/Validators.cs b/DICUI/Utilities/Validators.cs index cbf84306..78971e7c 100644 --- a/DICUI/Utilities/Validators.cs +++ b/DICUI/Utilities/Validators.cs @@ -5,8 +5,10 @@ using System.Linq; using System.Management; using System.Runtime.InteropServices; using System.Text.RegularExpressions; +using System.Threading.Tasks; using IMAPI2; using DICUI.Data; +using DICUI.External; namespace DICUI.Utilities { @@ -429,6 +431,111 @@ namespace DICUI.Utilities return drives; } + /// + /// Determine the base flags to use for checking a commandline + /// + /// Parameters as a string to check + /// Output nullable MediaType containing the found MediaType, if possible + /// Output nullable KnownSystem containing the found KnownSystem, if possible + /// Output string containing the found drive letter + /// Output string containing the found path + /// False on error (and all outputs set to null), true otherwise + public static bool DetermineFlags(string parameters, out MediaType? type, out KnownSystem? system, out string letter, out string path) + { + // Populate all output variables with null + type = null; system = null; letter = null; path = null; + + // The string has to be valid by itself first + if (String.IsNullOrWhiteSpace(parameters)) + { + return false; + } + + // Now split the string into parts for easier validation + // https://stackoverflow.com/questions/14655023/split-a-string-that-has-white-spaces-unless-they-are-enclosed-within-quotes + parameters = parameters.Trim(); + List parts = Regex.Matches(parameters, @"[\""].+?[\""]|[^ ]+") + .Cast() + .Select(m => m.Value) + .ToList(); + + type = Converters.BaseCommmandToMediaType(parts[0]); + system = Converters.BaseCommandToKnownSystem(parts[0]); + + // Determine what the commandline should look like given the first item + switch (parts[0]) + { + case DICCommands.CompactDisc: + case DICCommands.GDROM: + case DICCommands.Swap: + case DICCommands.Data: + case DICCommands.Audio: + case DICCommands.DigitalVideoDisc: + case DICCommands.BluRay: + case DICCommands.XBOX: + case DICCommands.Floppy: + if (!IsValidDriveLetter(parts[1])) + { + return false; + } + letter = parts[1]; + + if (IsFlag(parts[2])) + { + return false; + } + path = parts[2].Trim('\"'); + + // Special case for GameCube/Wii + if (parts.Contains(DICFlags.Raw)) + { + type = MediaType.GameCubeGameDisc; + system = KnownSystem.NintendoGameCube; + } + // Special case for PlayStation + else if (parts.Contains(DICFlags.NoFixSubQLibCrypt) + || parts.Contains(DICFlags.ScanAntiMod)) + { + type = MediaType.CD; + system = KnownSystem.SonyPlayStation; + } + // Special case for Saturn + else if (parts.Contains(DICFlags.SeventyFour)) + { + type = MediaType.CD; + system = KnownSystem.SegaSaturn; + } + + break; + case DICCommands.Stop: + case DICCommands.Start: + case DICCommands.Eject: + case DICCommands.Close: + case DICCommands.Reset: + case DICCommands.DriveSpeed: + if (!IsValidDriveLetter(parts[1])) + { + return false; + } + letter = parts[1]; + + break; + case DICCommands.Sub: + case DICCommands.MDS: + if (IsFlag(parts[1])) + { + return false; + } + path = parts[1].Trim('\"'); + + break; + default: + return false; + } + + return true; + } + /// /// Get the current disc type from drive letter /// @@ -659,7 +766,6 @@ namespace DICUI.Utilities return -1; } - /// /// Verify that, given a system and a media type, they are correct /// @@ -1115,108 +1221,21 @@ namespace DICUI.Utilities } /// - /// Determine the base flags to use for checking a commandline + /// Run protection scan on a given dump environment /// - /// Parameters as a string to check - /// Output nullable MediaType containing the found MediaType, if possible - /// Output nullable KnownSystem containing the found KnownSystem, if possible - /// Output string containing the found drive letter - /// Output string containing the found path - /// False on error (and all outputs set to null), true otherwise - public static bool DetermineFlags(string parameters, out MediaType? type, out KnownSystem? system, out string letter, out string path) + /// DumpEnvirionment containing all required information + /// Copy protection detected in the envirionment, if any + public static async Task RunProtectionScanOnPath(string path) { - // Populate all output variables with null - type = null; system = null; letter = null; path = null; - - // The string has to be valid by itself first - if (String.IsNullOrWhiteSpace(parameters)) + var found = await Task.Run(() => { - return false; - } + return ProtectionFind.Scan(path); + }); - // Now split the string into parts for easier validation - // https://stackoverflow.com/questions/14655023/split-a-string-that-has-white-spaces-unless-they-are-enclosed-within-quotes - parameters = parameters.Trim(); - List parts = Regex.Matches(parameters, @"[\""].+?[\""]|[^ ]+") - .Cast() - .Select(m => m.Value) - .ToList(); + if (found == null) + return "None found"; - type = Converters.BaseCommmandToMediaType(parts[0]); - system = Converters.BaseCommandToKnownSystem(parts[0]); - - // Determine what the commandline should look like given the first item - switch (parts[0]) - { - case DICCommands.CompactDisc: - case DICCommands.GDROM: - case DICCommands.Swap: - case DICCommands.Data: - case DICCommands.Audio: - case DICCommands.DigitalVideoDisc: - case DICCommands.BluRay: - case DICCommands.XBOX: - case DICCommands.Floppy: - if (!IsValidDriveLetter(parts[1])) - { - return false; - } - letter = parts[1]; - - if (IsFlag(parts[2])) - { - return false; - } - path = parts[2].Trim('\"'); - - // Special case for GameCube/Wii - if (parts.Contains(DICFlags.Raw)) - { - type = MediaType.GameCubeGameDisc; - system = KnownSystem.NintendoGameCube; - } - // Special case for PlayStation - else if (parts.Contains(DICFlags.NoFixSubQLibCrypt) - || parts.Contains(DICFlags.ScanAntiMod)) - { - type = MediaType.CD; - system = KnownSystem.SonyPlayStation; - } - // Special case for Saturn - else if (parts.Contains(DICFlags.SeventyFour)) - { - type = MediaType.CD; - system = KnownSystem.SegaSaturn; - } - - break; - case DICCommands.Stop: - case DICCommands.Start: - case DICCommands.Eject: - case DICCommands.Close: - case DICCommands.Reset: - case DICCommands.DriveSpeed: - if (!IsValidDriveLetter(parts[1])) - { - return false; - } - letter = parts[1]; - - break; - case DICCommands.Sub: - case DICCommands.MDS: - if (IsFlag(parts[1])) - { - return false; - } - path = parts[1].Trim('\"'); - - break; - default: - return false; - } - - return true; + return string.Join("\n", found.Select(kvp => kvp.Key + ": " + kvp.Value).ToArray()); } } }