Compare commits

..

25 Commits
1.16 ... 1.16.1

Author SHA1 Message Date
Matt Nadareski
8f3d325e7d Update to version 1.16.1 2020-05-07 15:40:29 -07:00
Matt Nadareski
a63472c6e6 Options (#201)
* Start reorganizing options and internals

* Make entire options flow more robust

* Few more TODOs, slightly cleaner code

* Simplify Options constructor

* Fix eject and reset

* Some other abstractions

* Enforce readonly

* Fix tests, like the TODO said

* Move specific output file parsing to specific parameters

* Add some future enums, add notes around .NET Core build path

* Wrap last incompatible .NET Core stuff

* Extract out CleanRip, fix a bunch of other spaghetti
2020-05-07 14:36:06 -07:00
Matt Nadareski
8c98005605 Fix CleanRip support 2020-05-07 14:23:49 -07:00
Matt Nadareski
8062d6cf17 Extract out CleanRip, fix a bunch of other spaghetti 2020-05-07 13:56:21 -07:00
Matt Nadareski
78bf6e63ed Wrap last incompatible .NET Core stuff 2020-05-07 13:03:24 -07:00
Matt Nadareski
68e0d759f7 Add some future enums, add notes around .NET Core build path 2020-05-07 12:58:37 -07:00
Matt Nadareski
26e72284af Move specific output file parsing to specific parameters 2020-05-06 20:24:33 -07:00
Matt Nadareski
0efecd6601 Fix tests, like the TODO said 2020-05-06 17:00:34 -07:00
Matt Nadareski
9a3c2eb626 Enforce readonly 2020-05-06 16:46:26 -07:00
Matt Nadareski
ca753b4526 Some other abstractions 2020-05-06 16:37:33 -07:00
Matt Nadareski
230b6ca721 Fix eject and reset 2020-05-06 16:06:30 -07:00
Matt Nadareski
dc90f9af3f Simplify Options constructor 2020-05-06 15:56:08 -07:00
Matt Nadareski
b5898c7ea3 Few more TODOs, slightly cleaner code 2020-05-06 15:44:46 -07:00
Matt Nadareski
36f1aea509 Make entire options flow more robust 2020-05-06 15:33:28 -07:00
Matt Nadareski
6742444182 Start reorganizing options and internals 2020-05-06 14:24:37 -07:00
Matt Nadareski
e01fd37e6b Typo 2020-05-05 14:37:34 -07:00
Matt Nadareski
ca7071f82a Update Aaru version for WIP builds 2020-05-05 14:23:23 -07:00
Matt Nadareski
3cb67e3e65 Add Python2 CNF parsing, forgot DumpEnv fixes 2020-05-01 15:02:58 -07:00
Matt Nadareski
e67dd589b5 Fix options, add fallbacks, consolidate code 2020-05-01 14:59:29 -07:00
Matt Nadareski
74f491eaaa Forgot the flag 2020-04-21 17:03:45 -07:00
Matt Nadareski
9ebd28ef5a More dd stuff, including AppVeyor. Why? Because. 2020-04-21 16:09:37 -07:00
Matt Nadareski
2a58052bfd So, I added DD support 2020-04-21 15:52:57 -07:00
Matt Nadareski
5ed73aff2b Mock out the basics needed for DD 2020-04-21 14:39:39 -07:00
Matt Nadareski
5a6ad09004 No DIC firmware check temporarily (fixes https://github.com/SabreTools/DICUI/issues/199) 2020-04-21 11:24:22 -07:00
Matt Nadareski
6a43b74043 Fix file location in AppVeyor builds 2020-04-13 12:17:17 -07:00
31 changed files with 4045 additions and 2357 deletions

View File

@@ -1,4 +1,13 @@
### 1.16.1 (2020-05-07)
- Add preliminary support for DD for Windows (end to end still NW)
- Add CNF parsing for Konami Python 2 discs (PS2-based)
- Updated included Aaru version
- Massive cleanup effort to detangle large chunks of code
- Miscellaneous bugfixes that came from the above
### 1.16 (2020-04-13)
- Updated to DIC version 20200403
- UI updates based on user feedback
- Added support for Aaru (formerly DiscImageChef)

View File

@@ -10,24 +10,26 @@ namespace DICUI.Check
public static void Main(string[] args)
{
// Help options
if (args.Length == 0
|| args[0] == "/h" || args[0] == "/?"
|| args[0] == "-h" || args[0] == "-?")
if (args.Length == 0 || args[0] == "-h" || args[0] == "-?")
{
DisplayHelp();
return;
}
// List options
if (args[0] == "/lm" || args[0] == "/listmedia"
|| args[0] == "-lm" || args[0] == "--listmedia")
if (args[0] == "-lm" || args[0] == "--listmedia")
{
ListMediaTypes();
Console.ReadLine();
return;
}
else if (args[0] == "/ls" || args[0] == "/listsystems"
|| args[0] == "-ls" || args[0] == "--listsystems")
else if (args[0] == "-lp" || args[0] == "--listprograms")
{
ListPrograms();
Console.ReadLine();
return;
}
else if (args[0] == "-ls" || args[0] == "--listsystems")
{
ListKnownSystems();
Console.ReadLine();
@@ -64,7 +66,13 @@ namespace DICUI.Check
for (; startIndex < args.Length; startIndex++)
{
// Redump login
if (args[startIndex] == "-c" || args[startIndex] == "--credentials")
if (args[startIndex].StartsWith("-c=") || args[startIndex].StartsWith("--credentials="))
{
string[] credentials = args[startIndex].Split('=')[1].Split(';');
username = credentials[0];
password = credentials[1];
}
else if (args[startIndex] == "-c" || args[startIndex] == "--credentials")
{
username = args[startIndex + 1];
password = args[startIndex + 2];
@@ -76,6 +84,11 @@ namespace DICUI.Check
{
internalProgram = args[startIndex].Split('=')[1];
}
else if (args[startIndex] == "-u" || args[startIndex] == "--use")
{
internalProgram = args[startIndex + 1];
startIndex++;
}
// Default, we fall out
else
@@ -102,19 +115,18 @@ namespace DICUI.Check
string filepath = Path.GetFullPath(args[i]);
// Now populate an environment
var env = new DumpEnvironment
// TODO: Replace this with Dictionary constructor
var options = new Options
{
OutputDirectory = "",
OutputFilename = filepath,
System = knownSystem,
Type = mediaType,
InternalProgram = internalProgram,
ScanForProtection = false,
PromptForDiscInformation = false,
InternalProgram = Converters.ToInternalProgram(internalProgram),
Username = username,
Password = password,
};
var env = new DumpEnvironment(options, "", filepath, null, knownSystem, mediaType, null);
env.FixOutputPaths();
// Finally, attempt to do the output dance
@@ -135,7 +147,7 @@ namespace DICUI.Check
Console.WriteLine("Usage:");
Console.WriteLine("DICUI.Check.exe <mediatype> <system> [options] </path/to/output.bin> ...");
Console.WriteLine();
Console.WriteLine(@"Common Media Types:\r\n
Console.WriteLine(@"Common Media Types:
bd / bluray - BD-ROM
cd / cdrom - CD-ROM
dvd - DVD-ROM
@@ -144,7 +156,7 @@ gd / gdrom - GD-ROM
umd - UMD");
Console.WriteLine("Run 'DICUI.Check.exe [-lm|--listmedia' for more options");
Console.WriteLine();
Console.WriteLine(@"Common Systems:\r\n
Console.WriteLine(@"Common Systems:
apple / mac - Apple Macintosh
cdi - Philips CD-i
ibm / ibmpc - IBM PC Compatible
@@ -156,9 +168,15 @@ xbox - Microsoft XBOX
x360 - Microsoft XBOX 360");
Console.WriteLine("Run 'DICUI.Check.exe [-ls|--listsystems' for more options");
Console.WriteLine();
Console.WriteLine(@"Common Options:\r\n
Console.WriteLine(@"Common Options:
-c username password - Redump credentials
-u - Check for Aaru");
-u - Set dumping program");
Console.WriteLine();
Console.WriteLine(@"Common Dumping Programs:
cr / cleanrip - CleanRip
dic - DiscImageCreator");
Console.WriteLine("Run 'DICUI.Check.exe [-lp|--listprograms' for more options");
Console.WriteLine();
}
/// <summary>
@@ -176,6 +194,21 @@ x360 - Microsoft XBOX 360");
}
}
/// <summary>
/// List all programs with their short usable names
/// </summary>
private static void ListPrograms()
{
Console.WriteLine("Supported Programs:");
foreach (var val in Enum.GetValues(typeof(InternalProgram)))
{
if (((InternalProgram)val) == InternalProgram.NONE)
continue;
Console.WriteLine($"{((InternalProgram?)val).LongName()}");
}
}
/// <summary>
/// List all known systems with their short usable names
/// </summary>

View File

@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.16")]
[assembly: AssemblyFileVersion("1.16.0.0")]
[assembly: AssemblyVersion("1.16.1")]
[assembly: AssemblyFileVersion("1.16.1.0")]

View File

@@ -1,8 +1,12 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Schema;
using DICUI.Data;
using DICUI.Utilities;
namespace DICUI.Aaru
{
@@ -212,7 +216,7 @@ namespace DICUI.Aaru
{
BaseCommand = Command.MediaDump;
InputValue = $"\\\\?\\{driveLetter.ToString()}:";
InputValue = $"\\\\?\\{driveLetter}:";
OutputValue = filename;
this[Flag.Force] = true;
@@ -224,7 +228,7 @@ namespace DICUI.Aaru
}
// First check to see if the combination of system and MediaType is valid
var validTypes = Utilities.Validators.GetValidMediaTypes(system);
var validTypes = Validators.GetValidMediaTypes(system);
if (!validTypes.Contains(type))
return;
@@ -305,7 +309,7 @@ namespace DICUI.Aaru
#endregion
if (BaseCommand != Command.NONE)
parameters.Add(Converters.LongName((Command)BaseCommand));
parameters.Add(Converters.LongName(BaseCommand));
else
return null;
@@ -1348,6 +1352,54 @@ namespace DICUI.Aaru
return true;
}
/// <summary>
/// Validate if all required output files exist
/// </summary>
/// <param name="basePath">Base filename and path to use for checking</param>
/// <param name="system">KnownSystem type representing the media</param>
/// <param name="type">MediaType type representing the media</param>
/// <returns></returns>
public override bool CheckAllOutputFilesExist(string basePath, KnownSystem? system, MediaType? type)
{
return File.Exists(basePath + ".cicm.xml")
&& File.Exists(basePath + ".aif")
&& File.Exists(basePath + ".ibg")
&& File.Exists(basePath + ".log")
&& File.Exists(basePath + ".mhddlog.bin")
&& File.Exists(basePath + ".resume.xml");
}
/// <summary>
/// Generate a SubmissionInfo for the output files
/// </summary>
/// <param name="info">Base submission info to fill in specifics for</param>
/// <param name="basePath">Base filename and path to use for checking</param>
/// <param name="system">KnownSystem type representing the media</param>
/// <param name="type">MediaType type representing the media</param>
/// <param name="drive">Drive representing the disc to get information from</param>
/// <returns></returns>
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, KnownSystem? system, MediaType? type, Drive drive)
{
// TODO: Fill in submission info specifics for Aaru
string outputDirectory = Path.GetDirectoryName(basePath);
// Fill in the hash data
info.TracksAndWriteOffsets.ClrMameProData = GenerateDatfile(basePath + ".cicm.xml");
switch (type)
{
case MediaType.CDROM:
case MediaType.GDROM: // TODO: Verify GD-ROM outputs this
info.TracksAndWriteOffsets.Cuesheet = GenerateCuesheet(basePath + ".aif", basePath + ".cicm.xml") ?? "";
break;
}
switch (system)
{
}
}
/// <summary>
/// Get the list of commands that use a given flag
/// </summary>
@@ -1781,5 +1833,255 @@ namespace DICUI.Aaru
return string.Empty;
}
#region Information Extraction Methods
/// <summary>
/// Generate a cuesheet string based on CICM sidecar data
/// </summary>
/// <param name="aif">AIF output image</param>
/// <param name="cicmSidecar">CICM Sidecar data generated by Aaru</param>
/// <returns>String containing the cuesheet, null on error</returns>
private string GenerateCuesheet(string aif, string cicmSidecar)
{
// Note that this path only generates a cuesheet against a single BIN, not split
// If the files don't exist, we can't get info from them
if (!File.Exists(aif) || !File.Exists(cicmSidecar))
return null;
// If this is being run in Check, we can't run Aaru
if (string.IsNullOrEmpty(ExecutablePath))
return null;
var convertParams = new Parameters(null)
{
BaseCommand = Command.ImageConvert,
InputValue = aif,
OutputValue = aif + ".cue",
};
convertParams[Flag.XMLSidecar] = true;
convertParams.XMLSidecarValue = cicmSidecar;
// TODO: How do we get around this generation???
ExecuteInternalProgram(convertParams).ConfigureAwait(false).GetAwaiter().GetResult();
File.Delete(aif + ".bin");
return GetFullFile(aif + ".cue");
}
/// <summary>
/// Generate a CMP XML datfile string based on CICM sidecar data
/// </summary>
/// <param name="cicmSidecar">CICM Sidecar data generated by Aaru</param>
/// <returns>String containing the datfile, null on error</returns>
private string GenerateDatfile(string cicmSidecar)
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(cicmSidecar))
return null;
// Required variables
int totalTracks = 0;
string datfile = string.Empty;
// Open and read in the XML file
XmlReader xtr = XmlReader.Create(cicmSidecar, new XmlReaderSettings
{
CheckCharacters = false,
DtdProcessing = DtdProcessing.Ignore,
IgnoreComments = true,
IgnoreWhitespace = true,
ValidationFlags = XmlSchemaValidationFlags.None,
ValidationType = ValidationType.None,
});
// If the reader is null for some reason, we can't do anything
if (xtr == null)
return null;
// Only care about CICM sidecar files
xtr.MoveToContent();
if (xtr.Name != "CICMMetadata")
return null;
// Only care about OpticalDisc types
// TODO: Aaru - Support floppy images
xtr = xtr.ReadSubtree();
xtr.MoveToContent();
xtr.Read();
if (xtr.Name != "OpticalDisc")
return null;
// Get track count and all tracks now
xtr = xtr.ReadSubtree();
xtr.MoveToContent();
xtr.Read();
while (!xtr.EOF)
{
// We only want elements
if (xtr.NodeType != XmlNodeType.Element)
{
xtr.Read();
continue;
}
switch (xtr.Name)
{
// Total track count
case "Tracks":
totalTracks = xtr.ReadElementContentAsInt();
break;
// Individual track data
case "Track":
XmlReader trackReader = xtr.ReadSubtree();
if (trackReader == null)
return null;
int trackNumber = -1;
long size = -1;
string crc32 = string.Empty;
string md5 = string.Empty;
string sha1 = string.Empty;
trackReader.MoveToContent();
trackReader.Read();
while (!trackReader.EOF)
{
// We only want elements
if (trackReader.NodeType != XmlNodeType.Element)
{
trackReader.Read();
continue;
}
switch (trackReader.Name)
{
// Track size
case "Size":
size = trackReader.ReadElementContentAsLong();
break;
// Track number
case "Sequence":
XmlReader sequenceReader = trackReader.ReadSubtree();
if (sequenceReader == null)
return null;
sequenceReader.MoveToContent();
sequenceReader.Read();
while (!sequenceReader.EOF)
{
// We only want elements
if (sequenceReader.NodeType != XmlNodeType.Element)
{
sequenceReader.Read();
continue;
}
switch (sequenceReader.Name)
{
case "TrackNumber":
trackNumber = sequenceReader.ReadElementContentAsInt();
break;
default:
trackReader.Skip();
break;
}
}
// Skip the sequence now that we've processed it
trackReader.Skip();
break;
// Checksums
case "Checksums":
XmlReader checksumReader = trackReader.ReadSubtree();
if (checksumReader == null)
return null;
checksumReader.MoveToContent();
checksumReader.Read();
while (!checksumReader.EOF)
{
// We only want elements
if (checksumReader.NodeType != XmlNodeType.Element)
{
checksumReader.Read();
continue;
}
switch (checksumReader.Name)
{
case "Checksum":
string checksumType = checksumReader.GetAttribute("type");
string checksumValue = checksumReader.ReadElementContentAsString();
switch (checksumType)
{
case "crc32":
crc32 = checksumValue;
break;
case "md5":
md5 = checksumValue;
break;
case "sha1":
sha1 = checksumValue;
break;
}
break;
default:
checksumReader.Skip();
break;
}
}
// Skip the checksums now that we've processed it
trackReader.Skip();
break;
default:
trackReader.Skip();
break;
}
}
// Build the track datfile data and append
string trackName = Path.GetFileName(cicmSidecar).Replace(".cicm.xml", string.Empty);
if (totalTracks == 1)
{
datfile += $"<rom name=\"{trackName}.bin\" size=\"{size}\" crc=\"{crc32}\" md5=\"{md5}\" sha1=\"{sha1}\" />\n";
}
else if (totalTracks > 1 && totalTracks < 10)
{
datfile += $"<rom name=\"{trackName} (Track {trackNumber}).bin\" size=\"{size}\" crc=\"{crc32}\" md5=\"{md5}\" sha1=\"{sha1}\" />\n";
}
else
{
datfile += $"<rom name=\"{trackName} (Track {trackNumber:2}).bin\" size=\"{size}\" crc=\"{crc32}\" md5=\"{md5}\" sha1=\"{sha1}\" />\n";
}
// Skip the track now that we've processed it
xtr.Skip();
break;
default:
xtr.Skip();
break;
}
}
return datfile;
}
#endregion
}
}

View File

@@ -0,0 +1,319 @@
using System.IO;
using DICUI.Data;
using DICUI.Utilities;
namespace DICUI.CleanRip
{
/// <summary>
/// Represents a generic set of CleanRip parameters
/// </summary>
public class Parameters : BaseParameters
{
/// <summary>
/// Populate a Parameters object from a param string
/// </summary>
/// <param name="parameters">String possibly representing a set of parameters</param>
public Parameters(string parameters)
: base(parameters)
{
this.InternalProgram = InternalProgram.CleanRip;
}
/// <summary>
/// Generate parameters based on a set of known inputs
/// </summary>
/// <param name="system">KnownSystem value to use</param>
/// <param name="type">MediaType value to use</param>
/// <param name="driveLetter">Drive letter to use</param>
/// <param name="filename">Filename to use</param>
/// <param name="driveSpeed">Drive speed to use</param>
/// <param name="paranoid">Enable paranoid mode (safer dumping)</param>
/// <param name="quietMode">Enable quiet mode (no beeps)</param>
/// <param name="retryCount">User-defined reread count</param>
public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, bool paranoid, bool quietMode, int retryCount)
: base(system, type, driveLetter, filename, driveSpeed, paranoid, quietMode, retryCount)
{
}
/// <summary>
/// Blindly generate a parameter string based on the inputs
/// </summary>
/// <returns>Correctly formatted parameter string, null on error</returns>
public override string GenerateParameters() => null;
/// <summary>
/// Get the input path from the implementation
/// </summary>
/// <returns>String representing the path, null on error</returns>
public override string InputPath() => null;
/// <summary>
/// Get the output path from the implementation
/// </summary>
/// <returns>String representing the path, null on error</returns>
public override string OutputPath() => null;
/// <summary>
/// Get the processing speed from the implementation
/// </summary>
/// <returns>int? representing the speed, null on error</returns>
public override int? GetSpeed() => null;
/// <summary>
/// Set the processing speed int the implementation
/// </summary>
/// <param name="speed">int? representing the speed</param>
public override void SetSpeed(int? speed) { }
/// <summary>
/// Get the MediaType from the current set of parameters
/// </summary>
/// <returns>MediaType value if successful, null on error</returns>
public override MediaType? GetMediaType() => null;
/// <summary>
/// Gets if the current command is considered a dumping command or not
/// </summary>
/// <returns>True if it's a dumping command, false otherwise</returns>
public override bool IsDumpingCommand() => true;
/// <summary>
/// Reset all special variables to have default values
/// </summary>
protected override void ResetValues() { }
/// <summary>
/// Set default parameters for a given system and media type
/// </summary>
/// <param name="system">KnownSystem value to use</param>
/// <param name="type">MediaType value to use</param>
/// <param name="driveLetter">Drive letter to use</param>
/// <param name="filename">Filename to use</param>
/// <param name="driveSpeed">Drive speed to use</param>
/// <param name="paranoid">Enable paranoid mode (safer dumping)</param>
/// <param name="retryCount">User-defined reread count</param>
protected override void SetDefaultParameters(
KnownSystem? system,
MediaType? type,
char driveLetter,
string filename,
int? driveSpeed,
bool paranoid,
int retryCount)
{
}
/// <summary>
/// Scan a possible parameter string and populate whatever possible
/// </summary>
/// <param name="parameters">String possibly representing parameters</param>
/// <returns></returns>
protected override bool ValidateAndSetParameters(string parameters) => true;
/// <summary>
/// Validate if all required output files exist
/// </summary>
/// <param name="basePath">Base filename and path to use for checking</param>
/// <param name="system">KnownSystem type representing the media</param>
/// <param name="type">MediaType type representing the media</param>
/// <returns></returns>
public override bool CheckAllOutputFilesExist(string basePath, KnownSystem? system, MediaType? type)
{
switch (type)
{
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
return File.Exists(basePath + "-dumpinfo.txt")
&& File.Exists(basePath + ".bca");
default:
return false;
}
}
/// <summary>
/// Generate a SubmissionInfo for the output files
/// </summary>
/// <param name="info">Base submission info to fill in specifics for</param>
/// <param name="basePath">Base filename and path to use for checking</param>
/// <param name="system">KnownSystem type representing the media</param>
/// <param name="type">MediaType type representing the media</param>
/// <param name="drive">Drive representing the disc to get information from</param>
/// <returns></returns>
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, KnownSystem? system, MediaType? type, Drive drive)
{
info.TracksAndWriteOffsets.ClrMameProData = GetCleanripDatfile(basePath + ".iso", basePath + "-dumpinfo.txt");
// Extract info based generically on MediaType
switch (type)
{
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
if (File.Exists(basePath + ".bca"))
info.Extras.BCA = GetFullFile(basePath + ".bca", true);
if (GetGameCubeWiiInformation(basePath + "-dumpinfo.txt", out Region? gcRegion, out string gcVersion))
{
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? gcRegion;
info.VersionAndEditions.Version = string.IsNullOrEmpty(info.VersionAndEditions.Version) ? gcVersion : info.VersionAndEditions.Version;
}
break;
}
}
#region Information Extraction Methods
/// <summary>
/// Get a formatted datfile from the cleanrip output, if possible
/// </summary>
/// <param name="iso">Path to ISO file</param>
/// <param name="dumpinfo">Path to discinfo file</param>
/// <returns></returns>
private string GetCleanripDatfile(string iso, string dumpinfo)
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(dumpinfo))
return null;
using (StreamReader sr = File.OpenText(dumpinfo))
{
long size = new FileInfo(iso).Length;
string crc = string.Empty;
string md5 = string.Empty;
string sha1 = string.Empty;
try
{
// Make sure this file is a dumpinfo
if (!sr.ReadLine().Contains("--File Generated by CleanRip"))
return null;
// Read all lines and gather dat information
while (!sr.EndOfStream)
{
string line = sr.ReadLine().Trim();
if (line.StartsWith("CRC32"))
crc = line.Substring(7).ToLowerInvariant();
else if (line.StartsWith("MD5"))
md5 = line.Substring(5);
else if (line.StartsWith("SHA-1"))
sha1 = line.Substring(7);
}
return $"<rom name=\"{Path.GetFileName(iso)}\" size=\"{size}\" crc=\"{crc}\" md5=\"{md5}\" sha1=\"{sha1}\" />";
}
catch
{
// We don't care what the exception is right now
return null;
}
}
}
/// <summary>
/// Get the extracted GC and Wii version
/// </summary>
/// <param name="dumpinfo">Path to discinfo file</param>
/// <param name="region">Output region, if possible</param>
/// <param name="version">Output internal version of the game</param>
/// <returns></returns>
private bool GetGameCubeWiiInformation(string dumpinfo, out Region? region, out string version)
{
region = null; version = null;
// If the file doesn't exist, we can't get info from it
if (!File.Exists(dumpinfo))
return false;
using (StreamReader sr = File.OpenText(dumpinfo))
{
try
{
// Make sure this file is a dumpinfo
if (!sr.ReadLine().Contains("--File Generated by CleanRip"))
return false;
// Read all lines and gather dat information
while (!sr.EndOfStream)
{
string line = sr.ReadLine().Trim();
if (line.StartsWith("Version"))
{
version = line.Substring(9);
}
else if (line.StartsWith("Filename"))
{
string serial = line.Substring(10);
// char gameType = serial[0];
// string gameid = serial[1] + serial[2];
// string version = serial[4] + serial[5]
switch (serial[3])
{
case 'A':
region = Region.World;
break;
case 'D':
region = Region.Germany;
break;
case 'E':
region = Region.USA;
break;
case 'F':
region = Region.France;
break;
case 'I':
region = Region.Italy;
break;
case 'J':
region = Region.Japan;
break;
case 'K':
region = Region.Korea;
break;
case 'L':
region = Region.Europe; // Japanese import to Europe
break;
case 'M':
region = Region.Europe; // American import to Europe
break;
case 'N':
region = Region.USA; // Japanese import to USA
break;
case 'P':
region = Region.Europe;
break;
case 'R':
region = Region.Russia;
break;
case 'S':
region = Region.Spain;
break;
case 'Q':
region = Region.Korea; // Korea with Japanese language
break;
case 'T':
region = Region.Korea; // Korea with English language
break;
case 'X':
region = null; // Not a real region code
break;
}
}
}
return true;
}
catch
{
// We don't care what the exception is right now
return false;
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,31 @@
namespace DICUI.DD
{
/// <summary>
/// Top-level commands for DD
/// </summary>
public static class CommandStrings
{
public const string List = "--list";
}
/// <summary>
/// Dumping flags for DD
/// </summary>
public static class FlagStrings
{
// Boolean flags
public const string Progress = "--progress";
public const string Size = "--size";
// Int64 flags
public const string BlockSize = "bs";
public const string Count = "count";
public const string Seek = "seek";
public const string Skip = "skip";
// String flags
public const string Filter = "--filter";
public const string InputFile = "if";
public const string OutputFile = "of";
}
}

View File

@@ -0,0 +1,104 @@
using DICUI.Data;
namespace DICUI.DD
{
public static class Converters
{
#region Cross-enumeration conversions
/// <summary>
/// Get the default extension for a given disc type
/// </summary>
/// <param name="type">MediaType value to check</param>
/// <returns>Valid extension (with leading '.'), null on error</returns>
public static string Extension(MediaType? type)
{
// DD has a single, unified output format by default
return ".bin";
}
#endregion
#region Convert to Long Name
/// <summary>
/// Get the string representation of the Command enum values
/// </summary>
/// <param name="command">Command value to convert</param>
/// <returns>String representing the value, if possible</returns>
public static string LongName(Command command)
{
switch (command)
{
case Command.List:
return CommandStrings.List;
case Command.NONE:
default:
return "";
}
}
/// <summary>
/// Get the string representation of the Flag enum values
/// </summary>
/// <param name="command">Flag value to convert</param>
/// <returns>String representing the value, if possible</returns>
public static string LongName(Flag flag)
{
switch (flag)
{
// Boolean flags
case Flag.Progress:
return FlagStrings.Progress;
case Flag.Size:
return FlagStrings.Size;
// Int64 flags
case Flag.BlockSize:
return FlagStrings.BlockSize;
case Flag.Count:
return FlagStrings.Count;
case Flag.Seek:
return FlagStrings.Seek;
case Flag.Skip:
return FlagStrings.Skip;
// String flags
case Flag.Filter:
return FlagStrings.Filter;
case Flag.InputFile:
return FlagStrings.InputFile;
case Flag.OutputFile:
return FlagStrings.OutputFile;
case Flag.NONE:
default:
return "";
}
}
#endregion
#region Convert From String
/// <summary>
/// Get the Command enum value for a given string
/// </summary>
/// <param name="command">String value to convert</param>
/// <returns>Command represented by the string(s), if possible</returns>
public static Command StringToCommand(string command)
{
switch (command)
{
case CommandStrings.List:
return Command.List;
default:
return Command.NONE;
}
}
#endregion
}
}

View File

@@ -0,0 +1,34 @@
namespace DICUI.DD
{
/// <summary>
/// Supported DD commands
/// </summary>
public enum Command: int
{
NONE = 0, // For DD, this represents a normal dump
List,
}
/// <summary>
/// Supported DD flags
/// </summary>
public enum Flag : int
{
NONE = 0,
// Boolean flags
Progress,
Size,
// Int64 flags
BlockSize,
Count,
Seek,
Skip,
// String flags
Filter,
InputFile,
OutputFile,
}
}

View File

@@ -0,0 +1,620 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using DICUI.Data;
using DICUI.Utilities;
namespace DICUI.DD
{
/// <summary>
/// Represents a generic set of DD parameters
/// </summary>
public class Parameters : BaseParameters
{
/// <summary>
/// Base command to run
/// </summary>
public Command BaseCommand { get; set; }
/// <summary>
/// Set of flags to pass to the executable
/// </summary>
protected Dictionary<Flag, bool?> _flags = new Dictionary<Flag, bool?>();
public bool? this[Flag key]
{
get
{
if (_flags.ContainsKey(key))
return _flags[key];
return null;
}
set
{
_flags[key] = value;
}
}
protected internal IEnumerable<Flag> Keys => _flags.Keys;
#region Flag Values
public long? BlockSizeValue { get; set; }
public long? CountValue { get; set; }
// fixed, removable, disk, partition
public string FilterValue { get; set; }
public string InputFileValue { get; set; }
public string OutputFileValue { get; set; }
public long? SeekValue { get; set; }
public long? SkipValue { get; set; }
#endregion
/// <summary>
/// Populate a Parameters object from a param string
/// </summary>
/// <param name="parameters">String possibly representing a set of parameters</param>
public Parameters(string parameters)
: base(parameters)
{
this.InternalProgram = InternalProgram.DD;
}
/// <summary>
/// Generate parameters based on a set of known inputs
/// </summary>
/// <param name="system">KnownSystem value to use</param>
/// <param name="type">MediaType value to use</param>
/// <param name="driveLetter">Drive letter to use</param>
/// <param name="filename">Filename to use</param>
/// <param name="driveSpeed">Drive speed to use</param>
/// <param name="paranoid">Enable paranoid mode (safer dumping)</param>
/// <param name="quietMode">Enable quiet mode (no beeps)</param>
/// <param name="retryCount">User-defined reread count</param>
public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, bool paranoid, bool quietMode, int retryCount)
: base(system, type, driveLetter, filename, driveSpeed, paranoid, quietMode, retryCount)
{
}
/// <summary>
/// Blindly generate a parameter string based on the inputs
/// </summary>
/// <returns>Correctly formatted parameter string, null on error</returns>
public override string GenerateParameters()
{
List<string> parameters = new List<string>();
if (BaseCommand != Command.NONE)
parameters.Add(Converters.LongName(BaseCommand));
#region Boolean flags
// Progress
if (GetSupportedCommands(Flag.Progress).Contains(BaseCommand))
{
if (this[Flag.Progress] == true)
parameters.Add($"{this[Flag.Progress]}");
}
// Size
if (GetSupportedCommands(Flag.Size).Contains(BaseCommand))
{
if (this[Flag.Size] == true)
parameters.Add($"{this[Flag.Size]}");
}
#endregion
#region Int64 flags
// Block Size
if (GetSupportedCommands(Flag.BlockSize).Contains(BaseCommand))
{
if (this[Flag.BlockSize] == true && BlockSizeValue != null)
parameters.Add($"{Converters.LongName(Flag.BlockSize)}={BlockSizeValue}");
}
// Count
if (GetSupportedCommands(Flag.Count).Contains(BaseCommand))
{
if (this[Flag.Count] == true && CountValue != null)
parameters.Add($"{Converters.LongName(Flag.Count)}={CountValue}");
}
// Seek
if (GetSupportedCommands(Flag.Seek).Contains(BaseCommand))
{
if (this[Flag.Seek] == true && SeekValue != null)
parameters.Add($"{Converters.LongName(Flag.Seek)}={SeekValue}");
}
// Skip
if (GetSupportedCommands(Flag.Skip).Contains(BaseCommand))
{
if (this[Flag.Skip] == true && SkipValue != null)
parameters.Add($"{Converters.LongName(Flag.Skip)}={SkipValue}");
}
#endregion
#region String flags
// Filter
if (GetSupportedCommands(Flag.Filter).Contains(BaseCommand))
{
if (this[Flag.Filter] == true && FilterValue != null)
parameters.Add($"{Converters.LongName(Flag.Filter)}={FilterValue}");
}
// Input File
if (GetSupportedCommands(Flag.InputFile).Contains(BaseCommand))
{
if (this[Flag.InputFile] == true && InputFileValue != null)
parameters.Add($"{Converters.LongName(Flag.InputFile)}={InputFileValue}");
else
return null;
}
// Output File
if (GetSupportedCommands(Flag.OutputFile).Contains(BaseCommand))
{
if (this[Flag.OutputFile] == true && OutputFileValue != null)
parameters.Add($"{Converters.LongName(Flag.OutputFile)}={OutputFileValue}");
else
return null;
}
#endregion
return string.Empty;
}
/// <summary>
/// Get the input path from the implementation
/// </summary>
/// <returns>String representing the path, null on error</returns>
public override string InputPath() => InputFileValue;
/// <summary>
/// Get the output path from the implementation
/// </summary>
/// <returns>String representing the path, null on error</returns>
public override string OutputPath() => OutputFileValue;
/// <summary>
/// Get the processing speed from the implementation
/// </summary>
/// <returns>int? representing the speed, null on error</returns>
/// <remarks>DD does not support drive speeds</remarks>
public override int? GetSpeed() => 1;
/// <summary>
/// Set the processing speed int the implementation
/// </summary>
/// <param name="speed">int? representing the speed</param>
/// <remarks>DD does not support drive speeds</remarks>
public override void SetSpeed(int? speed)
{
}
/// <summary>
/// Get the MediaType from the current set of parameters
/// </summary>
/// <returns>MediaType value if successful, null on error</returns>
/// <remarks>DD does not know the difference between media types</remarks>
public override MediaType? GetMediaType() => null;
/// <summary>
/// Gets if the current command is considered a dumping command or not
/// </summary>
/// <returns>True if it's a dumping command, false otherwise</returns>
public override bool IsDumpingCommand()
{
switch (this.BaseCommand)
{
case Command.List:
return false;
default:
return true;
}
}
/// <summary>
/// Reset all special variables to have default values
/// </summary>
protected override void ResetValues()
{
BaseCommand = Command.NONE;
_flags = new Dictionary<Flag, bool?>();
BlockSizeValue = null;
CountValue = null;
InputFileValue = null;
OutputFileValue = null;
SeekValue = null;
SkipValue = null;
}
/// <summary>
/// Set default parameters for a given system and media type
/// </summary>
/// <param name="system">KnownSystem value to use</param>
/// <param name="type">MediaType value to use</param>
/// <param name="driveLetter">Drive letter to use</param>
/// <param name="filename">Filename to use</param>
/// <param name="driveSpeed">Drive speed to use</param>
/// <param name="paranoid">Enable paranoid mode (safer dumping)</param>
/// <param name="retryCount">User-defined reread count</param>
protected override void SetDefaultParameters(
KnownSystem? system,
MediaType? type,
char driveLetter,
string filename,
int? driveSpeed,
bool paranoid,
int retryCount)
{
BaseCommand = Command.NONE;
this[Flag.InputFile] = true;
InputFileValue = $"\\\\?\\{driveLetter}:";
this[Flag.OutputFile] = true;
OutputFileValue = filename;
// TODO: Add more common block sizes
this[Flag.BlockSize] = true;
switch (type)
{
case MediaType.FloppyDisk:
BlockSizeValue = 1440 * 1024;
break;
default:
BlockSizeValue = 1024 * 1024 * 1024;
break;
}
this[Flag.Progress] = true;
this[Flag.Size] = true;
}
/// <summary>
/// Scan a possible parameter string and populate whatever possible
/// </summary>
/// <param name="parameters">String possibly representing parameters</param>
/// <returns></returns>
protected override bool ValidateAndSetParameters(string parameters)
{
// 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();
// Determine what the commandline should look like given the first item
int start = 0;
BaseCommand = Converters.StringToCommand(parts[0]);
if (BaseCommand != Command.NONE)
start = 1;
// Loop through all auxilary flags, if necessary
int i = 0;
for (i = start; i < parts.Count; i++)
{
// Flag read-out values
long? longValue = null;
string stringValue = null;
// Keep a count of keys to determine if we should break out to filename handling or not
int keyCount = Keys.Count();
#region Boolean flags
// Progress
ProcessBooleanParameter(parts, FlagStrings.Progress, Flag.Progress, ref i);
// Size
ProcessBooleanParameter(parts, FlagStrings.Size, Flag.Size, ref i);
#endregion
#region Int64 flags
// Block Size
longValue = ProcessInt64Parameter(parts, FlagStrings.BlockSize, Flag.BlockSize, ref i);
if (longValue == Int64.MinValue)
return false;
else if (longValue != null)
BlockSizeValue = longValue;
// Count
longValue = ProcessInt64Parameter(parts, FlagStrings.Count, Flag.Count, ref i);
if (longValue == Int64.MinValue)
return false;
else if (longValue != null)
CountValue = longValue;
// Seek
longValue = ProcessInt64Parameter(parts, FlagStrings.Seek, Flag.Seek, ref i);
if (longValue == Int64.MinValue)
return false;
else if (longValue != null)
SeekValue = longValue;
// Skip
longValue = ProcessInt64Parameter(parts, FlagStrings.Skip, Flag.Skip, ref i);
if (longValue == Int64.MinValue)
return false;
else if (longValue != null)
SkipValue = longValue;
#endregion
#region String flags
// Filter (fixed, removable, disk, partition)
stringValue = ProcessStringParameter(parts, FlagStrings.Filter, Flag.Filter, ref i);
if (!string.IsNullOrEmpty(stringValue))
FilterValue = stringValue;
// Input File
stringValue = ProcessStringParameter(parts, FlagStrings.InputFile, Flag.InputFile, ref i);
if (string.Equals(stringValue, string.Empty))
return false;
else if (stringValue != null)
InputFileValue = stringValue;
// Output File
stringValue = ProcessStringParameter(parts, FlagStrings.OutputFile, Flag.OutputFile, ref i);
if (string.Equals(stringValue, string.Empty))
return false;
else if (stringValue != null)
OutputFileValue = stringValue;
#endregion
}
return true;
}
/// <summary>
/// Validate if all required output files exist
/// </summary>
/// <param name="basePath">Base filename and path to use for checking</param>
/// <param name="system">KnownSystem type representing the media</param>
/// <param name="type">MediaType type representing the media</param>
/// <returns></returns>
public override bool CheckAllOutputFilesExist(string basePath, KnownSystem? system, MediaType? type)
{
// TODO: Figure out what sort of output files are expected... just `.bin`?
return true;
}
/// <summary>
/// Generate a SubmissionInfo for the output files
/// </summary>
/// <param name="info">Base submission info to fill in specifics for</param>
/// <param name="basePath">Base filename and path to use for checking</param>
/// <param name="system">KnownSystem type representing the media</param>
/// <param name="type">MediaType type representing the media</param>
/// <param name="drive">Drive representing the disc to get information from</param>
/// <returns></returns>
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, KnownSystem? system, MediaType? type, Drive drive)
{
// TODO: Implement getting submission info, if possible
}
/// <summary>
/// Get the list of commands that use a given flag
/// </summary>
/// <param name="flag">Flag value to get commands for</param>
/// <returns>List of Commands, if possible</returns>
private List<Command> GetSupportedCommands(Flag flag)
{
var commands = new List<Command>();
switch (flag)
{
#region Boolean flags
case Flag.Progress:
commands.Add(Command.NONE);
break;
case Flag.Size:
commands.Add(Command.NONE);
break;
#endregion
#region Int64 flags
case Flag.BlockSize:
commands.Add(Command.NONE);
break;
case Flag.Count:
commands.Add(Command.NONE);
break;
case Flag.Seek:
commands.Add(Command.NONE);
break;
case Flag.Skip:
commands.Add(Command.NONE);
break;
#endregion
#region String flags
case Flag.Filter:
commands.Add(Command.NONE);
break;
case Flag.InputFile:
commands.Add(Command.NONE);
break;
case Flag.OutputFile:
commands.Add(Command.NONE);
break;
#endregion
case Flag.NONE:
default:
return commands;
}
return commands;
}
/// <summary>
/// Process a boolean parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="flagString">Flag string to check</param>
/// <param name="flag">Flag value corresponding to the flag</param>
/// <param name="i">Reference to the position in the parts</param>
/// <returns>True if the parameter was processed successfully or skipped, false otherwise</returns>
private bool ProcessBooleanParameter(List<string> parts, string flagString, Flag flag, ref int i)
{
if (parts == null)
return false;
if (parts[i] == flagString)
{
if (!GetSupportedCommands(flag).Contains(BaseCommand))
return false;
this[flag] = true;
}
return true;
}
/// <summary>
/// Process an Int64 parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="flagString">Flag string to check</param>
/// <param name="flag">Flag value corresponding to the flag</param>
/// <param name="i">Reference to the position in the parts</param>
/// <returns>Int64 value if success, Int64.MinValue if skipped, null on error/returns>
private long? ProcessInt64Parameter(List<string> parts, string flagString, Flag flag, ref int i)
{
if (parts == null)
return null;
if (parts[i].StartsWith(flagString))
{
if (!GetSupportedCommands(flag).Contains(BaseCommand))
return null;
string[] commandParts = parts[i].Split('=');
if (commandParts.Length != 2)
return null;
string valuePart = commandParts[1];
long factor = 1;
// Characters
if (valuePart.EndsWith("c", StringComparison.Ordinal))
{
factor = 1;
valuePart.TrimEnd('c');
}
// Words
else if (valuePart.EndsWith("w", StringComparison.Ordinal))
{
factor = 2;
valuePart.TrimEnd('w');
}
// Double Words
else if (valuePart.EndsWith("d", StringComparison.Ordinal))
{
factor = 4;
valuePart.TrimEnd('d');
}
// Quad Words
else if (valuePart.EndsWith("q", StringComparison.Ordinal))
{
factor = 8;
valuePart.TrimEnd('q');
}
// Kilobytes
else if (valuePart.EndsWith("k", StringComparison.Ordinal))
{
factor = 1024;
valuePart.TrimEnd('k');
}
// Megabytes
else if (valuePart.EndsWith("M", StringComparison.Ordinal))
{
factor = 1024 * 1024;
valuePart.TrimEnd('M');
}
// Gigabytes
else if (valuePart.EndsWith("G", StringComparison.Ordinal))
{
factor = 1024 * 1024 * 1024;
valuePart.TrimEnd('G');
}
if (!IsValidInt64(valuePart))
return null;
this[flag] = true;
return long.Parse(valuePart) * factor;
}
return Int64.MinValue;
}
/// <summary>
/// Process a string parameter
/// </summary>
/// <param name="parts">List of parts to be referenced</param>
/// <param name="flagString">Flag string to check</param>
/// <param name="flag">Flag value corresponding to the flag</param>
/// <param name="i">Reference to the position in the parts</param>
/// <returns>String value if possible, string.Empty on missing, null on error</returns>
private string ProcessStringParameter(List<string> parts, string flagString, Flag flag, ref int i)
{
if (parts == null)
return null;
if (parts[i] == flagString)
{
if (!GetSupportedCommands(flag).Contains(BaseCommand))
return null;
string[] commandParts = parts[i].Split('=');
if (commandParts.Length != 2)
return null;
string valuePart = commandParts[1];
this[flag] = true;
return valuePart.Trim('"');
}
return string.Empty;
}
}
}

View File

@@ -6,11 +6,11 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)'!='netcoreapp2.1' AND '$(TargetFramework)'!='netcoreapp3.1'">
<PropertyGroup Condition="'$(TargetFramework)'!='netcoreapp3.1'">
<DefineConstants>NET_FRAMEWORK</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)'!='netcoreapp2.1' AND '$(TargetFramework)'!='netcoreapp3.1'">
<ItemGroup Condition="'$(TargetFramework)'!='netcoreapp3.1'">
<COMReference Include="IMAPI2">
<Guid>{2735412F-7F64-5B0F-8F00-5D77AFBE261E}</Guid>
<VersionMajor>1</VersionMajor>

View File

@@ -1,5 +1,10 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using DICUI.Utilities;
namespace DICUI.Data
{
@@ -8,13 +13,18 @@ namespace DICUI.Data
/// <summary>
/// Path to the executable
/// </summary>
public string Path { get; set; }
public string ExecutablePath { get; set; }
/// <summary>
/// Program that this set of parameters represents
/// </summary>
public InternalProgram InternalProgram { get; set; }
/// <summary>
/// Process to track external program
/// </summary>
private Process process;
/// <summary>
/// Populate a Parameters object from a param string
/// </summary>
@@ -126,6 +136,94 @@ namespace DICUI.Data
/// <returns></returns>
protected abstract bool ValidateAndSetParameters(string parameters);
/// <summary>
/// Validate if all required output files exist
/// </summary>
/// <param name="basePath">Base filename and path to use for checking</param>
/// <param name="system">KnownSystem type representing the media</param>
/// <param name="type">MediaType type representing the media</param>
/// <returns></returns>
public abstract bool CheckAllOutputFilesExist(string basePath, KnownSystem? system, MediaType? type);
/// <summary>
/// Generate a SubmissionInfo for the output files
/// </summary>
/// <param name="submissionInfo">Base submission info to fill in specifics for</param>
/// <param name="basePath">Base filename and path to use for checking</param>
/// <param name="system">KnownSystem type representing the media</param>
/// <param name="type">MediaType type representing the media</param>
/// <param name="drive">Drive representing the disc to get information from</param>
public abstract void GenerateSubmissionInfo(SubmissionInfo submissionInfo, string basePath, KnownSystem? system, MediaType? type, Drive drive);
/// <summary>
/// Run internal program
/// </summary>
public void ExecuteInternalProgram()
{
process = new Process()
{
StartInfo = new ProcessStartInfo()
{
FileName = ExecutablePath,
Arguments = GenerateParameters() ?? "",
},
};
process.Start();
process.WaitForExit();
}
/// <summary>
/// Run internal program async with an input set of parameters
/// </summary>
/// <param name="parameters"></param>
/// <returns>Standard output from commandline window</returns>
public async Task<string> ExecuteInternalProgram(BaseParameters parameters)
{
Process childProcess;
string output = await Task.Run(() =>
{
childProcess = new Process()
{
StartInfo = new ProcessStartInfo()
{
FileName = parameters.ExecutablePath,
Arguments = parameters.GenerateParameters(),
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
},
};
childProcess.Start();
childProcess.WaitForExit(1000);
// Just in case, we want to push a button 5 times to clear any errors
for (int i = 0; i < 5; i++)
childProcess.StandardInput.WriteLine("Y");
string stdout = childProcess.StandardOutput.ReadToEnd();
childProcess.Dispose();
return stdout;
});
return output;
}
/// <summary>
/// Cancel an in-progress dumping process
/// </summary>
public void KillInternalProgram()
{
try
{
if (process != null && !process.HasExited)
process.Kill();
}
catch
{ }
}
/// <summary>
/// Returns whether or not the selected item exists
/// </summary>
@@ -140,6 +238,35 @@ namespace DICUI.Data
return true;
}
/// <summary>
/// Get the full lines from the input file, if possible
/// </summary>
/// <param name="filename">file location</param>
/// <param name="binary">True if should read as binary, false otherwise (default)</param>
/// <returns>Full text of the file, null on error</returns>
protected string GetFullFile(string filename, bool binary = false)
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(filename))
return null;
// If we're reading as binary
if (binary)
{
string hex = string.Empty;
using (BinaryReader br = new BinaryReader(File.OpenRead(filename)))
{
while (br.BaseStream.Position < br.BaseStream.Length)
{
hex += Convert.ToString(br.ReadByte(), 16);
}
}
return hex;
}
return string.Join("\n", File.ReadAllLines(filename));
}
/// <summary>
/// Returns whether a string is a flag (starts with '/')
/// </summary>

