mirror of
https://github.com/SabreTools/MPF.git
synced 2026-07-02 17:24:48 +00:00
910 lines
32 KiB
C#
910 lines
32 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
using SabreTools.RedumpLib.Data;
|
|
|
|
namespace MPF.ExecutionContexts.Redumper
|
|
{
|
|
/// <summary>
|
|
/// Represents a generic set of Redumper parameters
|
|
/// </summary>
|
|
public sealed class ExecutionContext : BaseExecutionContext
|
|
{
|
|
#region Generic Dumping Information
|
|
|
|
/// <inheritdoc/>
|
|
public override string? InputPath => DriveValue?.Trim('"');
|
|
|
|
/// <inheritdoc/>
|
|
public override string? OutputPath => Path.Combine(
|
|
ImagePathValue?.Trim('"') ?? string.Empty,
|
|
ImageNameValue?.Trim('"') ?? string.Empty)
|
|
+ GetDefaultExtension(this.Type);
|
|
|
|
/// <inheritdoc/>
|
|
public override int? Speed => SpeedValue;
|
|
|
|
#endregion
|
|
|
|
#region Flag Values
|
|
|
|
/// <summary>
|
|
/// List of all modes being run
|
|
/// </summary>
|
|
public List<string>? ModeValues { get; set; }
|
|
|
|
#region General
|
|
|
|
/// <summary>
|
|
/// Drive to use, first available drive with disc, if not provided
|
|
/// </summary>
|
|
public string? DriveValue { get; set; }
|
|
|
|
/// <summary>
|
|
/// Drive read speed, optimal drive speed will be used if not provided
|
|
/// </summary>
|
|
public int? SpeedValue { get; set; }
|
|
|
|
/// <summary>
|
|
/// Number of sector retries in case of SCSI/C2 error (default: 0)
|
|
/// </summary>
|
|
public int? RetriesValue { get; set; }
|
|
|
|
/// <summary>
|
|
/// Dump files base directory
|
|
/// </summary>
|
|
public string? ImagePathValue { get; set; }
|
|
|
|
/// <summary>
|
|
/// Dump files prefix, autogenerated in dump mode, if not provided
|
|
/// </summary>
|
|
public string? ImageNameValue { get; set; }
|
|
|
|
#endregion
|
|
|
|
#region Drive Configuration
|
|
|
|
/// <summary>
|
|
/// Override drive type, possible values: GENERIC, PLEXTOR, LG_ASUS
|
|
/// </summary>
|
|
public string? DriveTypeValue { get; set; }
|
|
|
|
/// <summary>
|
|
/// Override drive read offset
|
|
/// </summary>
|
|
public int? DriveReadOffsetValue { get; set; }
|
|
|
|
/// <summary>
|
|
/// Override drive C2 shift
|
|
/// </summary>
|
|
public int? DriveC2ShiftValue { get; set; }
|
|
|
|
/// <summary>
|
|
/// Override drive pre-gap start LBA
|
|
/// </summary>
|
|
public int? DrivePregapStartValue { get; set; }
|
|
|
|
/// <summary>
|
|
/// Override drive read method, possible values: BE, D8, BE_CDDA
|
|
/// </summary>
|
|
public string? DriveReadMethodValue { get; set; }
|
|
|
|
/// <summary>
|
|
/// Override drive sector order, possible values: DATA_C2_SUB, DATA_SUB_C2
|
|
/// </summary>
|
|
public string? DriveSectorOrderValue { get; set; }
|
|
|
|
#endregion
|
|
|
|
#region Offset
|
|
|
|
/// <summary>
|
|
/// Override offset autodetection and use supplied value
|
|
/// </summary>
|
|
public int? ForceOffsetValue { get; set; }
|
|
|
|
/// <summary>
|
|
/// Maximum absolute sample value to treat it as silence (default: 32)
|
|
/// </summary>
|
|
public int? AudioSilenceThresholdValue { get; set; }
|
|
|
|
#endregion
|
|
|
|
#region Split
|
|
|
|
/// <summary>
|
|
/// Fill byte value for skipped sectors (default: 0x55)
|
|
/// </summary>
|
|
public byte? SkipFillValue { get; set; }
|
|
|
|
#endregion
|
|
|
|
#region Miscellaneous
|
|
|
|
/// <summary>
|
|
/// LBA to start dumping from
|
|
/// </summary>
|
|
public int? LBAStartValue { get; set; }
|
|
|
|
/// <summary>
|
|
/// LBA to stop dumping at (everything before the value), useful for discs with fake TOC
|
|
/// </summary>
|
|
public int? LBAEndValue { get; set; }
|
|
|
|
/// <summary>
|
|
/// LBA ranges of sectors to skip
|
|
/// </summary>
|
|
public string? SkipValue { get; set; }
|
|
|
|
/// <summary>
|
|
/// Write offset for dumps when reading as data
|
|
/// </summary>
|
|
public int? DumpWriteOffsetValue { get; set; }
|
|
|
|
/// <summary>
|
|
/// Number of sectors to read at once on initial dump, DVD only (Default 32)
|
|
/// </summary>
|
|
public int? DumpReadSizeValue { get; set; }
|
|
|
|
/// <summary>
|
|
/// Maximum number of lead-in retries per session (Default 4)
|
|
/// </summary>
|
|
public int? PlextorLeadinRetriesValue { get; set; }
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
/// <inheritdoc/>
|
|
public ExecutionContext(string? parameters) : base(parameters) { }
|
|
|
|
/// <inheritdoc/>
|
|
public ExecutionContext(RedumpSystem? system, MediaType? type, string? drivePath, string filename, int? driveSpeed, Dictionary<string, string?> options)
|
|
: base(system, type, drivePath, filename, driveSpeed, options)
|
|
{
|
|
}
|
|
|
|
#region BaseExecutionContext Implementations
|
|
|
|
/// <inheritdoc/>
|
|
/// <remarks>Command support is irrelevant for redumper</remarks>
|
|
public override Dictionary<string, List<string>> GetCommandSupport()
|
|
{
|
|
return new Dictionary<string, List<string>>()
|
|
{
|
|
[CommandStrings.NONE] =
|
|
[
|
|
// General
|
|
FlagStrings.HelpLong,
|
|
FlagStrings.HelpShort,
|
|
FlagStrings.Version,
|
|
FlagStrings.Verbose,
|
|
FlagStrings.Debug,
|
|
FlagStrings.Drive,
|
|
FlagStrings.Speed,
|
|
FlagStrings.Retries,
|
|
FlagStrings.ImagePath,
|
|
FlagStrings.ImageName,
|
|
FlagStrings.Overwrite,
|
|
|
|
// Drive Configuration
|
|
FlagStrings.DriveType,
|
|
FlagStrings.DriveReadOffset,
|
|
FlagStrings.DriveC2Shift,
|
|
FlagStrings.DrivePregapStart,
|
|
FlagStrings.DriveReadMethod,
|
|
FlagStrings.DriveSectorOrder,
|
|
|
|
// Drive Specific
|
|
FlagStrings.PlextorSkipLeadin,
|
|
FlagStrings.PlextorLeadinRetries,
|
|
FlagStrings.AsusSkipLeadout,
|
|
|
|
// Offset
|
|
FlagStrings.ForceOffset,
|
|
FlagStrings.AudioSilenceThreshold,
|
|
FlagStrings.CorrectOffsetShift,
|
|
FlagStrings.OffsetShiftRelocate,
|
|
|
|
// Split
|
|
FlagStrings.ForceSplit,
|
|
FlagStrings.LeaveUnchanged,
|
|
FlagStrings.ForceQTOC,
|
|
FlagStrings.SkipFill,
|
|
FlagStrings.ISO9660Trim,
|
|
|
|
// Miscellaneous
|
|
FlagStrings.LBAStart,
|
|
FlagStrings.LBAEnd,
|
|
FlagStrings.RefineSubchannel,
|
|
FlagStrings.Skip,
|
|
FlagStrings.DumpWriteOffset,
|
|
FlagStrings.DumpReadSize,
|
|
FlagStrings.OverreadLeadout,
|
|
FlagStrings.ForceUnscrambled,
|
|
FlagStrings.LegacySubs,
|
|
FlagStrings.DisableCDText,
|
|
],
|
|
};
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
/// <remarks>
|
|
/// Redumper is unique in that the base command can be multiple
|
|
/// modes all listed together. It is also unique in that "all
|
|
/// flags are supported for everything" and it filters out internally
|
|
/// </remarks>
|
|
public override string GenerateParameters()
|
|
{
|
|
var parameters = new List<string>();
|
|
|
|
ModeValues ??= [CommandStrings.NONE];
|
|
|
|
// Modes
|
|
parameters.AddRange(ModeValues);
|
|
|
|
#region General
|
|
|
|
// Help
|
|
if (this[FlagStrings.HelpLong] == true)
|
|
parameters.Add(FlagStrings.HelpLong);
|
|
|
|
// Version
|
|
if (this[FlagStrings.Version] == true)
|
|
parameters.Add(FlagStrings.Version);
|
|
|
|
// Verbose
|
|
if (this[FlagStrings.Verbose] == true)
|
|
parameters.Add(FlagStrings.Verbose);
|
|
|
|
// Debug
|
|
if (this[FlagStrings.Debug] == true)
|
|
parameters.Add(FlagStrings.Debug);
|
|
|
|
// Drive
|
|
if (this[FlagStrings.Drive] == true)
|
|
{
|
|
if (DriveValue != null)
|
|
{
|
|
if (DriveValue.Contains(' '))
|
|
parameters.Add($"{FlagStrings.Drive}=\"{DriveValue}\"");
|
|
else
|
|
parameters.Add($"{FlagStrings.Drive}={DriveValue}");
|
|
}
|
|
}
|
|
|
|
// Speed
|
|
if (this[FlagStrings.Speed] == true)
|
|
{
|
|
if (SpeedValue != null)
|
|
parameters.Add($"{FlagStrings.Speed}={SpeedValue}");
|
|
}
|
|
|
|
// Retries
|
|
if (this[FlagStrings.Retries] == true)
|
|
{
|
|
if (RetriesValue != null)
|
|
parameters.Add($"{FlagStrings.Retries}={RetriesValue}");
|
|
}
|
|
|
|
// Image Path
|
|
if (this[FlagStrings.ImagePath] == true)
|
|
{
|
|
if (ImagePathValue != null)
|
|
parameters.Add($"{FlagStrings.ImagePath}={ImagePathValue}");
|
|
}
|
|
|
|
// Image Name
|
|
if (this[FlagStrings.ImageName] == true)
|
|
{
|
|
if (ImageNameValue != null)
|
|
parameters.Add($"{FlagStrings.ImageName}={ImageNameValue}");
|
|
}
|
|
|
|
// Overwrite
|
|
if (this[FlagStrings.Overwrite] == true)
|
|
parameters.Add(FlagStrings.Overwrite);
|
|
|
|
#endregion
|
|
|
|
#region Drive Configuration
|
|
|
|
// Drive Type
|
|
if (this[FlagStrings.DriveType] == true)
|
|
{
|
|
if (DriveTypeValue != null)
|
|
parameters.Add($"{FlagStrings.DriveType}={DriveTypeValue}");
|
|
}
|
|
|
|
// Drive Read Offset
|
|
if (this[FlagStrings.DriveReadOffset] == true)
|
|
{
|
|
if (DriveReadOffsetValue != null)
|
|
parameters.Add($"{FlagStrings.DriveReadOffset}={DriveReadOffsetValue}");
|
|
}
|
|
|
|
// Drive C2 Shift
|
|
if (this[FlagStrings.DriveC2Shift] == true)
|
|
{
|
|
if (DriveC2ShiftValue != null)
|
|
parameters.Add($"{FlagStrings.DriveC2Shift}={DriveC2ShiftValue}");
|
|
}
|
|
|
|
// Drive Pregap Start
|
|
if (this[FlagStrings.DrivePregapStart] == true)
|
|
{
|
|
if (DrivePregapStartValue != null)
|
|
parameters.Add($"{FlagStrings.DrivePregapStart}={DrivePregapStartValue}");
|
|
}
|
|
|
|
// Drive Read Method
|
|
if (this[FlagStrings.DriveReadMethod] == true)
|
|
{
|
|
if (DriveReadMethodValue != null)
|
|
parameters.Add($"{FlagStrings.DriveReadMethod}={DriveReadMethodValue}");
|
|
}
|
|
|
|
// Drive Sector Order
|
|
if (this[FlagStrings.DriveSectorOrder] == true)
|
|
{
|
|
if (DriveSectorOrderValue != null)
|
|
parameters.Add($"{FlagStrings.DriveSectorOrder}={DriveSectorOrderValue}");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Drive Specific
|
|
|
|
// Plextor Leadin Skip
|
|
if (this[FlagStrings.PlextorSkipLeadin] == true)
|
|
parameters.Add(FlagStrings.PlextorSkipLeadin);
|
|
|
|
// Plextor Leadin Retries
|
|
if (this[FlagStrings.PlextorLeadinRetries] == true)
|
|
{
|
|
if (PlextorLeadinRetriesValue != null)
|
|
parameters.Add($"{FlagStrings.PlextorLeadinRetries}={PlextorLeadinRetriesValue}");
|
|
}
|
|
|
|
// Asus Skip Leadout
|
|
if (this[FlagStrings.AsusSkipLeadout] == true)
|
|
parameters.Add(FlagStrings.AsusSkipLeadout);
|
|
|
|
#endregion
|
|
|
|
#region Offset
|
|
|
|
// Force Offset
|
|
if (this[FlagStrings.ForceOffset] == true)
|
|
{
|
|
if (ForceOffsetValue != null)
|
|
parameters.Add($"{FlagStrings.ForceOffset}={ForceOffsetValue}");
|
|
}
|
|
|
|
// Audio Silence Threshold
|
|
if (this[FlagStrings.AudioSilenceThreshold] == true)
|
|
{
|
|
if (AudioSilenceThresholdValue != null)
|
|
parameters.Add($"{FlagStrings.AudioSilenceThreshold}={AudioSilenceThresholdValue}");
|
|
}
|
|
|
|
// Correct Offset Shift
|
|
if (this[FlagStrings.CorrectOffsetShift] == true)
|
|
parameters.Add(FlagStrings.CorrectOffsetShift);
|
|
|
|
// Offset Shift Relocate
|
|
if (this[FlagStrings.OffsetShiftRelocate] == true)
|
|
parameters.Add(FlagStrings.OffsetShiftRelocate);
|
|
|
|
#endregion
|
|
|
|
#region Split
|
|
|
|
// Force Split
|
|
if (this[FlagStrings.ForceSplit] == true)
|
|
parameters.Add(FlagStrings.ForceSplit);
|
|
|
|
// Leave Unchanged
|
|
if (this[FlagStrings.LeaveUnchanged] == true)
|
|
parameters.Add(FlagStrings.LeaveUnchanged);
|
|
|
|
// Force QTOC
|
|
if (this[FlagStrings.ForceQTOC] == true)
|
|
parameters.Add(FlagStrings.ForceQTOC);
|
|
|
|
// Skip Fill
|
|
if (this[FlagStrings.SkipFill] == true)
|
|
{
|
|
if (SkipFillValue != null)
|
|
parameters.Add($"{FlagStrings.SkipFill}={SkipFillValue:x}");
|
|
}
|
|
|
|
// ISO9660 Trim
|
|
if (this[FlagStrings.ISO9660Trim] == true)
|
|
parameters.Add(FlagStrings.ISO9660Trim);
|
|
|
|
#endregion
|
|
|
|
#region Miscellaneous
|
|
|
|
// LBA Start
|
|
if (this[FlagStrings.LBAStart] == true)
|
|
{
|
|
if (LBAStartValue != null)
|
|
parameters.Add($"{FlagStrings.LBAStart}={LBAStartValue}");
|
|
}
|
|
|
|
// LBA End
|
|
if (this[FlagStrings.LBAEnd] == true)
|
|
{
|
|
if (LBAEndValue != null)
|
|
parameters.Add($"{FlagStrings.LBAEnd}={LBAEndValue}");
|
|
}
|
|
|
|
// Refine Subchannel
|
|
if (this[FlagStrings.RefineSubchannel] == true)
|
|
parameters.Add(FlagStrings.RefineSubchannel);
|
|
|
|
// Skip
|
|
if (this[FlagStrings.Skip] == true)
|
|
{
|
|
if (!string.IsNullOrEmpty(SkipValue))
|
|
parameters.Add($"{FlagStrings.Skip}={SkipValue}");
|
|
}
|
|
|
|
// Dump Write Offset
|
|
if (this[FlagStrings.DumpWriteOffset] == true)
|
|
{
|
|
if (DumpWriteOffsetValue != null)
|
|
parameters.Add($"{FlagStrings.DumpWriteOffset}={DumpWriteOffsetValue}");
|
|
}
|
|
|
|
// Dump Read Size
|
|
if (this[FlagStrings.DumpReadSize] == true)
|
|
{
|
|
if (DumpReadSizeValue != null && DumpReadSizeValue > 0)
|
|
parameters.Add($"{FlagStrings.DumpReadSize}={DumpReadSizeValue}");
|
|
}
|
|
|
|
// Overread Leadout
|
|
if (this[FlagStrings.OverreadLeadout] == true)
|
|
parameters.Add(FlagStrings.OverreadLeadout);
|
|
|
|
// Force Unscrambled
|
|
if (this[FlagStrings.ForceUnscrambled] == true)
|
|
parameters.Add(FlagStrings.ForceUnscrambled);
|
|
|
|
// Legacy Subs
|
|
if (this[FlagStrings.LegacySubs] == true)
|
|
parameters.Add(FlagStrings.LegacySubs);
|
|
|
|
// Disable CD Text
|
|
if (this[FlagStrings.DisableCDText] == true)
|
|
parameters.Add(FlagStrings.DisableCDText);
|
|
|
|
#endregion
|
|
|
|
return string.Join(" ", [.. parameters]);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override string? GetDefaultExtension(MediaType? mediaType) => Converters.Extension(mediaType);
|
|
|
|
/// <inheritdoc/>
|
|
public override MediaType? GetMediaType() => null;
|
|
|
|
/// <inheritdoc/>
|
|
public override bool IsDumpingCommand()
|
|
{
|
|
return this.BaseCommand == CommandStrings.NONE
|
|
|| this.BaseCommand?.Contains(CommandStrings.CD) == true
|
|
|| this.BaseCommand?.Contains(CommandStrings.DVD) == true
|
|
|| this.BaseCommand?.Contains(CommandStrings.BluRay) == true
|
|
|| this.BaseCommand?.Contains(CommandStrings.SACD) == true
|
|
|| this.BaseCommand?.Contains(CommandStrings.New) == true
|
|
|| this.BaseCommand?.Contains(CommandStrings.Dump) == true
|
|
|| this.BaseCommand?.Contains(CommandStrings.DumpNew) == true;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void ResetValues()
|
|
{
|
|
BaseCommand = CommandStrings.NONE;
|
|
|
|
flags = [];
|
|
|
|
// General
|
|
DriveValue = null;
|
|
SpeedValue = null;
|
|
RetriesValue = null;
|
|
ImagePathValue = null;
|
|
ImageNameValue = null;
|
|
|
|
// Drive Configuration
|
|
DriveTypeValue = null;
|
|
DriveReadOffsetValue = null;
|
|
DriveC2ShiftValue = null;
|
|
DrivePregapStartValue = null;
|
|
DriveReadMethodValue = null;
|
|
DriveSectorOrderValue = null;
|
|
|
|
// Offset
|
|
ForceOffsetValue = null;
|
|
AudioSilenceThresholdValue = null;
|
|
|
|
// Split
|
|
SkipFillValue = null;
|
|
|
|
// Miscellaneous
|
|
LBAStartValue = null;
|
|
LBAEndValue = null;
|
|
SkipValue = null;
|
|
DumpReadSizeValue = null;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void SetDefaultParameters(string? drivePath, string filename, int? driveSpeed, Dictionary<string, string?> options)
|
|
{
|
|
// If we don't have a CD, DVD, HD-DVD, or BD, we can't dump using redumper
|
|
if (this.Type != MediaType.CDROM
|
|
&& this.Type != MediaType.DVD
|
|
&& this.Type != MediaType.HDDVD
|
|
&& this.Type != MediaType.BluRay)
|
|
{
|
|
return;
|
|
}
|
|
|
|
BaseCommand = CommandStrings.NONE;
|
|
switch (this.Type)
|
|
{
|
|
case MediaType.CDROM:
|
|
ModeValues = this.System switch
|
|
{
|
|
RedumpSystem.SuperAudioCD => [CommandStrings.SACD],
|
|
_ => [CommandStrings.CD],
|
|
};
|
|
break;
|
|
case MediaType.DVD:
|
|
ModeValues = [CommandStrings.DVD];
|
|
break;
|
|
case MediaType.HDDVD: // TODO: Keep in sync if another command string shows up
|
|
ModeValues = [CommandStrings.DVD];
|
|
break;
|
|
case MediaType.BluRay:
|
|
ModeValues = [CommandStrings.BluRay];
|
|
break;
|
|
default:
|
|
BaseCommand = null;
|
|
return;
|
|
}
|
|
|
|
this[FlagStrings.Drive] = true;
|
|
DriveValue = drivePath;
|
|
|
|
this[FlagStrings.Speed] = true;
|
|
SpeedValue = driveSpeed;
|
|
|
|
// Set user-defined options
|
|
if (GetBooleanSetting(options, SettingConstants.EnableVerbose, SettingConstants.EnableVerboseDefault))
|
|
this[FlagStrings.Verbose] = true;
|
|
if (GetBooleanSetting(options, SettingConstants.EnableDebug, SettingConstants.EnableDebugDefault))
|
|
this[FlagStrings.Debug] = true;
|
|
|
|
string? readMethod = GetStringSetting(options, SettingConstants.ReadMethod, SettingConstants.ReadMethodDefault);
|
|
|
|
if (!string.IsNullOrEmpty(readMethod) && readMethod != ReadMethod.NONE.ToString())
|
|
{
|
|
this[FlagStrings.DriveReadMethod] = true;
|
|
DriveReadMethodValue = readMethod;
|
|
}
|
|
|
|
string? sectorOrder = GetStringSetting(options, SettingConstants.SectorOrder, SettingConstants.SectorOrderDefault);
|
|
if (!string.IsNullOrEmpty(sectorOrder) && sectorOrder != SectorOrder.NONE.ToString())
|
|
{
|
|
this[FlagStrings.DriveSectorOrder] = true;
|
|
DriveSectorOrderValue = sectorOrder;
|
|
}
|
|
|
|
if (GetBooleanSetting(options, SettingConstants.UseGenericDriveType, SettingConstants.UseGenericDriveTypeDefault))
|
|
{
|
|
this[FlagStrings.DriveType] = true;
|
|
DriveTypeValue = "GENERIC";
|
|
}
|
|
|
|
// Set the output paths
|
|
if (!string.IsNullOrEmpty(filename))
|
|
{
|
|
var imagePath = Path.GetDirectoryName(filename);
|
|
if (!string.IsNullOrEmpty(imagePath))
|
|
{
|
|
this[FlagStrings.ImagePath] = true;
|
|
ImagePathValue = $"\"{imagePath}\"";
|
|
}
|
|
|
|
string imageName = Path.GetFileNameWithoutExtension(filename);
|
|
if (!string.IsNullOrEmpty(imageName))
|
|
{
|
|
this[FlagStrings.ImageName] = true;
|
|
ImageNameValue = $"\"{imageName}\"";
|
|
}
|
|
}
|
|
|
|
this[FlagStrings.Retries] = true;
|
|
RetriesValue = GetInt32Setting(options, SettingConstants.RereadCount, SettingConstants.RereadCountDefault);
|
|
|
|
if (GetBooleanSetting(options, SettingConstants.EnableLeadinRetry, SettingConstants.EnableLeadinRetryDefault))
|
|
{
|
|
this[FlagStrings.PlextorLeadinRetries] = true;
|
|
PlextorLeadinRetriesValue = GetInt32Setting(options, SettingConstants.LeadinRetryCount, SettingConstants.LeadinRetryCountDefault);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override bool ValidateAndSetParameters(string? parameters)
|
|
{
|
|
BaseCommand = CommandStrings.NONE;
|
|
|
|
// The string has to be valid by itself first
|
|
if (string.IsNullOrEmpty(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, @"([a-zA-Z\-]*=)?[\""].+?[\""]|[^ ]+", RegexOptions.Compiled)
|
|
.Cast<Match>()
|
|
.Select(m => m.Value)
|
|
.ToList();
|
|
|
|
// Setup the modes
|
|
ModeValues = [];
|
|
|
|
// All modes should be cached separately
|
|
int index = 0;
|
|
for (; index < parts.Count; index++)
|
|
{
|
|
// Flag to see if we have a flag
|
|
bool isFlag = false;
|
|
|
|
string part = parts[index];
|
|
switch (part)
|
|
{
|
|
case CommandStrings.CD:
|
|
case CommandStrings.DVD:
|
|
case CommandStrings.BluRay:
|
|
case CommandStrings.SACD:
|
|
case CommandStrings.New: // Temporary command, to be removed later
|
|
case CommandStrings.Rings:
|
|
case CommandStrings.Dump:
|
|
case CommandStrings.DumpNew: // Temporary command, to be removed later
|
|
case CommandStrings.Refine:
|
|
case CommandStrings.RefineNew: // Temporary command, to be removed later
|
|
case CommandStrings.Verify:
|
|
case CommandStrings.DVDKey:
|
|
case CommandStrings.DVDIsoKey:
|
|
case CommandStrings.Protection:
|
|
case CommandStrings.Split:
|
|
case CommandStrings.Hash:
|
|
case CommandStrings.Info:
|
|
case CommandStrings.Skeleton:
|
|
ModeValues.Add(part);
|
|
break;
|
|
|
|
// Default is either a flag or an invalid mode
|
|
default:
|
|
if (part.StartsWith("-"))
|
|
{
|
|
isFlag = true;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// If we had a flag, break out
|
|
if (isFlag)
|
|
break;
|
|
}
|
|
|
|
// Loop through all auxiliary flags, if necessary
|
|
for (int i = index; i < parts.Count; i++)
|
|
{
|
|
// Flag read-out values
|
|
byte? byteValue = null;
|
|
int? intValue = null;
|
|
string? stringValue = null;
|
|
|
|
#region General
|
|
|
|
// Help
|
|
ProcessFlagParameter(parts, FlagStrings.HelpShort, FlagStrings.HelpLong, ref i);
|
|
|
|
// Version
|
|
ProcessFlagParameter(parts, FlagStrings.Version, ref i);
|
|
|
|
// Verbose
|
|
ProcessFlagParameter(parts, FlagStrings.Verbose, ref i);
|
|
|
|
// Debug
|
|
ProcessFlagParameter(parts, FlagStrings.Debug, ref i);
|
|
|
|
// Drive
|
|
stringValue = ProcessStringParameter(parts, FlagStrings.Drive, ref i);
|
|
if (!string.IsNullOrEmpty(stringValue))
|
|
DriveValue = stringValue;
|
|
|
|
// Speed
|
|
intValue = ProcessInt32Parameter(parts, FlagStrings.Speed, ref i);
|
|
if (intValue != null && intValue != Int32.MinValue)
|
|
SpeedValue = intValue;
|
|
|
|
// Retries
|
|
intValue = ProcessInt32Parameter(parts, FlagStrings.Retries, ref i);
|
|
if (intValue != null && intValue != Int32.MinValue)
|
|
RetriesValue = intValue;
|
|
|
|
// Image Path
|
|
stringValue = ProcessStringParameter(parts, FlagStrings.ImagePath, ref i);
|
|
if (!string.IsNullOrEmpty(stringValue))
|
|
ImagePathValue = $"\"{stringValue!.Trim('"')}\"";
|
|
|
|
// Image Name
|
|
stringValue = ProcessStringParameter(parts, FlagStrings.ImageName, ref i);
|
|
if (!string.IsNullOrEmpty(stringValue))
|
|
ImageNameValue = $"\"{stringValue!.Trim('"')}\"";
|
|
|
|
// Overwrite
|
|
ProcessFlagParameter(parts, FlagStrings.Overwrite, ref i);
|
|
|
|
#endregion
|
|
|
|
#region Drive Configuration
|
|
|
|
// Drive Type
|
|
stringValue = ProcessStringParameter(parts, FlagStrings.DriveType, ref i);
|
|
if (!string.IsNullOrEmpty(stringValue))
|
|
DriveTypeValue = stringValue;
|
|
|
|
// Drive Read Offset
|
|
intValue = ProcessInt32Parameter(parts, FlagStrings.DriveReadOffset, ref i);
|
|
if (intValue != null && intValue != Int32.MinValue)
|
|
DriveReadOffsetValue = intValue;
|
|
|
|
// Drive C2 Shift
|
|
intValue = ProcessInt32Parameter(parts, FlagStrings.DriveC2Shift, ref i);
|
|
if (intValue != null && intValue != Int32.MinValue)
|
|
DriveC2ShiftValue = intValue;
|
|
|
|
// Drive Pregap Start
|
|
intValue = ProcessInt32Parameter(parts, FlagStrings.DrivePregapStart, ref i);
|
|
if (intValue != null && intValue != Int32.MinValue)
|
|
DrivePregapStartValue = intValue;
|
|
|
|
// Drive Read Method
|
|
stringValue = ProcessStringParameter(parts, FlagStrings.DriveReadMethod, ref i);
|
|
if (!string.IsNullOrEmpty(stringValue))
|
|
DriveReadMethodValue = stringValue;
|
|
|
|
// Drive Sector Order
|
|
stringValue = ProcessStringParameter(parts, FlagStrings.DriveSectorOrder, ref i);
|
|
if (!string.IsNullOrEmpty(stringValue))
|
|
DriveSectorOrderValue = stringValue;
|
|
|
|
#endregion
|
|
|
|
#region Drive Specific
|
|
|
|
// Plextor Skip Leadin
|
|
ProcessFlagParameter(parts, FlagStrings.PlextorSkipLeadin, ref i);
|
|
|
|
// Plextor Leadin Retries
|
|
intValue = ProcessInt32Parameter(parts, FlagStrings.PlextorLeadinRetries, ref i);
|
|
if (intValue != null && intValue != Int32.MinValue)
|
|
PlextorLeadinRetriesValue = intValue;
|
|
|
|
// Asus Skip Leadout
|
|
ProcessFlagParameter(parts, FlagStrings.AsusSkipLeadout, ref i);
|
|
|
|
#endregion
|
|
|
|
#region Offset
|
|
|
|
// Force Offset
|
|
intValue = ProcessInt32Parameter(parts, FlagStrings.ForceOffset, ref i);
|
|
if (intValue != null && intValue != Int32.MinValue)
|
|
ForceOffsetValue = intValue;
|
|
|
|
// Audio Silence Threshold
|
|
intValue = ProcessInt32Parameter(parts, FlagStrings.AudioSilenceThreshold, ref i);
|
|
if (intValue != null && intValue != Int32.MinValue)
|
|
AudioSilenceThresholdValue = intValue;
|
|
|
|
// Correct Offset Shift
|
|
ProcessFlagParameter(parts, FlagStrings.CorrectOffsetShift, ref i);
|
|
|
|
// Correct Shift Relocate
|
|
ProcessFlagParameter(parts, FlagStrings.OffsetShiftRelocate, ref i);
|
|
|
|
#endregion
|
|
|
|
#region Split
|
|
|
|
// Force Split
|
|
ProcessFlagParameter(parts, FlagStrings.ForceSplit, ref i);
|
|
|
|
// Leave Unchanged
|
|
ProcessFlagParameter(parts, FlagStrings.LeaveUnchanged, ref i);
|
|
|
|
// Force QTOC
|
|
ProcessFlagParameter(parts, FlagStrings.ForceQTOC, ref i);
|
|
|
|
// Skip Fill
|
|
byteValue = ProcessUInt8Parameter(parts, FlagStrings.SkipFill, ref i);
|
|
if (byteValue != null && byteValue != Byte.MinValue)
|
|
SkipFillValue = byteValue;
|
|
|
|
// ISO9660 Trim
|
|
ProcessFlagParameter(parts, FlagStrings.ISO9660Trim, ref i);
|
|
|
|
#endregion
|
|
|
|
#region Miscellaneous
|
|
|
|
// LBA Start
|
|
intValue = ProcessInt32Parameter(parts, FlagStrings.LBAStart, ref i);
|
|
if (intValue != null && intValue != Int32.MinValue)
|
|
LBAStartValue = intValue;
|
|
|
|
// LBA End
|
|
intValue = ProcessInt32Parameter(parts, FlagStrings.LBAEnd, ref i);
|
|
if (intValue != null && intValue != Int32.MinValue)
|
|
LBAEndValue = intValue;
|
|
|
|
// Refine Subchannel
|
|
ProcessFlagParameter(parts, FlagStrings.RefineSubchannel, ref i);
|
|
|
|
// Skip
|
|
stringValue = ProcessStringParameter(parts, FlagStrings.Skip, ref i);
|
|
if (!string.IsNullOrEmpty(stringValue))
|
|
SkipValue = stringValue;
|
|
|
|
// Dump Write Offset
|
|
intValue = ProcessInt32Parameter(parts, FlagStrings.DumpWriteOffset, ref i);
|
|
if (intValue != null && intValue != Int32.MinValue)
|
|
DumpWriteOffsetValue = intValue;
|
|
|
|
// Dump Read Size
|
|
intValue = ProcessInt32Parameter(parts, FlagStrings.DumpReadSize, ref i);
|
|
if (intValue != null && intValue != Int32.MinValue)
|
|
DumpReadSizeValue = intValue;
|
|
|
|
// Overread Leadout
|
|
ProcessFlagParameter(parts, FlagStrings.OverreadLeadout, ref i);
|
|
|
|
// Force Unscrambled
|
|
ProcessFlagParameter(parts, FlagStrings.ForceUnscrambled, ref i);
|
|
|
|
// Legacy Subs
|
|
ProcessFlagParameter(parts, FlagStrings.LegacySubs, ref i);
|
|
|
|
// Disable CD Text
|
|
ProcessFlagParameter(parts, FlagStrings.DisableCDText, ref i);
|
|
|
|
#endregion
|
|
}
|
|
|
|
// If the image name was not set, set it with a default value
|
|
if (string.IsNullOrEmpty(this.ImageNameValue))
|
|
this.ImageNameValue = "track";
|
|
|
|
return true;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|