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
This commit is contained in:
Matt Nadareski
2018-07-05 21:34:04 -07:00
committed by GitHub
parent fe04c6df73
commit c034df4266
13 changed files with 726 additions and 732 deletions

View File

@@ -63,7 +63,6 @@
<Compile Include="UI\AllowedSpeedsTest.cs" />
<Compile Include="Utilities\DumpEnvironmentTest.cs" />
<Compile Include="ResultTest.cs" />
<Compile Include="TasksTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Utilities\DriveTest.cs" />
<Compile Include="Utilities\ConvertersTest.cs" />

View File

@@ -1,4 +1,5 @@
using Xunit;
using DICUI.Utilities;
using Xunit;
namespace DICUI.Test
{

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -94,12 +94,12 @@
<Compile Include="Data\Constants.cs" />
<Compile Include="External\EVORE.cs" />
<Compile Include="Options.cs" />
<Compile Include="Tasks.cs" />
<Compile Include="External\ProtectionFind.cs" />
<Compile Include="UI\KnownSystemComboBoxItem.cs" />
<Compile Include="UI\AllowedSpeeds.cs" />
<Compile Include="Utilities\DumpEnvironment.cs" />
<Compile Include="Utilities\Extensions.cs" />
<Compile Include="Utilities\Result.cs" />
<Compile Include="Utilities\Validators.cs" />
<Compile Include="Utilities\Converters.cs" />
<Compile Include="OptionsWindow.xaml.cs">

View File

@@ -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
{

View File

@@ -27,13 +27,13 @@
<StackPanel VerticalAlignment="Top" Grid.ColumnSpan="4">
<Menu Width="Auto" Height="20" >
<MenuItem Header="_File">
<MenuItem x:Name="AppExit" Header="E_xit" HorizontalAlignment="Left" Width="140" Click="AppExit_Click" />
<MenuItem x:Name="AppExit" Header="E_xit" HorizontalAlignment="Left" Width="140" Click="AppExitClick" />
</MenuItem>
<MenuItem Header="_Tools">
<MenuItem x:Name="Options" Header="_Options" HorizontalAlignment="Left" Width="140" Click="tbr_Options_Click"/>
<MenuItem x:Name="Options" Header="_Options" HorizontalAlignment="Left" Width="140" Click="OptionsClick"/>
</MenuItem>
<MenuItem Header="_Help">
<MenuItem x:Name="About" Header="About" HorizontalAlignment="Left" Width="140" Click="About_Click"/>
<MenuItem x:Name="About" Header="_About" HorizontalAlignment="Left" Width="140" Click="AboutClick"/>
</MenuItem>
</Menu>
</StackPanel>

View File

@@ -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<Drive> _drives { get; set; }
private MediaType? _currentMediaType { get; set; }
private List<KnownSystem?> _systems { get; set; }
private List<MediaType?> _mediaTypes { get; set; }
private List<Drive> _drives;
private MediaType? _currentMediaType;
private List<KnownSystem?> _systems;
private List<MediaType?> _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
/// <summary>
/// Populate disc type according to system type
/// Populate media type according to system type
/// </summary>
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();
}
/// <summary>
@@ -310,32 +329,29 @@ namespace DICUI
/// </summary>
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<string> 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
}
/// <summary>
/// Set the current disc type in the combo box
/// Cache the current disc type to internal variable
/// </summary>
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);
}
/// <summary>
/// Set the current disc type in the combo box
/// </summary>
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);
}
}
}

View File

@@ -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")]

View File