View File

@@ -1,4 +1,6 @@
namespace DICUI.Data
using System;
namespace DICUI.Data
{
/// <summary>
/// Category for Redump
@@ -47,9 +49,13 @@
{
NONE = 0,
DiscImageCreator,
// Dumping support
Aaru,
DD, // TODO: Currently unimplemented
DD,
DiscImageCreator, // Includes UmdImageCreator
// Verification support only
CleanRip,
}
/// <summary>
@@ -385,8 +391,9 @@
}
/// <summary>
/// Media types according to https://docs.microsoft.com/en-us/previous-versions/windows/desktop/cimwin32a/win32-physicalmedia
/// Physical media types
/// </summary>
/// <see cref="https://docs.microsoft.com/en-us/previous-versions/windows/desktop/cimwin32a/win32-physicalmedia"/>
public enum PhysicalMediaType : ushort
{
Unknown = 0,
@@ -620,4 +627,97 @@
No = 1,
Yes = 2,
}
#region Win32_CDROMDrive
// https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-cdromdrive
/// <summary>
/// Availability and status of the device
/// </summary>
public enum Availability : ushort
{
Other = 1,
Unknown = 2,
RunningFullPower = 3,
Warning = 4,
InTest = 5,
NotApplicable = 6,
PowerOff = 7,
OffLine = 8,
OffDuty = 9,
Degraded = 10,
NotInstalled = 11,
InstallError = 12,
PowerSaveUnknown = 13,
PowerSaveLowPowerMode = 14,
PowerSaveStandby = 15,
PowerCycle = 16,
PowerSaveWarning = 17,
Paused = 18,
NotReady = 19,
NotConfigured = 20,
Quiesced = 21,
}
/// <summary>
/// Optical drive capabilities
/// </summary>
public enum Capabilities : ushort
{
Unknown = 0,
Other = 1,
SequentialAccess = 2,
RandomAccess = 3,
SupportsWriting = 4,
Encryption = 5,
Compression = 6,
SupportsRemoveableMedia = 7,
ManualCleaning = 8,
AutomaticCleaning = 9,
SMARTNotification = 10,
SupportsDualSidedMedia = 11,
PredismountEjectNotRequired = 12,
}
/// <summary>
/// File system flags
/// </summary>
[Flags]
public enum FileSystemFlags : uint
{
None = 0,
CaseSensitiveSearch = 1,
CasePreservedNames = 2,
UnicodeOnDisk = 4,
PersistentACLs = 8,
FileCompression = 16,
VolumeQuotas = 32,
SupportsSparseFiles = 64,
SupportsReparsePoints = 128,
SupportsRemoteStorage = 256,
SupportsLongNames = 16384,
VolumeIsCompressed = 32768,
ReadOnlyVolume = 524289, // TODO: Invesitgate, as this value seems wrong
SupportsObjectIDS = 65536,
SupportsEncryption = 131072,
SupportsNamedStreams = 262144,
}
/// <summary>
/// Specific power-related capabilities of a logical device
/// </summary>
public enum PowerManagementCapabilities : ushort
{
Unknown = 0,
NotSupported = 1,
Disabled = 2,
Enabled = 3,
PowerSavingModesEnteredAutomatically = 4,
PowerStateSettable = 5,
PowerCyclingSupported = 6,
TimedPowerOnSupported = 7,
}
#endregion
}

