diff --git a/DICUI.Library/Aaru/Parameters.cs b/DICUI.Library/Aaru/Parameters.cs
index 0805f24d..e3578a3f 100644
--- a/DICUI.Library/Aaru/Parameters.cs
+++ b/DICUI.Library/Aaru/Parameters.cs
@@ -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;
diff --git a/DICUI.Library/DD/Constants.cs b/DICUI.Library/DD/Constants.cs
new file mode 100644
index 00000000..e6d3cdca
--- /dev/null
+++ b/DICUI.Library/DD/Constants.cs
@@ -0,0 +1,31 @@
+namespace DICUI.DD
+{
+ ///
+ /// Top-level commands for DD
+ ///
+ public static class CommandStrings
+ {
+ public const string List = "--list";
+ }
+
+ ///
+ /// Dumping flags for DD
+ ///
+ 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";
+ }
+}
\ No newline at end of file
diff --git a/DICUI.Library/DD/Converters.cs b/DICUI.Library/DD/Converters.cs
index 6e8a1068..509e2dac 100644
--- a/DICUI.Library/DD/Converters.cs
+++ b/DICUI.Library/DD/Converters.cs
@@ -18,5 +18,87 @@ namespace DICUI.DD
}
#endregion
+
+ #region Convert to Long Name
+
+ ///
+ /// Get the string representation of the Command enum values
+ ///
+ /// Command value to convert
+ /// String representing the value, if possible
+ public static string LongName(Command command)
+ {
+ switch (command)
+ {
+ case Command.List:
+ return CommandStrings.List;
+
+ case Command.NONE:
+ default:
+ return "";
+ }
+ }
+
+ ///
+ /// Get the string representation of the Flag enum values
+ ///
+ /// Flag value to convert
+ /// String representing the value, if possible
+ 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
+
+ ///
+ /// Get the Command enum value for a given string
+ ///
+ /// String value to convert
+ /// Command represented by the string(s), if possible
+ public static Command StringToCommand(string command)
+ {
+ switch (command)
+ {
+ case CommandStrings.List:
+ return Command.List;
+
+ default:
+ return Command.NONE;
+ }
+ }
+
+ #endregion
}
}
\ No newline at end of file
diff --git a/DICUI.Library/DD/Enumerations.cs b/DICUI.Library/DD/Enumerations.cs
new file mode 100644
index 00000000..29a307e1
--- /dev/null
+++ b/DICUI.Library/DD/Enumerations.cs
@@ -0,0 +1,34 @@
+namespace DICUI.DD
+{
+ ///
+ /// Supported DD commands
+ ///
+ public enum Command: int
+ {
+ NONE = 0, // For DD, this represents a normal dump
+ List,
+ }
+
+ ///
+ /// Supported DD flags
+ ///
+ public enum Flag : int
+ {
+ NONE = 0,
+
+ // Boolean flags
+ Progress,
+ Size,
+
+ // Int64 flags
+ BlockSize,
+ Count,
+ Seek,
+ Skip,
+
+ // String flags
+ Filter,
+ InputFile,
+ OutputFile,
+ }
+}
\ No newline at end of file
diff --git a/DICUI.Library/DD/Parameters.cs b/DICUI.Library/DD/Parameters.cs
index 2d4a93bb..549ff272 100644
--- a/DICUI.Library/DD/Parameters.cs
+++ b/DICUI.Library/DD/Parameters.cs
@@ -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
///
public class Parameters : BaseParameters
{
+ ///
+ /// Base command to run
+ ///
+ public Command BaseCommand { get; set; }
+
+ ///
+ /// Set of flags to pass to the executable
+ ///
+ protected Dictionary _flags = new Dictionary();
+ public bool? this[Flag key]
+ {
+ get
+ {
+ if (_flags.ContainsKey(key))
+ return _flags[key];
+
+ return null;
+ }
+ set
+ {
+ _flags[key] = value;
+ }
+ }
+ protected internal IEnumerable 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
+
///
/// Populate a Parameters object from a param string
///
@@ -39,6 +87,90 @@ namespace DICUI.DD
/// Correctly formatted parameter string, null on error
public override string GenerateParameters()
{
+ List parameters = new List();
+
+ 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
///
/// String representing the path, null on error
- public override string InputPath() => string.Empty;
+ public override string InputPath() => InputFileValue;
///
/// Get the output path from the implementation
///
/// String representing the path, null on error
- public override string OutputPath() => string.Empty;
+ public override string OutputPath() => OutputFileValue;
///
/// Get the processing speed from the implementation
///
/// int? representing the speed, null on error
- public override int? GetSpeed() => null;
+ /// DD does not support drive speeds
+ public override int? GetSpeed() => 1;
///
/// Set the processing speed int the implementation
///
/// int? representing the speed
+ /// DD does not support drive speeds
public override void SetSpeed(int? speed)
{
}
@@ -72,19 +206,39 @@ namespace DICUI.DD
/// Get the MediaType from the current set of parameters
///
/// MediaType value if successful, null on error
+ /// DD does not know the difference between media types
public override MediaType? GetMediaType() => null;
///
/// Gets if the current command is considered a dumping command or not
///
/// True if it's a dumping command, false otherwise
- public override bool IsDumpingCommand() => true;
+ public override bool IsDumpingCommand()
+ {
+ switch (this.BaseCommand)
+ {
+ case Command.List:
+ return false;
+ default:
+ return true;
+ }
+ }
///
/// Reset all special variables to have default values
///
protected override void ResetValues()
{
+ BaseCommand = Command.NONE;
+
+ _flags = new Dictionary();
+
+ BlockSizeValue = null;
+ CountValue = null;
+ InputFileValue = null;
+ OutputFileValue = null;
+ SeekValue = null;
+ SkipValue = null;
}
///
@@ -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;
}
///
@@ -115,7 +280,301 @@ namespace DICUI.DD
///
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 parts = Regex.Matches(parameters, @"[\""].+?[\""]|[^ ]+")
+ .Cast()
+ .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;
}
+
+ ///
+ /// Get the list of commands that use a given flag
+ ///
+ /// Flag value to get commands for
+ /// List of Commands, if possible
+ private List GetSupportedCommands(Flag flag)
+ {
+ var commands = new List();
+ 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;
+ }
+
+ ///
+ /// Process a boolean parameter
+ ///
+ /// List of parts to be referenced
+ /// Flag string to check
+ /// Flag value corresponding to the flag
+ /// Reference to the position in the parts
+ /// True if the parameter was processed successfully or skipped, false otherwise
+ private bool ProcessBooleanParameter(List 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;
+ }
+
+ ///
+ /// Process an Int64 parameter
+ ///
+ /// List of parts to be referenced
+ /// Flag string to check
+ /// Flag value corresponding to the flag
+ /// Reference to the position in the parts
+ /// Int64 value if success, Int64.MinValue if skipped, null on error/returns>
+ private long? ProcessInt64Parameter(List 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;
+ }
+
+ ///
+ /// Process a string parameter
+ ///
+ /// List of parts to be referenced
+ /// Flag string to check
+ /// Flag value corresponding to the flag
+ /// Reference to the position in the parts
+ /// String value if possible, string.Empty on missing, null on error
+ private string ProcessStringParameter(List 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;
+ }
}
}
diff --git a/DICUI.Library/DiscImageCreator/Parameters.cs b/DICUI.Library/DiscImageCreator/Parameters.cs
index 237c47cc..1e5a789f 100644
--- a/DICUI.Library/DiscImageCreator/Parameters.cs
+++ b/DICUI.Library/DiscImageCreator/Parameters.cs
@@ -163,7 +163,7 @@ namespace DICUI.DiscImageCreator
List parameters = new List();
if (BaseCommand != Command.NONE)
- parameters.Add(Converters.LongName((Command)BaseCommand));
+ parameters.Add(Converters.LongName(BaseCommand));
else
return null;