@@ -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
{
/// <summary>
/// Generic success/failure result object, with optional message
/// </summary>
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;
}
/// <summary>
/// Class containing dumping tasks
/// </summary>
public class Tasks
{
/// <summary>
/// Get disc speed using DIC
/// </summary>
/// <returns>Drive speed if possible, -1 on error</returns>
public static async Task<int> 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;
}
/// <summary>
/// Eject the disc using DIC
/// </summary>
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();
});
}
/// <summary>
/// Cancel an in-progress dumping process
/// </summary>
public static void CancelDumping(DumpEnvironment env)
{
try
{
if (env.dicProcess != null && !env.dicProcess.HasExited)
env.dicProcess.Kill();
}
catch
{ }
}
/// <summary>
/// This executes the complete dump workflow on a DumpEnvironment
/// </summary>
public static async Task<Result> 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;
}
/// <summary>
/// Validate the current DumpEnvironment
/// </summary>
/// <param name="env">DumpEnvirionment containing all required information</param>
/// <returns>Result instance with the outcome</returns>
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();
}
/// <summary>
/// Run DiscImageCreator with the given DumpEnvironment
/// </summary>
/// <param name="env">DumpEnvirionment containing all required information</param>
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();
}
/// <summary>
/// Run any additional tools given a DumpEnvironment
/// </summary>
/// <param name="env">DumpEnvirionment containing all required information</param>
/// <returns>Result instance with the outcome</returns>
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();
}
/// <summary>
/// Execute subdump for a (potential) Sega Saturn dump
/// </summary>
/// <param name="env">DumpEnvirionment containing all required information</param>
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();
});
}
/// <summary>
/// Run protection scan on a given dump environment
/// </summary>
/// <param name="env">DumpEnvirionment containing all required information</param>
/// <returns>Copy protection detected in the envirionment, if any</returns>
public static async Task<string> 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());
}
/// <summary>
/// Verify that the current environment has a complete dump and create submission info is possible
/// </summary>
/// <param name="env">DumpEnvirionment containing all required information</param>
/// <returns>Result instance with the outcome</returns>
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<string, string> templateValues = env.ExtractOutputInformation();
List<string> formattedValues = env.FormatOutputData(templateValues);
bool success = env.WriteOutputData(formattedValues);
return Result.Success();
}
}
}

View File

@@ -52,23 +52,188 @@ namespace DICUI.Utilities
public string DICParameters;
// External process information
public Process dicProcess;
private Process dicProcess;
#region Public Functionality
/// <summary>
/// Checks if the configuration is valid
/// Cancel an in-progress dumping process
/// </summary>
/// <returns>True if the configuration is valid, false otherwise</returns>
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
{ }
}
/// <summary>
/// Eject the disc using DIC
/// </summary>
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();
});
}
/// <summary>
/// Get disc speed using DIC
/// </summary>
/// <returns>Drive speed if possible, -1 on error</returns>
public async Task<int> 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;
}
/// <summary>
/// Get the full parameter string for DIC
/// </summary>
/// <param name="driveSpeed">Nullable int representing the drive speed</param>
/// <returns>String representing the params, null on error</returns>
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<string> defaultParams = Converters.KnownSystemAndMediaTypeToParameters(System, Type);
return command
+ " " + Drive.Letter
+ " \"" + Path.Combine(OutputDirectory, OutputFilename) + "\" "
+ (Type.DoesSupportDriveSpeed() && System.DoesSupportDriveSpeed() ? driveSpeed + " " : "")
+ string.Join(" ", defaultParams);
}
return null;
}
/// <summary>
/// Execute a complete dump workflow
/// </summary>
public async Task<Result> 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
/// <summary>
/// Adjust the current environment if we are given custom parameters
/// </summary>
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
/// <remarks>
/// TODO: Investigate why the `&` replacement is needed
/// </remarks>
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
}
/// <summary>
/// Attempts to find the first track of a dumped disc based on the inputs
/// Checks if the parameters are valid
/// </summary>
/// <returns>Proper path to first track, null on error</returns>
/// <remarks>
/// 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
/// </remarks>
public string GetFirstTrack()
/// <returns>True if the configuration is valid, false otherwise</returns>
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
/// <summary>
/// Run any additional tools given a DumpEnvironment
/// </summary>
/// <returns>Result instance with the outcome</returns>
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();
}
/// <summary>
/// Ensures that all required output files have been created
/// Run DiscImageCreator
/// </summary>
/// <returns></returns>
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();
}
/// <summary>
/// Execute subdump for a (potential) Sega Saturn dump
/// </summary>
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();
});
}
/// <summary>
@@ -199,7 +343,7 @@ namespace DICUI.Utilities
/// <param name="driveLetter">Drive letter to check</param>
/// <returns>Dictionary containing mapped output values, null on error</returns>
/// <remarks>TODO: Make sure that all special formats are accounted for</remarks>
public Dictionary<string, string> ExtractOutputInformation()
private Dictionary<string, string> 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;
}
/// <summary>
/// Format the output data in a human readable way, separating each printed line into a new item in the list
/// </summary>
/// <param name="info">Information dictionary that should contain normalized values</param>
/// <returns>List of strings representing each line of an output file, null on error</returns>
/// <remarks>TODO: Get full list of customizable stuff for other systems</remarks>
public List<string> FormatOutputData(Dictionary<string, string> info)
private List<string> FormatOutputData(Dictionary<string, string> info)
{
// Check to see if the inputs are valid
if (info == null)
@@ -543,55 +686,118 @@ namespace DICUI.Utilities
}
/// <summary>
/// Write the data to the output folder
/// Ensures that all required output files have been created
/// </summary>
/// <param name="lines">Preformatted list of lines to write out to the file</param>
/// <returns>True on success, false on error</returns>
public bool WriteOutputData(List<string> lines)
/// <returns></returns>
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;
}
/// <summary>
/// Get the full lines from the input file, if possible
/// Get the existance of an anti-modchip string from the input file, if possible
/// </summary>
/// <param name="filename">file location</param>
/// <returns>Full text of the file, null on error</returns>
private string GetFullFile(string filename)
/// <param name="disc">_disc.txt file location</param>
/// <returns>Antimodchip existance if possible, false on error</returns>
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;
}
}
}
/// <summary>
/// Get the current copy protection scheme, if possible
/// </summary>
/// <returns>Copy protection scheme if possible, null on error</returns>
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;
}
/// <summary>
@@ -699,61 +905,55 @@ namespace DICUI.Utilities
}
/// <summary>
/// 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
/// </summary>
/// <param name="disc">_disc.txt file location</param>
/// <returns>Antimodchip existance if possible, false on error</returns>
private bool GetAntiModchipDetected(string disc)
/// <returns>Proper path to first track, null on error</returns>
/// <remarks>
/// 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
/// </remarks>
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;
}
/// <summary>
/// Get the current copy protection scheme, if possible
/// Get the full lines from the input file, if possible
/// </summary>
/// <returns>Copy protection scheme if possible, null on error</returns>
private string GetCopyProtection()
/// <param name="filename">file location</param>
/// <returns>Full text of the file, null on error</returns>
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));
}
/// <summary>
@@ -1120,5 +1320,90 @@ namespace DICUI.Utilities
}
}
}
/// <summary>
/// Validate the current environment is ready for a dump
/// </summary>
/// <returns>Result instance with the outcome</returns>
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();
}
/// <summary>
/// Verify that the current environment has a complete dump and create submission info is possible
/// </summary>
/// <returns>Result instance with the outcome</returns>
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<string, string> templateValues = ExtractOutputInformation();
List<string> formattedValues = FormatOutputData(templateValues);
bool success = WriteOutputData(formattedValues);
return Result.Success();
}
/// <summary>
/// Write the data to the output folder
/// </summary>
/// <param name="lines">Preformatted list of lines to write out to the file</param>
/// <returns>True on success, false on error</returns>
private bool WriteOutputData(List<string> 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
}
}