View File

@@ -0,0 +1,286 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace DICUI.Data
{
public class Options : IDictionary<string, string>
{
private Dictionary<string, string> _settings;
#region Internal Program
public string AaruPath
{
get { return GetStringSetting(_settings, "AaruPath", "Programs\\Aaru\\Aaru.exe"); }
set { _settings["AaruPath"] = value; }
}
public string CreatorPath
{
get { return GetStringSetting(_settings, "CreatorPath", "Programs\\Creator\\DiscImageCreator.exe"); }
set { _settings["CreatorPath"] = value; }
}
public string DDPath
{
get { return GetStringSetting(_settings, "DDPath", "Programs\\DD\\dd.exe"); }
set { _settings["DDPath"] = value; }
}
public string InternalProgram
{
get { return GetStringSetting(_settings, "InternalProgram", Data.InternalProgram.DiscImageCreator.ToString()); }
set { _settings["InternalProgram"] = value; }
}
#endregion
#region Extra Paths
public string DefaultOutputPath
{
get { return GetStringSetting(_settings, "DefaultOutputPath", "ISO"); }
set { _settings["DefaultOutputPath"] = value; }
}
public string SubDumpPath
{
get { return GetStringSetting(_settings, "SubDumpPath", "Programs\\Subdump\\subdump.exe"); }
set { _settings["SubDumpPath"] = value; }
}
#endregion
#region Dumping Speeds
public int PreferredDumpSpeedCD
{
get { return GetInt32Setting(_settings, "PreferredDumpSpeedCD", 72); }
set { _settings["PreferredDumpSpeedCD"] = value.ToString(); }
}
public int PreferredDumpSpeedDVD
{
get { return GetInt32Setting(_settings, "PreferredDumpSpeedDVD", 24); }
set { _settings["PreferredDumpSpeedDVD"] = value.ToString(); }
}
public int PreferredDumpSpeedBD
{
get { return GetInt32Setting(_settings, "PreferredDumpSpeedBD", 16); }
set { _settings["PreferredDumpSpeedBD"] = value.ToString(); }
}
#endregion
#region Extra Dumping Options
public bool QuietMode
{
get { return GetBooleanSetting(_settings, "QuietMode", false); }
set { _settings["QuietMode"] = value.ToString(); }
}
public bool ParanoidMode
{
get { return GetBooleanSetting(_settings, "ParanoidMode", false); }
set { _settings["ParanoidMode"] = value.ToString(); }
}
public bool ScanForProtection
{
get { return GetBooleanSetting(_settings, "ScanForProtection", true); }
set { _settings["ScanForProtection"] = value.ToString(); }
}
public int RereadAmountForC2
{
get { return GetInt32Setting(_settings, "RereadAmountForC2", 20); }
set { _settings["RereadAmountForC2"] = value.ToString(); }
}
public bool AddPlaceholders
{
get { return GetBooleanSetting(_settings, "AddPlaceholders", true); }
set { _settings["AddPlaceholders"] = value.ToString(); }
}
public bool PromptForDiscInformation
{
get { return GetBooleanSetting(_settings, "PromptForDiscInformation", true); }
set { _settings["PromptForDiscInformation"] = value.ToString(); }
}
public bool IgnoreFixedDrives
{
get { return GetBooleanSetting(_settings, "IgnoreFixedDrives", false); }
set { _settings["IgnoreFixedDrives"] = value.ToString(); }
}
public bool ResetDriveAfterDump
{
get { return GetBooleanSetting(_settings, "ResetDriveAfterDump", false); }
set { _settings["ResetDriveAfterDump"] = value.ToString(); }
}
#endregion
#region Skip Options
public bool SkipMediaTypeDetection
{
get { return GetBooleanSetting(_settings, "SkipMediaTypeDetection", false); }
set { _settings["SkipMediaTypeDetection"] = value.ToString(); }
}
public bool SkipSystemDetection
{
get { return GetBooleanSetting(_settings, "SkipSystemDetection", false); }
set { _settings["SkipSystemDetection"] = value.ToString(); }
}
#endregion
#region Logging Options
public bool VerboseLogging
{
get { return GetBooleanSetting(_settings, "VerboseLogging", true); }
set { _settings["VerboseLogging"] = value.ToString(); }
}
public bool OpenLogWindowAtStartup
{
get { return GetBooleanSetting(_settings, "OpenLogWindowAtStartup", true); }
set { _settings["OpenLogWindowAtStartup"] = value.ToString(); }
}
#endregion
#region Redump Login Information
public string Username
{
get { return GetStringSetting(_settings, "Username", ""); }
set { _settings["Username"] = value; }
}
// TODO: Figure out a way to keep this encrypted in some way, BASE64 to start?
public string Password
{
get { return GetStringSetting(_settings, "Password", ""); }
set { _settings["Password"] = value; }
}
#endregion
/// <summary>
/// Constructor taking a dictionary for settings
/// </summary>
/// <param name="settings"></param>
public Options(Dictionary<string, string> settings = null)
{
this._settings = settings ?? new Dictionary<string, string>();
}
/// <summary>
/// Get a Boolean setting from a settings, dictionary
/// </summary>
/// <param name="settings">Dictionary representing the settings</param>
/// <param name="key">Setting key to get a value for</param>
/// <param name="defaultValue">Default value to return if no value is found</param>
/// <returns>Setting value if possible, default value otherwise</returns>
private bool GetBooleanSetting(Dictionary<string, string> settings, string key, bool defaultValue)
{
if (settings.ContainsKey(key))
{
if (Boolean.TryParse(settings[key], out bool value))
return value;
else
return defaultValue;
}
else
{
return defaultValue;
}
}
/// <summary>
/// Get an Int32 setting from a settings, dictionary
/// </summary>
/// <param name="settings">Dictionary representing the settings</param>
/// <param name="key">Setting key to get a value for</param>
/// <param name="defaultValue">Default value to return if no value is found</param>
/// <returns>Setting value if possible, default value otherwise</returns>
private int GetInt32Setting(Dictionary<string, string> settings, string key, int defaultValue)
{
if (settings.ContainsKey(key))
{
if (Int32.TryParse(settings[key], out int value))
return value;
else
return defaultValue;
}
else
{
return defaultValue;
}
}
/// <summary>
/// Get a String setting from a settings, dictionary
/// </summary>
/// <param name="settings">Dictionary representing the settings</param>
/// <param name="key">Setting key to get a value for</param>
/// <param name="defaultValue">Default value to return if no value is found</param>
/// <returns>Setting value if possible, default value otherwise</returns>
private string GetStringSetting(Dictionary<string, string> settings, string key, string defaultValue)
{
if (settings.ContainsKey(key))
return settings[key];
else
return defaultValue;
}
#region IDictionary implementations
public ICollection<string> Keys => _settings.Keys;
public ICollection<string> Values => _settings.Values;
public int Count => _settings.Count;
public bool IsReadOnly => ((IDictionary<string, string>)_settings).IsReadOnly;
public string this[string key]
{
get { return (_settings.ContainsKey(key) ? _settings[key] : null); }
set { _settings[key] = value; }
}
public bool ContainsKey(string key) => _settings.ContainsKey(key);
public void Add(string key, string value) => _settings.Add(key, value);
public bool Remove(string key) => _settings.Remove(key);
public bool TryGetValue(string key, out string value) => _settings.TryGetValue(key, out value);
public void Add(KeyValuePair<string, string> item) => _settings.Add(item.Key, item.Value);
public void Clear() => _settings.Clear();
public bool Contains(KeyValuePair<string, string> item) => ((IDictionary<string, string>)_settings).Contains(item);
public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex) => ((IDictionary<string, string>)_settings).CopyTo(array, arrayIndex);
public bool Remove(KeyValuePair<string, string> item) => ((IDictionary<string, string>)_settings).Remove(item);
public IEnumerator<KeyValuePair<string, string>> GetEnumerator() => _settings.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _settings.GetEnumerator();
#endregion
}
}

