So, I added DD support

This commit is contained in:
Matt Nadareski
2020-04-21 15:52:57 -07:00
parent 5ed73aff2b
commit 2a58052bfd
6 changed files with 614 additions and 8 deletions

View File

@@ -212,7 +212,7 @@ namespace DICUI.Aaru
{
BaseCommand = Command.MediaDump;
InputValue = $"\\\\?\\{driveLetter.ToString()}:";
InputValue = $"\\\\?\\{driveLetter}:";
OutputValue = filename;
this[Flag.Force] = true;
@@ -305,7 +305,7 @@ namespace DICUI.Aaru
#endregion
if (BaseCommand != Command.NONE)
parameters.Add(Converters.LongName((Command)BaseCommand));
parameters.Add(Converters.LongName(BaseCommand));
else
return null;

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

@@ -18,5 +18,87 @@ namespace DICUI.DD
}
#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

@@ -1,4 +1,8 @@
using DICUI.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using DICUI.Data;
namespace DICUI.DD
{
@@ -7,6 +11,50 @@ namespace DICUI.DD
/// </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>
@@ -39,6 +87,90 @@ namespace DICUI.DD
/// <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;
}
@@ -46,24 +178,26 @@ namespace DICUI.DD
/// Get the input path from the implementation
/// </summary>
/// <returns>String representing the path, null on error</returns>
public override string InputPath() => string.Empty;
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() => string.Empty;
public override string OutputPath() => OutputFileValue;
/// <summary>
/// Get the processing speed from the implementation
/// </summary>
/// <returns>int? representing the speed, null on error</returns>
public override int? GetSpeed() => null;
/// <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)
{
}
@@ -72,19 +206,39 @@ namespace DICUI.DD
/// 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() => true;
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>
@@ -106,6 +260,17 @@ namespace DICUI.DD
bool paranoid,
int retryCount)
{
BaseCommand = Command.NONE;
InputFileValue = $"\\\\?\\{driveLetter}:";
OutputFileValue = filename;
// TODO: Refine the block size more based on media type (1440K for FDD, etc.)
this[Flag.BlockSize] = true;
BlockSizeValue = 1024 * 1024 * 1024;
this[Flag.Progress] = true;
this[Flag.Size] = true;
}
/// <summary>
@@ -115,7 +280,301 @@ namespace DICUI.DD
/// <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>
/// 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

@@ -163,7 +163,7 @@ namespace DICUI.DiscImageCreator
List<string> parameters = new List<string>();
if (BaseCommand != Command.NONE)
parameters.Add(Converters.LongName((Command)BaseCommand));
parameters.Add(Converters.LongName(BaseCommand));
else
return null;