27
DICUI/Utilities/Result.cs Normal file
View File

@@ -0,0 +1,27 @@
namespace DICUI.Utilities
{
/// <summary>
/// Generic success/failure result object, with optional message
/// </summary>
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;
}
}

View File

@@ -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;
}
/// <summary>
/// Determine the base flags to use for checking a commandline
/// </summary>
/// <param name="parameters">Parameters as a string to check</param>
/// <param name="type">Output nullable MediaType containing the found MediaType, if possible</param>
/// <param name="system">Output nullable KnownSystem containing the found KnownSystem, if possible</param>
/// <param name="letter">Output string containing the found drive letter</param>
/// <param name="path">Output string containing the found path</param>
/// <returns>False on error (and all outputs set to null), true otherwise</returns>
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<string> parts = Regex.Matches(parameters, @"[\""].+?[\""]|[^ ]+")
.Cast<Match>()
.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;
}
/// <summary>
/// Get the current disc type from drive letter
/// </summary>
@@ -659,7 +766,6 @@ namespace DICUI.Utilities
return -1;
}
/// <summary>
/// Verify that, given a system and a media type, they are correct
/// </summary>
@@ -1115,108 +1221,21 @@ namespace DICUI.Utilities
}
/// <summary>
/// Determine the base flags to use for checking a commandline
/// Run protection scan on a given dump environment
/// </summary>
/// <param name="parameters">Parameters as a string to check</param>
/// <param name="type">Output nullable MediaType containing the found MediaType, if possible</param>
/// <param name="system">Output nullable KnownSystem containing the found KnownSystem, if possible</param>
/// <param name="letter">Output string containing the found drive letter</param>
/// <param name="path">Output string containing the found path</param>
/// <returns>False on error (and all outputs set to null), true otherwise</returns>
public static bool DetermineFlags(string parameters, out MediaType? type, out KnownSystem? system, out string letter, out string path)
/// <param name="env">DumpEnvirionment containing all required information</param>
/// <returns>Copy protection detected in the envirionment, if any</returns>
public static async Task<string> 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<string> parts = Regex.Matches(parameters, @"[\""].+?[\""]|[^ ]+")
.Cast<Match>()
.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());
}
}
}