View File

@@ -249,12 +249,12 @@ namespace DICUI.Data
/// </summary>
public class CommonDiscInfoSection
{
// TODO: Name not defined
// Name not defined by Redump
[JsonProperty(PropertyName = "d_system", Required = Required.AllowNull)]
[JsonConverter(typeof(KnownSystemConverter))]
public KnownSystem? System { get; set; }
// TODO: Name not defined
// Name not defined by Redump
// TODO: Have this convert to a new `RedumpMedia?` if possible, for submission
[JsonProperty(PropertyName = "d_media", Required = Required.AllowNull)]
[JsonConverter(typeof(MediaTypeConverter))]

View File

@@ -1,8 +1,4 @@
using System;
using System.IO;
using DICUI.Data;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace DICUI.DiscImageCreator
{

File diff suppressed because it is too large Load Diff

View File

@@ -32,6 +32,6 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.16")]
[assembly: AssemblyFileVersion("1.16.0.0")]
[assembly: AssemblyVersion("1.16.1")]
[assembly: AssemblyFileVersion("1.16.1.0")]
[assembly: InternalsVisibleTo("DICUI.Test")]

View File

@@ -475,6 +475,39 @@ namespace DICUI.Utilities
}
}
/// <summary>
/// Get the string representation of the InternalProgram enum values
/// </summary>
/// <param name="prog">InternalProgram value to convert</param>
/// <returns>String representing the value, if possible</returns>
public static string LongName(this InternalProgram? prog)
{
switch (prog)
{
#region Dumping support
case InternalProgram.Aaru:
return "Aaru";
case InternalProgram.DD:
return "dd";
case InternalProgram.DiscImageCreator:
return "DiscImageCreator";
#endregion
#region Verification support only
case InternalProgram.CleanRip:
return "CleanRip";
#endregion
case InternalProgram.NONE:
default:
return "Unknown";
}
}
/// <summary>
/// Get the string representation of the KnownSystem enum values
/// </summary>
@@ -2083,6 +2116,7 @@ namespace DICUI.Utilities
{
switch (internalProgram.ToLowerInvariant())
{
// Dumping support
case "aaru":
case "chef":
case "dichef":
@@ -2092,9 +2126,18 @@ namespace DICUI.Utilities
case "dic":
case "dicreator":
case "discimagecreator":
case "umd":
case "umdcreator":
case "umdimagecreator":
return InternalProgram.DiscImageCreator;
case "dd":
return InternalProgram.DD;
// Verification support only
case "cleanrip":
case "cr":
return InternalProgram.CleanRip;
default:
return InternalProgram.NONE;
}

File diff suppressed because it is too large Load Diff

View File

@@ -778,7 +778,7 @@ namespace DICUI.Utilities
// Get the DeviceID and MediaType from the current drive letter
string deviceId = null;
ushort mediaType = 0;
int mediaType = 0;
try
{
// Get the device ID first
@@ -789,6 +789,36 @@ namespace DICUI.Utilities
foreach (ManagementObject queryObj in searcher.Get())
{
deviceId = (string)queryObj["DeviceID"];
#region Possibly useful fields
foreach (var property in queryObj.Properties)
{
Console.WriteLine(property);
}
// Capabilities list
ushort[] capabilities = (ushort[])queryObj["Capabilities"];
// Internal name of the device
string caption = (string)queryObj["Caption"];
// Flags for the file system, see FileSystemFlags
uint fileSystemFlagsEx = (uint)queryObj["FileSystemFlagsEx"];
// "CD Writer" doesn't fit https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-cdromdrive
string mediaTypeString = (string)queryObj["MediaType"];
// Internal name of the device (Seems like a duplicate of Caption)
string name = (string)queryObj["Name"];
// Full device ID for the drive (Seems like duplicate of DeviceID)
string pnpDeviceId = (string)queryObj["PNPDeviceId"];
// Size of the loaded media (extrapolate disc type from this?)
ulong size = (ulong)queryObj["Size"];
#endregion
}
// If we got no valid device, we don't care and just return
@@ -820,16 +850,23 @@ namespace DICUI.Utilities
return null;
#else
// TODO: This entire .NET Core path still doesn't work
// This may honestly require an entire import of IMAPI2 stuff and then try
// as best as possible to get it working.
// Now try to get the physical media associated
searcher = new ManagementObjectSearcher(
"root\\CIMV2",
$"SELECT * FROM Win32_PhysicalMedia");
//$"SELECT * FROM Win32_PhysicalMedia WHERE Name = '{deviceId}'");
foreach (ManagementObject queryObj in searcher.Get())
{
deviceId = (string)queryObj["Tag"];
mediaType = (ushort)queryObj["MediaType"];
foreach (var property in queryObj.Properties)
{
Console.WriteLine(property);
}
mediaType = (int)(queryObj["MediaType"] ?? 0);
}
return ((PhysicalMediaType)mediaType).ToMediaType();
@@ -967,6 +1004,7 @@ namespace DICUI.Utilities
/// <returns>Copy protection detected in the envirionment, if any</returns>
public static async Task<string> RunProtectionScanOnPath(string path)
{
#if NET_FRAMEWORK
try
{
var found = await Task.Run(() =>
@@ -984,6 +1022,9 @@ namespace DICUI.Utilities
{
return $"Path could not be scanned! {ex}";
}
#else
return "Copy protection scanning is not available on .NET Core builds";
#endif
}
}
}

View File

@@ -16,14 +16,12 @@ namespace DICUI.Test
[InlineData("stop D", 'D', false, MediaType.DVD, true)]
public void ParametersValidTest(string parameters, char letter, bool isFloppy, MediaType? mediaType, bool expected)
{
var env = new DumpEnvironment
{
Parameters = new DiscImageCreator.Parameters(parameters),
Drive = isFloppy
? new Drive(InternalDriveType.Floppy, new DriveInfo(letter.ToString()))
: new Drive(InternalDriveType.Optical, new DriveInfo(letter.ToString())),
Type = mediaType,
};
var options = new Options() { InternalProgram = "dic" };
var drive = isFloppy
? new Drive(InternalDriveType.Floppy, new DriveInfo(letter.ToString()))
: new Drive(InternalDriveType.Optical, new DriveInfo(letter.ToString()));
var env = new DumpEnvironment(options, string.Empty, string.Empty, drive, KnownSystem.IBMPCCompatible, mediaType, parameters);
bool actual = env.ParametersValid();
Assert.Equal(expected, actual);
@@ -40,11 +38,8 @@ namespace DICUI.Test
[InlineData("superhero", "blah&foo.bin", "superhero", "blah&foo.bin")]
public void FixOutputPathsTest(string outputDirectory, string outputFilename, string expectedOutputDirectory, string expectedOutputFilename)
{
var env = new DumpEnvironment
{
OutputDirectory = outputDirectory,
OutputFilename = outputFilename,
};
var options = new Options() { InternalProgram = "dic" };
var env = new DumpEnvironment(options, outputDirectory, outputFilename, null, KnownSystem.IBMPCCompatible, MediaType.CDROM, string.Empty);
env.FixOutputPaths();
Assert.Equal(expectedOutputDirectory, env.OutputDirectory);

View File

@@ -3,6 +3,7 @@
<appSettings>
<add key="AaruPath" value="Programs\Aaru\Aaru.exe"/>
<add key="CreatorPath" value="Programs\Creator\DiscImageCreator.exe"/>
<add key="DDPath" value="Programs\DD\dd.exe"/>
<add key="SubDumpPath" value="Programs\Subdump\subdump.exe"/>
<add key="DefaultOutputPath" value="ISO"/>
<add key="InternalProgram" value="DiscImageCreator"/>

View File

@@ -1,208 +0,0 @@
using System;
using System.Configuration;
using System.Linq;
using System.Reflection;
using DICUI.Data;
namespace DICUI
{
public class Options
{
public string DefaultOutputPath { get; private set; }
public string AaruPath { get; private set; }
public string CreatorPath { get; private set; }
public string SubDumpPath { get; private set; }
public string InternalProgram { get; set; }
public int PreferredDumpSpeedCD { get; set; }
public int PreferredDumpSpeedDVD { get; set; }
public int PreferredDumpSpeedBD { get; set; }
public bool QuietMode { get; set; }
public bool ParanoidMode { get; set; }
public bool ScanForProtection { get; set; }
public int RereadAmountForC2 { get; set; }
public bool AddPlaceholders { get; set; }
public bool PromptForDiscInformation { get; set; }
public bool IgnoreFixedDrives { get; set; }
public bool ResetDriveAfterDump { get; set; }
public bool SkipMediaTypeDetection { get; set; }
public bool SkipSystemDetection { get; set; }
public bool VerboseLogging { get; set; }
public bool OpenLogWindowAtStartup { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public void Save()
{
Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
//TODO: reflection is used
//TODO: is remove needed, doesn't the value get directly overridden
Array.ForEach(
GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance),
p => {
configFile.AppSettings.Settings.Remove(p.Name);
configFile.AppSettings.Settings.Add(p.Name, Convert.ToString(p.GetValue(this)));
}
);
configFile.Save(ConfigurationSaveMode.Modified);
}
public void Load()
{
Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
//TODO: hardcoded, we should find a better way
this.AaruPath = GetStringSetting(configFile, "AaruPath", "Programs\\Aaru\\Aaru.exe");
this.CreatorPath = GetStringSetting(configFile, "CreatorPath", "Programs\\Creator\\DiscImageCreator.exe");
this.SubDumpPath = GetStringSetting(configFile, "SubDumpPath", "Programs\\Subdump\\subdump.exe");
this.DefaultOutputPath = GetStringSetting(configFile, "DefaultOutputPath", "ISO");
this.InternalProgram = GetStringSetting(configFile, "InternalProgram", Data.InternalProgram.DiscImageCreator.ToString());
this.PreferredDumpSpeedCD = GetInt32Setting(configFile, "PreferredDumpSpeedCD", 72);
this.PreferredDumpSpeedDVD = GetInt32Setting(configFile, "PreferredDumpSpeedDVD", 24);
this.PreferredDumpSpeedBD = GetInt32Setting(configFile, "PreferredDumpSpeedBD", 16);
this.QuietMode = GetBooleanSetting(configFile, "QuietMode", false);
this.ParanoidMode = GetBooleanSetting(configFile, "ParanoidMode", false);
this.ScanForProtection = GetBooleanSetting(configFile, "ScanForProtection", true);
this.SkipMediaTypeDetection = GetBooleanSetting(configFile, "SkipMediaTypeDetection", false);
this.SkipSystemDetection = GetBooleanSetting(configFile, "SkipSystemDetection", false);
this.RereadAmountForC2 = GetInt32Setting(configFile, "RereadAmountForC2", 20);
this.VerboseLogging = GetBooleanSetting(configFile, "VerboseLogging", true);
this.OpenLogWindowAtStartup = GetBooleanSetting(configFile, "OpenLogWindowAtStartup", true);
this.AddPlaceholders = GetBooleanSetting(configFile, "AddPlaceholders", true);
this.PromptForDiscInformation = GetBooleanSetting(configFile, "PromptForDiscInformation", true);
this.IgnoreFixedDrives = GetBooleanSetting(configFile, "IgnoreFixedDrives", false);
this.ResetDriveAfterDump = GetBooleanSetting(configFile, "ResetDriveAfterDump", false);
this.Username = GetStringSetting(configFile, "Username", "");
this.Password = GetStringSetting(configFile, "Password", "");
}
/// <summary>
/// Get a boolean setting from a configuration
/// </summary>
/// <param name="configFile">Current configuration file</param>
/// <param name="key">Setting key to get a value for</param>
/// <param name="defaultValue">Default value to return if no value is found</param>
/// <returns>Setting value if possible, default value otherwise</returns>
public bool GetBooleanSetting(Configuration configFile, string key, bool defaultValue)
{
var settings = configFile.AppSettings.Settings;
if (settings.AllKeys.Contains(key))
{
if (Boolean.TryParse(settings[key].Value, out bool value))
return value;
else
return defaultValue;
}
else
{
return defaultValue;
}
}
/// <summary>
/// Get a boolean setting from a configuration
/// </summary>
/// <param name="configFile">Current configuration file</param>
/// <param name="key">Setting key to get a value for</param>
/// <param name="defaultValue">Default value to return if no value is found</param>
/// <returns>Setting value if possible, default value otherwise</returns>
public int GetInt32Setting(Configuration configFile, string key, int defaultValue)
{
var settings = configFile.AppSettings.Settings;
if (settings.AllKeys.Contains(key))
{
if (Int32.TryParse(settings[key].Value, out int value))
return value;
else
return defaultValue;
}
else
{
return defaultValue;
}
}
/// <summary>
/// Get a boolean setting from a configuration
/// </summary>
/// <param name="configFile">Current configuration file</param>
/// <param name="key">Setting key to get a value for</param>
/// <param name="defaultValue">Default value to return if no value is found</param>
/// <returns>Setting value if possible, default value otherwise</returns>
public long GetInt64Setting(Configuration configFile, string key, long defaultValue)
{
var settings = configFile.AppSettings.Settings;
if (settings.AllKeys.Contains(key))
{
if (Int64.TryParse(settings[key].Value, out long value))
return value;
else
return defaultValue;
}
else
{
return defaultValue;
}
}
/// <summary>
/// Get a boolean setting from a configuration
/// </summary>
/// <param name="configFile">Current configuration file</param>
/// <param name="key">Setting key to get a value for</param>
/// <param name="defaultValue">Default value to return if no value is found</param>
/// <returns>Setting value if possible, default value otherwise</returns>
public string GetStringSetting(Configuration configFile, string key, string defaultValue)
{
var settings = configFile.AppSettings.Settings;
if (settings.AllKeys.Contains(key))
return settings[key].Value;
else
return defaultValue;
}
//TODO: probably should be generic for non-string options
//TODO: using reflection for Set and Get is orthodox but it works, should be changed to a key,value map probably
public void Set(string key, string value)
{
GetType().GetProperty(key, BindingFlags.Public | BindingFlags.Instance).SetValue(this, value);
}
public string Get(string key)
{
return GetType().GetProperty(key, BindingFlags.Public | BindingFlags.Instance).GetValue(this) as string;
}
public int GetPreferredDumpSpeedForMediaType(MediaType? type)
{
switch (type)
{
case MediaType.CDROM:
case MediaType.GDROM:
return PreferredDumpSpeedCD;
case MediaType.DVD:
case MediaType.HDDVD:
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
return PreferredDumpSpeedDVD;
case MediaType.BluRay:
return PreferredDumpSpeedBD;
default:
return 8;
}
}
}
}

View File

@@ -51,8 +51,8 @@ using System.Windows;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.16")]
[assembly: AssemblyFileVersion("1.16.0.0")]
[assembly: AssemblyVersion("1.16.1")]
[assembly: AssemblyFileVersion("1.16.1.0")]
// Anything marked as internal can be used by the test methods
[assembly: InternalsVisibleTo("DICUI.Test")]

122
DICUI/UIOptions.cs Normal file
View File

@@ -0,0 +1,122 @@
using System.Collections.Generic;
using System.Configuration;
using DICUI.Data;
namespace DICUI
{
public class UIOptions
{
// TODO: Is there any way that this can be made private?
public Options Options { get; set; }
#region Passthrough readonly values
// TODO: Can any of these be removed?
public string DefaultOutputPath { get { return Options.DefaultOutputPath; } }
public bool IgnoreFixedDrives { get { return Options.IgnoreFixedDrives; } }
public bool ResetDriveAfterDump { get { return Options.ResetDriveAfterDump; } }
public bool SkipMediaTypeDetection { get { return Options.SkipMediaTypeDetection; } }
public bool SkipSystemDetection { get { return Options.SkipSystemDetection; } }
public bool OpenLogWindowAtStartup { get { return Options.OpenLogWindowAtStartup; } }
#endregion
/// <summary>
/// Default constructor
/// </summary>
public UIOptions()
{
Load();
}
/// <summary>
/// Save a configuration from internal Options
/// </summary>
public void Save()
{
Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
// Loop through all settings in Options and save them, overwriting existing settings
foreach (var kvp in Options)
{
configFile.AppSettings.Settings.Remove(kvp.Key);
configFile.AppSettings.Settings.Add(kvp.Key, kvp.Value);
}
configFile.Save(ConfigurationSaveMode.Modified);
}
/// <summary>
/// Load a configuration into internal Options
/// </summary>
private void Load()
{
Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var settings = ConvertToDictionary(configFile);
Options = new Options(settings);
}
/// <summary>
/// Get a setting value from the base Options
/// </summary>
/// <param name="key">Key to retrieve the value for</param>
/// <returns>String value if possible, null otherwise</returns>
public string Get(string key)
{
return Options[key];
}
/// <summary>
/// Set a setting value in the base Options
/// </summary>
/// <param name="key">Key to set the value for</param>
/// <param name="value">Value to set</param>
public void Set(string key, string value)
{
Options[key] = value;
}
/// <summary>
/// Get the preferred dumping speed given a media type
/// </summary>
/// <param name="type">MediaType representing the current selection</param>
/// <returns>Int value representing the dump speed</returns>
public int GetPreferredDumpSpeedForMediaType(MediaType? type)
{
switch (type)
{
case MediaType.CDROM:
case MediaType.GDROM:
return this.Options.PreferredDumpSpeedCD;
case MediaType.DVD:
case MediaType.HDDVD:
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
return this.Options.PreferredDumpSpeedDVD;
case MediaType.BluRay:
return this.Options.PreferredDumpSpeedBD;
default:
return this.Options.PreferredDumpSpeedCD;
}
}
/// <summary>
/// Convert the configuration app settings to a dictionary
/// </summary>
/// <param name="configFile">Configuration to load from</param>
/// <returns>Dictionary with all values from app settings</returns>
private Dictionary<string, string> ConvertToDictionary(Configuration configFile)
{
var settings = configFile.AppSettings.Settings;
var dict = new Dictionary<string, string>();
foreach (string key in settings.AllKeys)
{
dict[key] = settings[key]?.Value ?? string.Empty;
}
return dict;
}
}
}

View File

@@ -6,113 +6,189 @@ namespace DICUI
{
public class OptionsViewModel
{
private Options _options;
private UIOptions _uiOptions;
public OptionsViewModel(Options options)
#region Internal Program
public string AaruPath
{
this._options = options;
get { return _uiOptions.Options.AaruPath; }
set { _uiOptions.Options.AaruPath = value; }
}
public string CreatorPath
{
get { return _uiOptions.Options.CreatorPath; }
set { _uiOptions.Options.CreatorPath = value; }
}
public string DDPath
{
get { return _uiOptions.Options.DDPath; }
set { _uiOptions.Options.DDPath = value; }
}
public string InternalProgram
{
get { return _options.InternalProgram; }
set { _options.InternalProgram = value; }
get { return _uiOptions.Options.InternalProgram; }
set { _uiOptions.Options.InternalProgram = value; }
}
#endregion
#region Extra Paths
public string DefaultOutputPath
{
get { return _uiOptions.Options.DefaultOutputPath; }
set { _uiOptions.Options.DefaultOutputPath = value; }
}
public string SubDumpPath
{
get { return _uiOptions.Options.SubDumpPath; }
set { _uiOptions.Options.SubDumpPath = value; }
}
#endregion
#region Dumping Speeds
public int PreferredDumpSpeedCD
{
get { return _uiOptions.Options.PreferredDumpSpeedCD; }
set { _uiOptions.Options.PreferredDumpSpeedCD = value; }
}
public int PreferredDumpSpeedDVD
{
get { return _uiOptions.Options.PreferredDumpSpeedDVD; }
set { _uiOptions.Options.PreferredDumpSpeedDVD = value; }
}
public int PreferredDumpSpeedBD
{
get { return _uiOptions.Options.PreferredDumpSpeedBD; }
set { _uiOptions.Options.PreferredDumpSpeedBD = value; }
}
#endregion
#region Extra Dumping Options
public bool QuietMode
{
get { return _options.QuietMode; }
set { _options.QuietMode = value; }
get { return _uiOptions.Options.QuietMode; }
set { _uiOptions.Options.QuietMode = value; }
}
public bool ParanoidMode
{
get { return _options.ParanoidMode; }
set { _options.ParanoidMode = value; }
get { return _uiOptions.Options.ParanoidMode; }
set { _uiOptions.Options.ParanoidMode = value; }
}
public bool ScanForProtection
{
get { return _options.ScanForProtection; }
set { _options.ScanForProtection = value; }
get { return _uiOptions.Options.ScanForProtection; }
set { _uiOptions.Options.ScanForProtection = value; }
}
public string RereadAmountForC2
{
get { return Convert.ToString(_options.RereadAmountForC2); }
get { return Convert.ToString(_uiOptions.Options.RereadAmountForC2); }
set
{
if (Int32.TryParse(value, out int result))
_options.RereadAmountForC2 = result;
_uiOptions.Options.RereadAmountForC2 = result;
}
}
public bool AddPlaceholders
{
get { return _options.AddPlaceholders; }
set { _options.AddPlaceholders = value; }
get { return _uiOptions.Options.AddPlaceholders; }
set { _uiOptions.Options.AddPlaceholders = value; }
}
public bool PromptForDiscInformation
{
get { return _options.PromptForDiscInformation; }
set { _options.PromptForDiscInformation = value; }
get { return _uiOptions.Options.PromptForDiscInformation; }
set { _uiOptions.Options.PromptForDiscInformation = value; }
}
public bool IgnoreFixedDrives
{
get { return _options.IgnoreFixedDrives; }
set { _options.IgnoreFixedDrives = value; }
get { return _uiOptions.Options.IgnoreFixedDrives; }
set { _uiOptions.Options.IgnoreFixedDrives = value; }
}
public bool ResetDriveAfterDump
{
get { return _options.ResetDriveAfterDump; }
set { _options.ResetDriveAfterDump = value; }
get { return _uiOptions.Options.ResetDriveAfterDump; }
set { _uiOptions.Options.ResetDriveAfterDump = value; }
}
#endregion
#region Skip Options
public bool SkipMediaTypeDetection
{
get { return _options.SkipMediaTypeDetection; }
set { _options.SkipMediaTypeDetection = value; }
get { return _uiOptions.Options.SkipMediaTypeDetection; }
set { _uiOptions.Options.SkipMediaTypeDetection = value; }
}
public bool SkipSystemDetection
{
get { return _options.SkipSystemDetection; }
set { _options.SkipSystemDetection = value; }
get { return _uiOptions.Options.SkipSystemDetection; }
set { _uiOptions.Options.SkipSystemDetection = value; }
}
#endregion
#region Logging Options
public bool VerboseLogging
{
get { return _options.VerboseLogging; }
get { return _uiOptions.Options.VerboseLogging; }
set
{
_options.VerboseLogging = value;
_options.Save();
_uiOptions.Options.VerboseLogging = value;
_uiOptions.Save(); // TODO: Why does this save here?
}
}
public bool OpenLogWindowAtStartup
{
get { return _options.OpenLogWindowAtStartup; }
get { return _uiOptions.Options.OpenLogWindowAtStartup; }
set
{
_options.OpenLogWindowAtStartup = value;
_options.Save();
_uiOptions.Options.OpenLogWindowAtStartup = value;
_uiOptions.Save(); // TODO: Why does this save here?
}
}
#endregion
#region Redump Login Information
public string Username
{
get { return _options.Username; }
set { _options.Username = value; }
get { return _uiOptions.Options.Username; }
set { _uiOptions.Options.Username = value; }
}
public string Password
{
get { return _options.Password; }
set { _options.Password = value; }
get { return _uiOptions.Options.Password; }
set { _uiOptions.Options.Password = value; }
}
#endregion
public OptionsViewModel(UIOptions uiOptions)
{
this._uiOptions = uiOptions;
}
}

View File

@@ -26,7 +26,7 @@ namespace DICUI.Windows
private DumpEnvironment _env;
// Option related
private Options _options;
private UIOptions _uiOptions;
private OptionsWindow _optionsWindow;
// User input related
@@ -39,9 +39,8 @@ namespace DICUI.Windows
InitializeComponent();
// Initializes and load Options object
_options = new Options();
_options.Load();
ViewModels.OptionsViewModel = new OptionsViewModel(_options);
_uiOptions = new UIOptions();
ViewModels.OptionsViewModel = new OptionsViewModel(_uiOptions);
_logWindow = new LogWindow(this);
ViewModels.LoggerViewModel.SetWindow(_logWindow);
@@ -51,7 +50,7 @@ namespace DICUI.Windows
DiskScanButton.IsEnabled = false;
CopyProtectScanButton.IsEnabled = false;
if (_options.OpenLogWindowAtStartup)
if (_uiOptions.OpenLogWindowAtStartup)
{
this.WindowStartupLocation = WindowStartupLocation.Manual;
double combinedHeight = this.Height + _logWindow.Height + Constants.LogWindowMarginFromMainWindow;
@@ -73,7 +72,7 @@ namespace DICUI.Windows
_alreadyShown = true;
if (_options.OpenLogWindowAtStartup)
if (_uiOptions.OpenLogWindowAtStartup)
{
//TODO: this should be bound directly to WindowVisible property in two way fashion
// we need to study how to properly do it in XAML
@@ -109,7 +108,7 @@ namespace DICUI.Windows
_env.EjectDisc();
}
if (_options.ResetDriveAfterDump)
if (_uiOptions.ResetDriveAfterDump)
{
ViewModels.LoggerViewModel.VerboseLogLn($"Resetting drive {_env.Drive.Letter}");
_env.ResetDrive();
@@ -242,7 +241,7 @@ namespace DICUI.Windows
// lazy initialization
if (_optionsWindow == null)
{
_optionsWindow = new OptionsWindow(this, _options);
_optionsWindow = new OptionsWindow(this, _uiOptions);
_optionsWindow.Closed += delegate
{
_optionsWindow = null;
@@ -369,7 +368,7 @@ namespace DICUI.Windows
DiskScanButton.IsEnabled = true;
// Populate the list of drives and add it to the combo box
_drives = Validators.CreateListOfDrives(_options.IgnoreFixedDrives);
_drives = Validators.CreateListOfDrives(_uiOptions.IgnoreFixedDrives);
DriveLetterComboBox.ItemsSource = _drives;
if (DriveLetterComboBox.Items.Count > 0)
@@ -391,7 +390,7 @@ namespace DICUI.Windows
CopyProtectScanButton.IsEnabled = true;
// Get the current media type
if (!_options.SkipSystemDetection && index != -1)
if (!_uiOptions.SkipSystemDetection && index != -1)
{
ViewModels.LoggerViewModel.VerboseLog("Trying to detect system for drive {0}.. ", _drives[index].Letter);
var currentSystem = Validators.GetKnownSystem(_drives[index]);
@@ -441,44 +440,13 @@ namespace DICUI.Windows
private DumpEnvironment DetermineEnvironment()
{
// Populate the new environment
var env = new DumpEnvironment()
{
// Paths to tools
SubdumpPath = _options.SubDumpPath,
InternalProgram = Converters.ToInternalProgram(_options.InternalProgram),
OutputDirectory = OutputDirectoryTextBox.Text,
OutputFilename = OutputFilenameTextBox.Text,
// Get the currently selected options
Drive = DriveLetterComboBox.SelectedItem as Drive,
QuietMode = _options.QuietMode,
ParanoidMode = _options.ParanoidMode,
ScanForProtection = _options.ScanForProtection,
RereadAmountC2 = _options.RereadAmountForC2,
AddPlaceholders = _options.AddPlaceholders,
PromptForDiscInformation = _options.PromptForDiscInformation,
Username = _options.Username,
Password = _options.Password,
System = SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem,
Type = MediaTypeComboBox.SelectedItem as MediaType?,
};
// Set parameters and path accordingly
env.SetParameters(ParametersTextBox.Text);
switch (env.InternalProgram)
{
case InternalProgram.Aaru:
env.Parameters.Path = _options.AaruPath;
break;
case InternalProgram.DiscImageCreator:
env.Parameters.Path = _options.CreatorPath;
break;
}
var env = new DumpEnvironment(_uiOptions.Options,
OutputDirectoryTextBox.Text,
OutputFilenameTextBox.Text,
DriveLetterComboBox.SelectedItem as Drive,
SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem,
MediaTypeComboBox.SelectedItem as MediaType?,
ParametersTextBox.Text);
// Disable automatic reprocessing of the textboxes until we're done
OutputDirectoryTextBox.TextChanged -= OutputDirectoryTextBoxTextChanged;
@@ -498,8 +466,8 @@ namespace DICUI.Windows
/// </summary>
private async void StartDumping()
{
if (_env == null)
_env = DetermineEnvironment();
// One last check to determine environment, just in case
_env = DetermineEnvironment();
// If still in custom parameter mode, check that users meant to continue or not
if (EnableParametersCheckBox.IsChecked == true)
@@ -521,14 +489,6 @@ namespace DICUI.Windows
try
{
// Check for the firmware first for DiscImageCreator
// TODO: Remove this (and method) once DIC end-to-end logging becomes a thing
if (_env.InternalProgram == InternalProgram.DiscImageCreator && !await _env.DriveHasLatestFimrware())
{
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;
}
// Validate that the user explicitly wants an inactive drive to be considered for dumping
if (!_env.Drive.MarkedActive)
{
@@ -572,37 +532,28 @@ namespace DICUI.Windows
if (result)
{
// TODO: Remove Aaru handling when irrelevant
if (_env.InternalProgram == InternalProgram.Aaru)
{
ViewModels.LoggerViewModel.VerboseLogLn("Aaru does not support split tracks or DiscImageCreator-compatible outputs");
ViewModels.LoggerViewModel.VerboseLogLn("No automatic submission information will be gathered for this disc");
}
else
{
// Verify dump output and save it
result = _env.VerifyAndSaveDumpOutput(progress,
EjectWhenDoneCheckBox.IsChecked,
_options.ResetDriveAfterDump,
(si) =>
{
// Verify dump output and save it
result = _env.VerifyAndSaveDumpOutput(progress,
EjectWhenDoneCheckBox.IsChecked,
_uiOptions.ResetDriveAfterDump,
(si) =>
{
// lazy initialization
if (_discInformationWindow == null)
{
_discInformationWindow = new DiscInformationWindow(this, si);
_discInformationWindow.Closed += delegate
{
_discInformationWindow = new DiscInformationWindow(this, si);
_discInformationWindow.Closed += delegate
{
_discInformationWindow = null;
};
}
_discInformationWindow.Owner = this;
_discInformationWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
_discInformationWindow.Refresh();
return _discInformationWindow.ShowDialog();
_discInformationWindow = null;
};
}
);
}
_discInformationWindow.Owner = this;
_discInformationWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
_discInformationWindow.Refresh();
return _discInformationWindow.ShowDialog();
}
);
}
StatusLabel.Content = result ? "Dumping complete!" : result.Message;
@@ -666,19 +617,10 @@ namespace DICUI.Windows
// Set the output directory, if we changed drives or it's not already
if (driveChanged || string.IsNullOrEmpty(OutputDirectoryTextBox.Text))
OutputDirectoryTextBox.Text = Path.Combine(_options.DefaultOutputPath, drive?.VolumeLabel ?? string.Empty);
OutputDirectoryTextBox.Text = Path.Combine(_uiOptions.DefaultOutputPath, drive?.VolumeLabel ?? string.Empty);
// Get the extension for the file for the next two statements
string extension = null;
switch (_env.InternalProgram)
{
case InternalProgram.Aaru:
extension = Aaru.Converters.Extension(mediaType);
break;
case InternalProgram.DiscImageCreator:
extension = DiscImageCreator.Converters.Extension(mediaType);
break;
}
string extension = _env.GetExtension(mediaType);
// Set the output filename, if we changed drives or it's not already
if (driveChanged || string.IsNullOrEmpty(OutputFilenameTextBox.Text))
@@ -737,31 +679,10 @@ namespace DICUI.Windows
DriveSpeedComboBox.ItemsSource = values;
ViewModels.LoggerViewModel.VerboseLogLn("Supported media speeds: {0}", string.Join(",", values));
// Find the minimum set to compare against
int preferred = 100;
switch (_currentMediaType)
{
case MediaType.CDROM:
case MediaType.GDROM:
preferred = _options.PreferredDumpSpeedCD;
break;
case MediaType.DVD:
case MediaType.HDDVD:
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
preferred = _options.PreferredDumpSpeedDVD;
break;
case MediaType.BluRay:
preferred = _options.PreferredDumpSpeedBD;
break;
default:
preferred = _options.PreferredDumpSpeedCD;
break;
}
// Set the selected speed
ViewModels.LoggerViewModel.VerboseLogLn("Setting drive speed to: {0}", preferred);
DriveSpeedComboBox.SelectedValue = preferred;
int speed = _uiOptions.GetPreferredDumpSpeedForMediaType(_currentMediaType);
ViewModels.LoggerViewModel.VerboseLogLn("Setting drive speed to: {0}", speed);
DriveSpeedComboBox.SelectedValue = speed;
}
/// <summary>
@@ -775,7 +696,7 @@ namespace DICUI.Windows
return;
// Get the current media type
if (!_options.SkipMediaTypeDetection)
if (!_uiOptions.SkipMediaTypeDetection)
{
ViewModels.LoggerViewModel.VerboseLog("Trying to detect media type for drive {0}.. ", drive.Letter);
_currentMediaType = Validators.GetMediaType(drive);

View File

@@ -33,19 +33,35 @@
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Aaru Path" />
<TextBox x:Name="AaruPathTextBox" Grid.Row="0" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
<TextBox x:Name="AaruPathTextBox" Grid.Row="0" Grid.Column="1" Height="22" HorizontalAlignment="Stretch"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Text="{Binding Path=AaruPath}" />
<Button x:Name="AaruPathButton" Grid.Row="0" Grid.Column="2" Height="22" Width="22" Content="..." Click="BrowseForPathClick" />
<Label Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="DiscImageCreator Path" />
<TextBox x:Name="CreatorPathTextBox" Grid.Row="1" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
<TextBox x:Name="CreatorPathTextBox" Grid.Row="1" Grid.Column="1" Height="22" HorizontalAlignment="Stretch"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Text="{Binding Path=CreatorPath}" />
<Button x:Name="CreatorPathButton" Grid.Row="1" Grid.Column="2" Height="22" Width="22" Content="..." Click="BrowseForPathClick" />
<!--
<Label Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="DD Path" />
<TextBox x:Name="DDPathTextBox" Grid.Row="1" Grid.Column="1" Height="22" HorizontalAlignment="Stretch"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Text="{Binding Path=DDPath}" />
<Button x:Name="DDPathButton" Grid.Row="1" Grid.Column="2" Height="22" Width="22" Content="..." Click="BrowseForPathClick" />
-->
<Label Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="subdump Path" />
<TextBox x:Name="SubDumpPathTextBox" Grid.Row="2" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
<TextBox x:Name="SubDumpPathTextBox" Grid.Row="2" Grid.Column="1" Height="22" HorizontalAlignment="Stretch"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Text="{Binding Path=SubDumpPath}" />
<Button x:Name="SubDumpPathButton" Grid.Row="2" Grid.Column="2" Height="22" Width="22" Content="..." Click="BrowseForPathClick"/>
<Label Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Default Output Path" />
<TextBox x:Name="DefaultOutputPathTextBox" Grid.Row="3" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
<TextBox x:Name="DefaultOutputPathTextBox" Grid.Row="3" Grid.Column="1" Height="22" HorizontalAlignment="Stretch"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Text="{Binding Path=DefaultOutputPath}" />
<Button x:Name="DefaultOutputPathButton" Grid.Row="3" Grid.Column="2" Height="22" Width="22" Content="..." Click="BrowseForPathClick" />
</Grid>
@@ -64,16 +80,28 @@
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="CD-ROM" />
<Slider x:Name="DumpSpeedCDSlider" Grid.Row="0" Grid.Column="1" Minimum="1" Maximum="72" IsSnapToTickEnabled="True" TickPlacement="BottomRight" Ticks="{Binding Source={x:Static local:Constants.SpeedsForCDAsCollection}}" />
<TextBox x:Name="DumpSpeedCDTextBox" Grid.Row="0" Grid.Column="2" Width="22" Height="22" TextAlignment="Center" IsReadOnly="True" IsReadOnlyCaretVisible="False" VerticalAlignment="Center" Text="{Binding ElementName=DumpSpeedCDSlider, Path=Value, UpdateSourceTrigger=PropertyChanged}" Background="LightGray" Foreground="Gray"/>
<Slider x:Name="DumpSpeedCDSlider" Grid.Row="0" Grid.Column="1" Minimum="1" Maximum="72" IsSnapToTickEnabled="True" TickPlacement="BottomRight"
Ticks="{Binding Source={x:Static local:Constants.SpeedsForCDAsCollection}}"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Value="{Binding Path=PreferredDumpSpeedCD}" />
<TextBox x:Name="DumpSpeedCDTextBox" Grid.Row="0" Grid.Column="2" Width="22" Height="22" TextAlignment="Center" IsReadOnly="True" IsReadOnlyCaretVisible="False" VerticalAlignment="Center"
Text="{Binding ElementName=DumpSpeedCDSlider, Path=Value, UpdateSourceTrigger=PropertyChanged}" Background="LightGray" Foreground="Gray"/>
<Label Grid.Row="1" Grid.Column="0" Content="DVD-ROM" />
<Slider x:Name="DumpSpeedDVDSlider" Grid.Row="1" Grid.Column="1" Minimum="1" Maximum="24" IsSnapToTickEnabled="True" TickPlacement="BottomRight" Ticks="{Binding Source={x:Static local:Constants.SpeedsForDVDAsCollection}}" />
<TextBox x:Name="DumpSpeedDVDTextBox" Grid.Row="1" Grid.Column="2" Width="22" Height="22" TextAlignment="Center" IsReadOnly="True" IsReadOnlyCaretVisible="False" VerticalAlignment="Center" Text="{Binding ElementName=DumpSpeedDVDSlider, Path=Value, UpdateSourceTrigger=PropertyChanged}" Background="LightGray" Foreground="Gray"/>
<Slider x:Name="DumpSpeedDVDSlider" Grid.Row="1" Grid.Column="1" Minimum="1" Maximum="24" IsSnapToTickEnabled="True" TickPlacement="BottomRight"
Ticks="{Binding Source={x:Static local:Constants.SpeedsForDVDAsCollection}}"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Value="{Binding Path=PreferredDumpSpeedDVD}" />
<TextBox x:Name="DumpSpeedDVDTextBox" Grid.Row="1" Grid.Column="2" Width="22" Height="22" TextAlignment="Center" IsReadOnly="True" IsReadOnlyCaretVisible="False" VerticalAlignment="Center"
Text="{Binding ElementName=DumpSpeedDVDSlider, Path=Value, UpdateSourceTrigger=PropertyChanged}" Background="LightGray" Foreground="Gray"/>
<Label Grid.Row="2" Grid.Column="0" Content="BD-ROM" />
<Slider x:Name="DumpSpeedBDSlider" Grid.Row="2" Grid.Column="1" Minimum="1" Maximum="16" IsSnapToTickEnabled="True" TickPlacement="BottomRight" Ticks="{Binding Source={x:Static local:Constants.SpeedsForBDAsCollection}}" />
<TextBox x:Name="DumpSpeedBDTextBox" Grid.Row="2" Grid.Column="2" Width="22" Height="22" TextAlignment="Center" IsReadOnly="True" IsReadOnlyCaretVisible="False" VerticalAlignment="Center" Text="{Binding ElementName=DumpSpeedBDSlider, Path=Value, UpdateSourceTrigger=PropertyChanged}" Background="LightGray" Foreground="Gray"/>
<Slider x:Name="DumpSpeedBDSlider" Grid.Row="2" Grid.Column="1" Minimum="1" Maximum="16" IsSnapToTickEnabled="True" TickPlacement="BottomRight"
Ticks="{Binding Source={x:Static local:Constants.SpeedsForBDAsCollection}}"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Value="{Binding Path=PreferredDumpSpeedBD}" />
<TextBox x:Name="DumpSpeedBDTextBox" Grid.Row="2" Grid.Column="2" Width="22" Height="22" TextAlignment="Center" IsReadOnly="True" IsReadOnlyCaretVisible="False" VerticalAlignment="Center"
Text="{Binding ElementName=DumpSpeedBDSlider, Path=Value, UpdateSourceTrigger=PropertyChanged}" Background="LightGray" Foreground="Gray"/>
</Grid>
@@ -167,7 +195,9 @@
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Username" />
<TextBox x:Name="RedumpUsernameTextBox" Grid.Row="0" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" />
<TextBox x:Name="RedumpUsernameTextBox" Grid.Row="0" Grid.Column="1" Height="22" HorizontalAlignment="Stretch"
DataContext="{Binding Source={x:Static local:ViewModels.OptionsViewModel}}"
Text="{Binding Path=Username}" />
<Label Grid.Row="0" Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Password" />
<PasswordBox x:Name="RedumpPasswordBox" Grid.Row="0" Grid.Column="3" Height="22" HorizontalAlignment="Stretch" PasswordChar="*" />

View File

@@ -14,13 +14,13 @@ namespace DICUI.Windows
public partial class OptionsWindow : Window
{
private readonly MainWindow _mainWindow;
private readonly Options _options;
private readonly UIOptions _uiOptions;
public OptionsWindow(MainWindow mainWindow, Options options)
public OptionsWindow(MainWindow mainWindow, UIOptions options)
{
InitializeComponent();
_mainWindow = mainWindow;
_options = options;
_uiOptions = options;
}
private OpenFileDialog CreateOpenFileDialog()
@@ -41,12 +41,6 @@ namespace DICUI.Windows
return dialog;
}
private string[] PathSettings()
{
string[] pathSettings = { "AaruPath", "CreatorPath", "DefaultOutputPath", "SubDumpPath" };
return pathSettings;
}
private TextBox TextBoxForPathSetting(string name)
{
return FindName(name + "TextBox") as TextBox;
@@ -83,7 +77,9 @@ namespace DICUI.Windows
}
if (exists)
{
TextBoxForPathSetting(pathSettingName).Text = path;
}
else
{
System.Windows.MessageBox.Show(
@@ -99,30 +95,18 @@ namespace DICUI.Windows
public void Refresh()
{
Array.ForEach(PathSettings(), setting => TextBoxForPathSetting(setting).Text = _options.Get(setting));
DumpSpeedCDSlider.Value = _options.PreferredDumpSpeedCD;
DumpSpeedDVDSlider.Value = _options.PreferredDumpSpeedDVD;
DumpSpeedBDSlider.Value = _options.PreferredDumpSpeedBD;
RedumpUsernameTextBox.Text = _options.Username;
RedumpPasswordBox.Password = _options.Password;
// Handle non-bindable fields
RedumpPasswordBox.Password = _uiOptions.Options.Password;
}
#region Event Handlers
private void OnAcceptClick(object sender, EventArgs e)
{
Array.ForEach(PathSettings(), setting => _options.Set(setting, TextBoxForPathSetting(setting).Text));
// Handle non-bindable fields
_uiOptions.Options.Password = RedumpPasswordBox.Password;
_options.PreferredDumpSpeedCD = Convert.ToInt32(DumpSpeedCDSlider.Value);
_options.PreferredDumpSpeedDVD = Convert.ToInt32(DumpSpeedDVDSlider.Value);
_options.PreferredDumpSpeedBD = Convert.ToInt32(DumpSpeedBDSlider.Value);
_options.Username = RedumpUsernameTextBox.Text;
_options.Password = RedumpPasswordBox.Password;
_options.Save();
_uiOptions.Save();
Hide();
_mainWindow.OnOptionsUpdated();
@@ -134,6 +118,9 @@ namespace DICUI.Windows
Hide();
}
/// <summary>
/// Test Redump credentials for validity
/// </summary>
private void OnRedumpTestClick(object sender, EventArgs e)
{
using (CookieAwareWebClient wc = new CookieAwareWebClient())

View File

@@ -7,12 +7,14 @@ DiscImageCreator/Aaru UI in C#
This is a community project, so if you have some time and knowledge to give, we'll be glad to add you to the contributor of this project :)
DICUI relies on the following projects:
- **DiscImageCreator** by Sarami - Dumping - [GitHub](https://github.com/saramibreak/DiscImageCreator)
- **Aaru** by Claunia - Dumping - [GitHub](https://github.com/aaru-dps/Aaru)
- **CleanRip** by emu_kidid - Offline dumping - [GitHub](https://github.com/emukidid/cleanrip)
- **DD for Windows* - Dumping - [Homepage](http://www.chrysocome.net/dd);
- **DiscImageCreator** by Sarami - Dumping - [GitHub](https://github.com/saramibreak/DiscImageCreator)
- **BurnOutSharp** - Protection scanning - [GitHub](https://github.com/mnadareski/BurnOutSharp)
- **UnshieldSharp** - Protection scanning - [GitHub](https://github.com/mnadareski/UnshieldSharp)
**Note:** Both DiscImageCreator and Aaru have WIP builds. In general, WIP builds are not supported with new flags or features until they make it into the stable release.
**Note:** Both Aaru DiscImageCreator have WIP builds. In general, WIP builds are not supported with new flags or features until they make it into the stable release.
## System Requirements
@@ -53,3 +55,4 @@ These are the tireless individuals who have dedicated countless hours to help te
- **Kludge** - Primary stress tester
- **ajshell1** - Tester
- **eientei95** - Tester
- **VGPC Discord** - Testing and feedback

View File

@@ -32,17 +32,22 @@ build:
# post-build step
after_build:
- ps: appveyor DownloadFile https://github.com/aaru-dps/Aaru/releases/download/v5.0.0.2879/aaru-5.0.0.2879-1_windows_x64.zip
- ps: appveyor DownloadFile https://github.com/aaru-dps/Aaru/releases/download/v5.0.1.2884/aaru-5.0.1.2884-1_windows_x64.zip
- ps: appveyor DownloadFile http://www.chrysocome.net/downloads/8ab730cd2a29e76ddd89be1f99357942/dd-0.6beta3.zip
- ps: appveyor DownloadFile https://github.com/saramibreak/DiscImageCreator/files/4426240/DiscImageCreator_20200403.zip
- ps: appveyor DownloadFile https://archive.org/download/subdump_fua_0x28/subdump_fua_0x28.zip
- 7z e aaru-5.0.0.2879-1_windows_x64.zip -oDICUI\bin\Debug\net462\Programs\Aaru *
- 7z e aaru-5.0.0.2879-1_windows_x64.zip -oDICUI\bin\Debug\net472\Programs\Aaru *
- 7z e aaru-5.0.0.2879-1_windows_x64.zip -oDICUI\bin\Debug\net48\Programs\Aaru *
- 7z e aaru-5.0.0.2879-1_windows_x64.zip -oDICUI\bin\Debug\netcoreapp3.0\Programs\Aaru *
- 7z e aaru-5.0.1.2884-1_windows_x64.zip -oDICUI\bin\Debug\net462\Programs\Aaru *
- 7z e aaru-5.0.1.2884-1_windows_x64.zip -oDICUI\bin\Debug\net472\Programs\Aaru *
- 7z e aaru-5.0.1.2884-1_windows_x64.zip -oDICUI\bin\Debug\net48\Programs\Aaru *
- 7z e aaru-5.0.1.2884-1_windows_x64.zip -oDICUI\bin\Debug\netcoreapp3.1\Programs\Aaru *
- 7z e dd-0.6beta3.zip -oDICUI\bin\Debug\net462\Programs\DD *
- 7z e dd-0.6beta3.zip -oDICUI\bin\Debug\net472\Programs\DD *
- 7z e dd-0.6beta3.zip -oDICUI\bin\Debug\net48\Programs\DD *
- 7z e dd-0.6beta3.zip -oDICUI\bin\Debug\netcoreapp3.1\Programs\DD *
- 7z e DiscImageCreator_20200403.zip -oDICUI\bin\Debug\net462\Programs\Creator Release_ANSI\*
- 7z e DiscImageCreator_20200403.zip -oDICUI\bin\Debug\net472\Programs\Creator Release_ANSI\*
- 7z e DiscImageCreator_20200403.zip -oDICUI\bin\Debug\net48\Programs\Creator Release_ANSI\*
- 7z e DiscImageCreator_20200403.zip -oDICUI\bin\Debug\netcoreapp3.0\Programs\Creator Release_ANSI\*
- 7z e DiscImageCreator_20200403.zip -oDICUI\bin\Debug\netcoreapp3.1\Programs\Creator Release_ANSI\*
- 7z e subdump_fua_0x28.zip -oDICUI\bin\Debug\net462 *
- mkdir DICUI\bin\Debug\net462\Programs\Subdump
- mv DICUI\bin\Debug\net462\subdump_fua_0x28.exe DICUI\bin\Debug\net462\Programs\Subdump\subdump.exe
@@ -52,9 +57,9 @@ after_build:
- 7z e subdump_fua_0x28.zip -oDICUI\bin\Debug\net48 *
- mkdir DICUI\bin\Debug\net48\Programs\Subdump
- mv DICUI\bin\Debug\net48\subdump_fua_0x28.exe DICUI\bin\Debug\net462\Programs\Subdump\subdump.exe
- 7z e subdump_fua_0x28.zip -oDICUI\bin\Debug\netcoreapp3.0 *
- mkdir DICUI\bin\Debug\netcoreapp3.0\Programs\Subdump
- mv DICUI\bin\Debug\netcoreapp3.0\subdump_fua_0x28.exe DICUI\bin\Debug\netcoreapp3.0\Programs\Subdump\subdump.exe
- 7z e subdump_fua_0x28.zip -oDICUI\bin\Debug\netcoreapp3.1 *
- mkdir DICUI\bin\Debug\netcoreapp3.1\Programs\Subdump
- mv DICUI\bin\Debug\netcoreapp3.1\subdump_fua_0x28.exe DICUI\bin\Debug\netcoreapp3.1\Programs\Subdump\subdump.exe
- 7z a DICUI.zip DICUI\bin\Debug\*
- 7z a DICUI-Check.zip DICUI.Check\bin\Debug\*