Compare commits

..

139 Commits
3.3.2 ... 3.5.0

Author SHA1 Message Date
Matt Nadareski
9012ff85a9 Bump version 2025-10-10 08:44:07 -04:00
Matt Nadareski
ccc33bebbd Try to handle Windows-specific compression issue 2025-10-10 08:09:49 -04:00
Matt Nadareski
57b07aee02 Support detecting split Wii for CleanRip 2025-10-09 15:35:38 -04:00
Matt Nadareski
069d676492 Fix test broken by last commit 2025-10-09 15:05:57 -04:00
Matt Nadareski
a26dfb7e7a Enable skeleton output for all CLI runs 2025-10-09 12:06:16 -04:00
Matt Nadareski
a9ea457808 Use block-based reading instead of CopyTo 2025-10-09 10:31:59 -04:00
Matt Nadareski
41bc410452 Pre-compress state files with Zstd 2025-10-09 10:01:24 -04:00
Matt Nadareski
bbfdf462d0 Fix broken file count tests 2025-10-08 12:54:18 -04:00
Matt Nadareski
5a1d51c05f Pre-compress skeleton files with Zstd 2025-10-08 12:48:50 -04:00
Matt Nadareski
16e80f75cf Add preemptive helper for Zstd handling 2025-10-08 12:04:04 -04:00
Matt Nadareski
2a6e066707 Add preemptive new file support 2025-10-08 11:53:19 -04:00
Matt Nadareski
d6102107fb Only allow skeleton creation for CD and DVD
This was a hard decision to limit again, but with the inability to make Zstd the default for log compression, this is not a reasonable thing to enable for most users.
2025-10-08 11:31:12 -04:00
Matt Nadareski
79163dcb35 Fix default value tests 2025-10-08 11:15:16 -04:00
Matt Nadareski
c1aa863c91 Allow skeleton creation for all media types 2025-10-08 11:10:13 -04:00
Matt Nadareski
dbd4b55dda Use ZipWriterOptions instead of generic 2025-10-08 10:59:51 -04:00
Matt Nadareski
1f58521f51 Fix incorrect flagging of a failed check 2025-10-08 10:54:20 -04:00
Matt Nadareski
4da1ab9c29 Guard against unzippable files 2025-10-08 10:35:28 -04:00
Matt Nadareski
5771add8c0 Revert "Use Deflate64 instead of Deflate for compression"
This reverts commit 977a71d9cf.
2025-10-08 10:20:10 -04:00
Matt Nadareski
977a71d9cf Use Deflate64 instead of Deflate for compression 2025-10-08 09:59:41 -04:00
Matt Nadareski
b2d09d04ea Use null or empty instead of just null 2025-10-08 09:49:22 -04:00
Matt Nadareski
78df92e5d3 More gracefully handle "missing" media types 2025-10-08 09:29:34 -04:00
Matt Nadareski
9770b7c917 Add more useful credentials inputs for Check 2025-10-07 20:37:11 -04:00
Matt Nadareski
1ddb287977 Minor cleanup on interactive modes 2025-10-07 20:27:22 -04:00
Matt Nadareski
b9e4bbf744 Finalize wire-through and clean up 2025-10-07 19:43:34 -04:00
Matt Nadareski
08829ed811 Fix minor issues with options loading 2025-10-07 18:27:12 -04:00
Matt Nadareski
bf181e2294 Start wiring through log compression changes 2025-10-07 18:07:46 -04:00
Matt Nadareski
49571c6bfc Use GC.SharpCompress as archive handling library 2025-10-07 17:33:01 -04:00
Matt Nadareski
9a0bc868f8 More consistency in commandline programs 2025-10-07 16:40:30 -04:00
Matt Nadareski
bc2c08690d Update packages 2025-10-07 16:21:02 -04:00
Matt Nadareski
493cb80624 Allow but do not require config for Check 2025-10-07 15:19:50 -04:00
Matt Nadareski
49b8ecf6c3 Fix minor typo in verify inputs check 2025-10-06 18:05:14 -04:00
Matt Nadareski
c9b7ad7819 Exit early on parsing failures 2025-10-06 17:53:15 -04:00
Matt Nadareski
fe76387f6a Remove CommandOptions implementations 2025-10-06 17:49:16 -04:00
Matt Nadareski
0a60fe5a37 Fix strange invocations of extension methods 2025-10-06 16:37:28 -04:00
Matt Nadareski
baffdb8b29 Remove duplicate input declarations 2025-10-06 16:34:19 -04:00
Matt Nadareski
4a3c585a8d Assign inputs for interactive modes 2025-10-06 16:25:41 -04:00
Matt Nadareski
1ee7ea1948 Create and use base feature in CLI 2025-10-06 16:13:51 -04:00
Matt Nadareski
ee08bfe0fc Create and use base feature in Check 2025-10-06 16:06:23 -04:00
Matt Nadareski
896caec9cd Create and use main features for CLI and Check 2025-10-06 15:54:14 -04:00
Matt Nadareski
68932ab473 Reduce unnecessary shared code 2025-10-06 15:25:11 -04:00
Matt Nadareski
d105d04146 Add placeholder command set creation 2025-10-06 11:01:25 -04:00
Matt Nadareski
7023c78d40 Minor cleanup around last added 2025-10-06 10:34:11 -04:00
Matt Nadareski
81156a3c63 Create interactive mode features 2025-10-06 10:32:16 -04:00
Matt Nadareski
7b2b06a36f Use CommandLine library for CLI executables 2025-10-06 10:11:44 -04:00
Matt Nadareski
3f974ab336 Update packages 2025-10-05 17:41:38 -04:00
Matt Nadareski
b238616685 Rename log zip on collision 2025-10-04 20:49:56 -04:00
Matt Nadareski
2984459823 Tweaks to how failure cases are reported 2025-10-04 18:57:25 -04:00
Matt Nadareski
ce979b3c3f Add failure if media type could not be determined 2025-10-02 22:06:22 -04:00
Matt Nadareski
cb8e1fd34b Bump version 2025-09-30 12:02:06 -04:00
Matt Nadareski
cc148735f8 Require exact versions for build 2025-09-30 11:18:59 -04:00
Matt Nadareski
8238d14f7b Fix missed package update 2025-09-30 10:55:57 -04:00
Matt Nadareski
a56676501e Fix starting index for CLI 2025-09-29 22:43:33 -04:00
Matt Nadareski
79716ea0b5 Bump version 2025-09-29 17:54:03 -04:00
Matt Nadareski
43477a133f Update BinaryObjectScanner to 3.4.3 2025-09-29 14:30:52 -04:00
Matt Nadareski
8889beef1d Reduction in media type use for dumping 2025-09-29 11:25:57 -04:00
Matt Nadareski
ac4be751b3 Make media type a named parameter for CLI 2025-09-29 10:56:56 -04:00
Matt Nadareski
69f855fc93 Fix tests 2025-09-29 10:45:53 -04:00
Matt Nadareski
cf01095623 Skip trying to set speeds if no drives 2025-09-29 10:43:12 -04:00
Matt Nadareski
3236223e3f Default to CD speed range 2025-09-29 10:40:59 -04:00
Matt Nadareski
36450cd22b Minor tweaks to frontend code 2025-09-29 10:25:24 -04:00
Deterous
6a9b6748d2 Remove SkipMediaTypeDetection option, cleanup options window (#895)
* Remove SkipMediaTypeDetection option, cleanup options window

* Shrink detection section in options

* always try to guess media type
2025-09-26 10:56:25 -04:00
Matt Nadareski
3bf83378a2 Fix logic from around Macrovision security driver filtering (fixes #811) 2025-09-25 11:38:03 -04:00
Matt Nadareski
bc938fd58c Return full result from dump checks 2025-09-25 10:54:29 -04:00
Matt Nadareski
f50a110acd Update media type visibility on system change 2025-09-25 09:26:11 -04:00
Matt Nadareski
fcda2a6e3b Change label with media type visibility 2025-09-25 09:07:41 -04:00
Matt Nadareski
d33526b27e Set media type visibility when options changed 2025-09-25 08:56:06 -04:00
Matt Nadareski
0b0427e9c1 Limit media type visibility further 2025-09-25 08:54:33 -04:00
Matt Nadareski
c34b92bad8 Default media type box to hidden to avoid visual issues 2025-09-25 08:49:04 -04:00
Matt Nadareski
89145df0fa Experiment with only showing media type box for DIC 2025-09-25 08:32:06 -04:00
Matt Nadareski
ee7cde6360 Bump version 2025-09-25 08:05:10 -04:00
Matt Nadareski
8e9edf43ac Update RedumpLib to 1.7.4 2025-09-24 13:41:27 -04:00
Matt Nadareski
51115430cb Update BinaryObjectScanner to 3.4.2 2025-09-24 13:20:29 -04:00
Matt Nadareski
7cf108828e Update changelog 2025-09-22 15:33:55 -04:00
Matt Nadareski
020390af65 Cleanup last commits, add tests 2025-09-22 15:30:48 -04:00
HeroponRikiBestest
e04ceb953c Add filters to handle Release Control output. (#892)
* Add filters to handle matroschka output.

* Apply RC-contained filtering to new framework

* Attempt to refine logic to fit framework
2025-09-22 15:23:24 -04:00
Matt Nadareski
363b018cb7 Further flesh out framework 2025-09-22 13:44:21 -04:00
Matt Nadareski
cf025522ef Add context-sensitive protections helper method 2025-09-22 13:41:11 -04:00
Matt Nadareski
0fb8bf5c29 Update BinaryObjectScanner to 3.4.0 2025-09-22 10:15:40 -04:00
Matt Nadareski
e280745eee Add RedumperRefineSectorMode setting (fixes #890) 2025-09-18 08:27:42 -04:00
fuzzball
fb306750e6 Support new versioning format in redumper (#889)
* Support new versioning format

* Update changelist
2025-09-16 07:13:54 -04:00
Deterous
da5a514482 Update redumper to build 655 (#888) 2025-09-12 07:35:01 -04:00
Deterous
fc288e1c46 Update RedumpLib, detect Playmaji Polymega system (#886)
* Update RedumpLib, detect Playmaji Polymega system

* Update libs for Processors

* Add IO and Matching to Processors csproj
2025-09-05 11:09:22 -04:00
Deterous
102acb9ebf Fix UIC processing logic (#885)
* Fix UIC title field

* the sabre approved way

* Better UIC test_disc.txt

* Fix UIC category logic

* Fix GetUMDCategoryTest

* Final test tweak
2025-09-04 08:27:13 -04:00
Deterous
b76b2a69f5 Update DIC to 20250901 (Windows/Linux only) (#884) 2025-09-02 07:24:07 -04:00
Deterous
254ad6cfd0 Support multisession cache files (#882)
* redumper multisession .cache

* Changelist

* Fix tests
2025-08-25 08:00:34 -04:00
Matt Nadareski
f432f438ab Update RedumpLib to 1.7.1 2025-08-23 09:58:16 -04:00
Matt Nadareski
e890243830 Update test Nuget packages 2025-08-23 09:56:25 -04:00
Matt Nadareski
6493b462f1 Minor cleanup 2025-08-23 09:47:17 -04:00
Deterous
54c0716ea9 Update redumper to build 653 (#880)
* Update redumper to build 653

* nit
2025-08-23 08:43:35 -04:00
Matt Nadareski
7fbb5133d7 Update LibIRD 2025-08-19 10:41:53 -04:00
Matt Nadareski
993a0fd7d3 Update RedumpLib and LibIRD 2025-08-19 07:23:02 -04:00
fuzzball
47878fee1f Fix for C2 error doubling issue (#877)
* Expand error detection

* Update changelist

---------

Co-authored-by: Matt Nadareski <mnadareski@outlook.com>
2025-08-15 10:37:15 -04:00
Matt Nadareski
4cb8a31505 Update Aaru to build 5.4.1 (fixes #879) 2025-08-14 09:02:25 -04:00
Matt Nadareski
0685972842 Fix inconsistency with newlines 2025-07-23 11:49:54 -04:00
Matt Nadareski
5b1cc3c715 Add CopyUpdateUrlToClipboard option 2025-07-23 07:51:18 -04:00
Matt Nadareski
572f0d5095 Treat all UMD as DL visually 2025-07-22 14:57:03 -04:00
Matt Nadareski
23bafad3db Update RedumpLib to 1.6.9 2025-07-21 12:14:37 -04:00
Matt Nadareski
c7b77e4bd7 Reduce preprocessing in DumpEnvironment 2025-07-19 12:36:03 -04:00
Matt Nadareski
755eee4441 Put a try/catch around GenerateArtifacts 2025-07-19 12:25:20 -04:00
Matt Nadareski
fca2c53d6c Let the processor always deal with unsupported 2025-07-19 09:06:28 -04:00
Matt Nadareski
8f6f5f6ef0 UI consistency when parameters are editable (fixes #876) 2025-07-18 15:09:21 -04:00
Matt Nadareski
2e9970ee6a Always trust the output files for processing 2025-07-18 13:20:45 -04:00
Matt Nadareski
4fa1273111 Remove media type from Check Dump UI 2025-07-18 13:15:40 -04:00
Matt Nadareski
d3993a48e4 Bump version 2025-07-18 08:20:54 -04:00
Deterous
d522bb6c76 Update redumper to build 631 (#875)
* Update redumper to build 631

* add flag to tests
2025-07-16 08:04:27 -04:00
Matt Nadareski
816672a817 Slightly better IRD organization 2025-07-15 13:06:05 -04:00
Matt Nadareski
f8171da306 Better handle mixed-separator paths 2025-07-15 08:00:55 -04:00
Matt Nadareski
ce073e5fbf Simplify code from previous commit 2025-07-14 13:13:25 -04:00
Matt Nadareski
28205e42f0 Strip errant whitespace during path normalization (fixes #874) 2025-07-14 12:58:44 -04:00
Matt Nadareski
0160366530 Add new help and version flags for CLI and Check (fixes #873) 2025-07-12 16:04:54 -04:00
Matt Nadareski
663477d408 Update RedumpLib to 1.6.8 (fixes #872) 2025-07-11 12:49:12 -04:00
Matt Nadareski
bd2e012eef Net Yaroze only for PS1 2025-07-11 12:09:06 -04:00
Matt Nadareski
a514374169 Remove legacy codes from info window (fixes #871) 2025-07-11 12:05:03 -04:00
Matt Nadareski
f73c0730e2 Update changelog 2025-07-09 07:23:38 -04:00
fuzzball
a658c80de7 Empty should be null (#868) 2025-07-09 07:23:09 -04:00
Matt Nadareski
b806bc6cd1 Fix unnecessary null assignment 2025-06-26 10:35:47 -04:00
Matt Nadareski
cf9675f620 Only use serial for PS3/4/5 if no custom volume label 2025-06-26 10:34:49 -04:00
Matt Nadareski
ea18051709 Swap PS1/2 back to original name handling 2025-06-26 08:38:46 -04:00
Matt Nadareski
4fdf8e5dde Use reasonable default names for PlayStation systems (fixes #866) 2025-06-26 08:30:14 -04:00
Deterous
a4616d139d Better handling of Xbox/360, redumper build 613 (#865)
* Better handling of bad SS, redumper build 613

* Add missing helper function

* Fix new func signature

* Fix var name

* Nulls

* Don't get vollabel for xbox/360

* formatting

* formatting v2
2025-06-23 21:03:42 -04:00
Matt Nadareski
0f09a9c913 Address nullable default value 2025-06-18 09:40:00 -04:00
Matt Nadareski
48ffd6f40c Set some default values for CLI (fixes #863) 2025-06-18 09:34:35 -04:00
Matt Nadareski
6612c8ea4d Remove dead code in DIC processor 2025-06-18 09:13:44 -04:00
Matt Nadareski
68d1a0664a IsAudio cleanup cleanup 2025-06-18 09:08:37 -04:00
Matt Nadareski
86d8590789 IsAudio cleanup 2025-06-18 08:52:51 -04:00
Matt Nadareski
e23427d7c9 Update redumper to build 611 2025-06-17 21:00:52 -04:00
Matt Nadareski
cd19a2e4a0 Use the correct base path for Check 2025-06-17 17:55:10 -04:00
Matt Nadareski
000e7d88a8 Fix start index in Check 2025-06-17 17:18:12 -04:00
Matt Nadareski
e3beb1ef77 Rename disc info to media info 2025-06-17 16:35:03 -04:00
Matt Nadareski
a3a75b1c2d Fix missed test updates 2025-06-17 15:52:48 -04:00
Matt Nadareski
11850a8d6b Enable Check to determine media type automatically 2025-06-17 15:36:23 -04:00
Matt Nadareski
bf6b58d64b Fill out DetermineMediaType for DiscImageCreator 2025-06-17 14:26:13 -04:00
Matt Nadareski
1789334625 Fill out DetermineMediaType for Aaru 2025-06-17 13:05:35 -04:00
Matt Nadareski
9520f58240 Fill out DetermineMediaType for Redumper 2025-06-17 11:37:37 -04:00
Matt Nadareski
48e5e01729 Add DetermineMediaType scaffolding and tests 2025-06-17 09:45:16 -04:00
Matt Nadareski
8c7959fb08 Reduce media-specific checks where unnecessary 2025-06-17 08:51:57 -04:00
Matt Nadareski
8ef7543cf1 Ignore volume labels with path separators 2025-06-16 09:26:56 -04:00
Matt Nadareski
f9e39ee4be Further clarify configuration requirements for CLI (fixes #861) 2025-06-16 07:43:51 -04:00
Matt Nadareski
0a4621c963 Handle layers for PS3CFW (fixes #859) 2025-06-13 20:35:32 -04:00
96 changed files with 5335 additions and 2845 deletions

View File

@@ -1,3 +1,148 @@
### 3.5.0 (2025-10-10)
- Add failure if media type could not be determined
- Tweaks to how failure cases are reported
- Rename log zip on collision
- Update packages
- Use CommandLine library for CLI executables
- Create interactive mode features
- Minor cleanup around last added
- Add placeholder command set creation
- Reduce unnecessary shared code
- Create and use main features for CLI and Check
- Create and use base feature in Check
- Create and use base feature in CLI
- Assign inputs for interactive modes
- Remove duplicate input declarations
- Fix strange invocations of extension methods
- Remove CommandOptions implementations
- Exit early on parsing failures
- Fix minor typo in verify inputs check
- Allow but do not require config for Check
- Update packages
- More consistency in commandline programs
- Use GC.SharpCompress as archive handling library
- Start wiring through log compression changes
- Fix minor issues with options loading
- Finalize wire-through and clean up
- Minor cleanup on interactive modes
- Add more useful credentials inputs for Check
- More gracefully handle "missing" media types
- Use null or empty instead of just null
- Guard against unzippable files
- Fix incorrect flagging of a failed check
- Use ZipWriterOptions instead of generic
- Allow skeleton creation for all media types
- Fix default value tests
- Only allow skeleton creation for CD and DVD
- Add preemptive new file support
- Add preemptive helper for Zstd handling
- Pre-compress skeleton files with Zstd
- Fix broken file count tests
- Pre-compress state files with Zstd
- Use block-based reading instead of CopyTo
- Enable skeleton output for all CLI runs
- Fix test broken by last commit
- Support detecting split Wii for CleanRip
- Try to handle Windows-specific compression issue
### 3.4.2 (2025-09-30)
- Fix starting index for CLI
- Fix missed package update
- Require exact versions for build
### 3.4.1 (2025-09-29)
- Experiment with only showing media type box for DIC
- Default media type box to hidden to avoid visual issues
- Limit media type visibility further
- Set media type visibility when options changed
- Change label with media type visibility
- Update media type visibility on system change
- Return full result from dump checks
- Fix logic from around Macrovision security driver filtering
- Remove SkipMediaTypeDetection option, cleanup options window
- Minor tweaks to frontend code
- Default to CD speed range
- Skip trying to set speeds if no drives
- Fix tests
- Make media type a named parameter for CLI
- Reduction in media type use for dumping
- Update BinaryObjectScanner to 3.4.3
### 3.4.0 (2025-09-25)
- Remove media type from Check Dump UI
- Always trust the output files for processing
- UI consistency when parameters are editable
- Let the processor always deal with unsupported
- Put a try/catch around GenerateArtifacts
- Reduce preprocessing in DumpEnvironment
- Update RedumpLib to 1.6.9
- Treat all UMD as DL visually
- Add CopyUpdateUrlToClipboard option
- Fix inconsistency with newlines
- Update Aaru to build 5.4.1
- Fix for C2 error doubling issue (fuzz6001)
- Update RedumpLib and LibIRD
- Update LibIRD
- Update redumper to build 653
- Minor cleanup
- Update test Nuget packages
- Update RedumpLib to 1.7.1
- Support multisession cache files
- Update DIC to 20250901 (Windows/Linux only)
- Fix UIC processing logic
- Update RedumpLib, detect Playmaji Polymega system
- Update redumper to b655
- Support new versioning format in redumper (fuzz6001)
- Add RedumperRefineSectorMode setting
- Update BinaryObjectScanner to 3.4.0
- Add context-sensitive protections helper method
- Further flesh out framework
- Add filters to handle Release Control output (Bestest)
- Cleanup last commits, add tests
- Update BinaryObjectScanner to 3.4.2
- Update RedumpLib to 1.7.4
### 3.3.3 (2025-07-18)
- Handle layers for PS3CFW
- Further clarify configuration requirements for CLI
- Ignore volume labels with path separators
- Reduce media-specific checks where unnecessary
- Add DetermineMediaType scaffolding and tests
- Fill out DetermineMediaType for Redumper
- Fill out DetermineMediaType for Aaru
- Fill out DetermineMediaType for DiscImageCreator
- Enable Check to determine media type automatically
- Fix missed test updates
- Rename disc info to media info
- Fix start index in Check
- Use the correct base path for Check
- Update redumper to build 611
- IsAudio cleanup
- IsAudio cleanup cleanup
- Remove dead code in DIC processor
- Set some default values for CLI
- Address nullable default value
- Better handling of Xbox/360, redumper build 613
- Use reasonable default names for PlayStation systems
- Swap PS1/2 back to original name handling
- Only use serial for PS3/4/5 if no custom volume label
- Fix unnecessary null assignment
- Empty should be null (fuzz6001)
- Remove legacy codes from info window
- Net Yaroze only for PS1
- Update RedumpLib to 1.6.8
- Add new help and version flags for CLI and Check
- Strip errant whitespace during path normalization
- Simplify code from previous commit
- Better handle mixed-separator paths
- Slightly better IRD organization
- Update redumper to build 631
### 3.3.2 (2025-06-12)
- Include Aaru in automatic builds

View File

@@ -0,0 +1,269 @@
using System;
using System.IO;
#if NET40
using System.Threading.Tasks;
#endif
using MPF.Frontend;
using MPF.Frontend.Tools;
using SabreTools.RedumpLib.Data;
using SabreTools.RedumpLib.Web;
using LogCompression = MPF.Processors.LogCompression;
namespace MPF.CLI.Features
{
internal abstract class BaseFeature : SabreTools.CommandLine.Feature
{
#region Properties
/// <summary>
/// User-defined options
/// </summary>
public Options Options { get; protected set; }
/// <summary>
/// Currently-selected system
/// </summary>
public RedumpSystem? System { get; protected set; }
/// <summary>
/// Media type to dump
/// </summary>
/// <remarks>Required for DIC and if custom parameters not set</remarks>
public MediaType? MediaType { get; protected set; }
/// <summary>
/// Path to the device to dump
/// </summary>
/// <remarks>Required if custom parameters are not set</remarks>
public string? DevicePath { get; protected set; }
/// <summary>
/// Path to the mounted filesystem to check
/// </summary>
/// <remarks>Should only be used when the device path is not readable</remarks>
public string? MountedPath { get; protected set; }
/// <summary>
/// Path to the output file
/// </summary>
/// <remarks>Required if custom parameters are not set</remarks>
public string? FilePath { get; protected set; }
/// <summary>
/// Override drive speed
/// </summary>
public int? DriveSpeed { get; protected set; }
/// <summary>
/// Custom parameters for dumping
/// </summary>
public string? CustomParams { get; protected set; }
#endregion
protected BaseFeature(string name, string[] flags, string description, string? detailed = null)
: base(name, flags, description, detailed)
{
Options = new Options()
{
// Internal Program
InternalProgram = InternalProgram.NONE,
// Extra Dumping Options
ScanForProtection = false,
AddPlaceholders = true,
PullAllInformation = false,
AddFilenameSuffix = false,
OutputSubmissionJSON = false,
IncludeArtifacts = false,
CompressLogFiles = false,
LogCompression = LogCompression.DeflateMaximum,
DeleteUnnecessaryFiles = false,
CreateIRDAfterDumping = false,
// Protection Scanning Options
ScanArchivesForProtection = true,
IncludeDebugProtectionInformation = false,
HideDriveLetters = false,
// Redump Login Information
RetrieveMatchInformation = true,
RedumpUsername = null,
RedumpPassword = null,
};
}
/// <inheritdoc/>
public override bool Execute()
{
// Validate the supplied credentials
if (Options.RetrieveMatchInformation
&& !string.IsNullOrEmpty(Options.RedumpUsername)
&& !string.IsNullOrEmpty(Options.RedumpPassword))
{
bool? validated = RedumpClient.ValidateCredentials(Options.RedumpUsername!, Options.RedumpPassword!).GetAwaiter().GetResult();
string message = validated switch
{
true => "Redump username and password accepted!",
false => "Redump username and password denied!",
null => "An error occurred validating your credentials!",
};
Console.WriteLine(message);
}
// Validate the internal program
switch (Options.InternalProgram)
{
case InternalProgram.Aaru:
if (!File.Exists(Options.AaruPath))
{
Console.Error.WriteLine("A path needs to be supplied in config.json for Aaru, exiting...");
return false;
}
break;
case InternalProgram.DiscImageCreator:
if (!File.Exists(Options.DiscImageCreatorPath))
{
Console.Error.WriteLine("A path needs to be supplied in config.json for DIC, exiting...");
return false;
}
break;
case InternalProgram.Redumper:
if (!File.Exists(Options.RedumperPath))
{
Console.Error.WriteLine("A path needs to be supplied in config.json for Redumper, exiting...");
return false;
}
break;
default:
Console.Error.WriteLine($"{Options.InternalProgram} is not a supported dumping program, exiting...");
break;
}
// Ensure we have the values we need
if (CustomParams == null && (DevicePath == null || FilePath == null))
{
Console.Error.WriteLine("Both a device path and file path need to be supplied, exiting...");
return false;
}
if (Options.InternalProgram == InternalProgram.DiscImageCreator
&& CustomParams == null
&& (MediaType == null || MediaType == SabreTools.RedumpLib.Data.MediaType.NONE))
{
Console.Error.WriteLine("Media type is required for DiscImageCreator, exiting...");
return false;
}
// Normalize the file path
if (FilePath != null)
FilePath = FrontendTool.NormalizeOutputPaths(FilePath, getFullPath: true);
// Get the speed from the options
int speed = DriveSpeed ?? FrontendTool.GetDefaultSpeedForMediaType(MediaType, Options);
// Populate an environment
var drive = Drive.Create(null, DevicePath ?? string.Empty);
var env = new DumpEnvironment(Options,
FilePath,
drive,
System,
Options.InternalProgram);
env.SetExecutionContext(MediaType, null);
env.SetProcessor();
// Process the parameters
string? paramStr = CustomParams ?? env.GetFullParameters(MediaType, speed);
if (string.IsNullOrEmpty(paramStr))
{
Console.Error.WriteLine("No valid environment could be created, exiting...");
return false;
}
env.SetExecutionContext(MediaType, paramStr);
// Invoke the dumping program
Console.WriteLine($"Invoking {Options.InternalProgram} using '{paramStr}'");
var dumpResult = env.Run(MediaType).GetAwaiter().GetResult();
Console.WriteLine(dumpResult.Message);
if (!dumpResult)
return false;
// If it was not a dumping command
if (!env.IsDumpingCommand())
{
Console.Error.WriteLine();
Console.WriteLine("Execution not recognized as dumping command, skipping processing...");
return true;
}
// If we have a mounted path, replace the environment
if (MountedPath != null && Directory.Exists(MountedPath))
{
drive = Drive.Create(null, MountedPath);
env = new DumpEnvironment(Options,
FilePath,
drive,
System,
internalProgram: null);
env.SetExecutionContext(MediaType, null);
env.SetProcessor();
}
// Finally, attempt to do the output dance
var verifyResult = env.VerifyAndSaveDumpOutput()
.ConfigureAwait(false).GetAwaiter().GetResult();
Console.WriteLine(verifyResult.Message);
return true;
}
/// <summary>
/// Display help for MPF.CLI
/// </summary>
/// <param name="error">Error string to prefix the help text with</param>
public static void DisplayHelp()
{
Console.WriteLine("Usage:");
Console.WriteLine("MPF.CLI <system> [options]");
Console.WriteLine();
Console.WriteLine("Standalone Options:");
Console.WriteLine("?, h, help Show this help text");
Console.WriteLine("version Print the program version");
Console.WriteLine("lc, listcodes List supported comment/content site codes");
Console.WriteLine("lm, listmedia List supported media types");
Console.WriteLine("ls, listsystems List supported system types");
Console.WriteLine("lp, listprograms List supported dumping program outputs");
Console.WriteLine("i, interactive Enable interactive mode");
Console.WriteLine();
Console.WriteLine("CLI Options:");
Console.WriteLine("-u, --use <program> Override configured dumping program name");
Console.WriteLine("-t, --mediatype <mediatype> Set media type for dumping (Required for DIC)");
Console.WriteLine("-d, --device <devicepath> Physical drive path (Required if no custom parameters set)");
Console.WriteLine("-m, --mounted <dirpath> Mounted filesystem path for additional checks");
Console.WriteLine("-f, --file \"<filepath>\" Output file path (Required if no custom parameters set)");
Console.WriteLine("-s, --speed <speed> Override default dumping speed");
Console.WriteLine("-c, --custom \"<params>\" Custom parameters to use");
Console.WriteLine();
Console.WriteLine("Dumping program paths and other settings can be found in the config.json file");
Console.WriteLine("generated next to the program by default. Ensure that all settings are to user");
Console.WriteLine("preference before running MPF.CLI.");
Console.WriteLine();
Console.WriteLine("Custom dumping parameters, if used, will fully replace the default parameters.");
Console.WriteLine("All dumping parameters need to be supplied if doing this.");
Console.WriteLine("Otherwise, both a drive path and output file path are required.");
Console.WriteLine();
Console.WriteLine("Mounted filesystem path is only recommended on OSes that require block");
Console.WriteLine("device dumping, usually Linux and macOS.");
Console.WriteLine();
}
}
}

View File

@@ -0,0 +1,190 @@
using System;
using System.IO;
using MPF.Frontend;
using MPF.Frontend.Tools;
using SabreTools.RedumpLib.Data;
namespace MPF.CLI.Features
{
internal sealed class InteractiveFeature : BaseFeature
{
#region Feature Definition
public const string DisplayName = "interactive";
private static readonly string[] _flags = ["i", "interactive"];
private const string _description = "Enable interactive mode";
#endregion
public InteractiveFeature()
: base(DisplayName, _flags, _description)
{
}
/// <inheritdoc/>
public override bool ProcessArgs(string[] args, int index)
{
// Cache all args as inputs
for (int i = 1; i < args.Length; i++)
{
Inputs.Add(args[i]);
}
// Read the options from config, if possible
Options = OptionsLoader.LoadFromConfig();
// Create return values
MediaType = SabreTools.RedumpLib.Data.MediaType.NONE;
FilePath = Path.Combine(Options.DefaultOutputPath ?? "ISO", "track.bin");
System = Options.DefaultSystem;
// Create state values
string? result = string.Empty;
root:
Console.Clear();
Console.WriteLine("MPF.CLI Interactive Mode - Main Menu");
Console.WriteLine("-------------------------");
Console.WriteLine();
Console.WriteLine($"1) Set system (Currently '{System}')");
Console.WriteLine($"2) Set dumping program (Currently '{Options.InternalProgram}')");
Console.WriteLine($"3) Set media type (Currently '{MediaType}')");
Console.WriteLine($"4) Set device path (Currently '{DevicePath}')");
Console.WriteLine($"5) Set mounted path (Currently '{MountedPath}')");
Console.WriteLine($"6) Set file path (Currently '{FilePath}')");
Console.WriteLine($"7) Set override speed (Currently '{DriveSpeed}')");
Console.WriteLine($"8) Set custom parameters (Currently '{CustomParams}')");
Console.WriteLine();
Console.WriteLine($"Q) Exit the program");
Console.WriteLine($"X) Start dumping");
Console.Write("> ");
result = Console.ReadLine();
switch (result)
{
case "1":
goto system;
case "2":
goto dumpingProgram;
case "3":
goto mediaType;
case "4":
goto devicePath;
case "5":
goto mountedPath;
case "6":
goto filePath;
case "7":
goto overrideSpeed;
case "8":
goto customParams;
case "q":
case "Q":
Environment.Exit(0);
break;
case "x":
case "X":
Console.Clear();
goto exit;
case "z":
case "Z":
Console.WriteLine("It is pitch black. You are likely to be eaten by a grue.");
Console.Write("> ");
Console.ReadLine();
goto root;
default:
Console.WriteLine($"Invalid selection: {result}");
Console.ReadLine();
goto root;
}
system:
Console.WriteLine();
Console.WriteLine("For possible inputs, use the List Systems commandline option");
Console.WriteLine();
Console.WriteLine("Input the system and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
System = result.ToRedumpSystem();
goto root;
dumpingProgram:
Console.WriteLine();
Console.WriteLine("Options:");
Console.WriteLine($"{InternalProgram.Redumper.ToString().ToLowerInvariant().PadRight(15)} => {InternalProgram.Redumper.LongName()}");
Console.WriteLine($"{InternalProgram.DiscImageCreator.ToString().ToLowerInvariant().PadRight(15)} => {InternalProgram.DiscImageCreator.LongName()}");
Console.WriteLine($"{InternalProgram.Aaru.ToString().ToLowerInvariant().PadRight(15)} => {InternalProgram.Aaru.LongName()}");
Console.WriteLine();
Console.WriteLine("Input the dumping program and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
Options.InternalProgram = result.ToInternalProgram();
goto root;
mediaType:
Console.WriteLine();
Console.WriteLine("For possible inputs, use the List Media commandline option");
Console.WriteLine();
Console.WriteLine("Input the media type and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
MediaType = OptionsLoader.ToMediaType(result);
goto root;
devicePath:
Console.WriteLine();
Console.WriteLine("Input the device path and press Enter:");
Console.Write("> ");
DevicePath = Console.ReadLine();
goto root;
mountedPath:
Console.WriteLine();
Console.WriteLine("Input the mounted path and press Enter:");
Console.Write("> ");
MountedPath = Console.ReadLine();
goto root;
filePath:
Console.WriteLine();
Console.WriteLine("Input the file path and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
if (!string.IsNullOrEmpty(result))
result = Path.GetFullPath(result!);
FilePath = result;
goto root;
overrideSpeed:
Console.WriteLine();
Console.WriteLine("Input the override speed and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
if (!int.TryParse(result, out int speed))
speed = -1;
DriveSpeed = speed;
goto root;
customParams:
Console.WriteLine();
Console.WriteLine("Input the custom parameters and press Enter:");
Console.Write("> ");
CustomParams = Console.ReadLine();
goto root;
exit:
return true;
}
/// <inheritdoc/>
public override bool VerifyInputs() => true;
}
}

View File

@@ -0,0 +1,115 @@
using MPF.Frontend;
using MPF.Frontend.Tools;
using SabreTools.CommandLine.Inputs;
using SabreTools.RedumpLib.Data;
namespace MPF.CLI.Features
{
internal sealed class MainFeature : BaseFeature
{
#region Feature Definition
public const string DisplayName = "main";
/// <remarks>Flags are unused</remarks>
private static readonly string[] _flags = [];
/// <remarks>Description is unused</remarks>
private const string _description = "";
#endregion
#region Inputs
private const string _customName = "custom";
internal readonly StringInput CustomInput = new(_customName, ["-c", "--custom"], "Custom parameters to use");
private const string _deviceName = "device";
internal readonly StringInput DeviceInput = new(_deviceName, ["-d", "--device"], "Physical drive path (Required if no custom parameters set)");
private const string _fileName = "file";
internal readonly StringInput FileInput = new(_fileName, ["-f", "--file"], "Output file path (Required if no custom parameters set)");
private const string _mediaTypeName = "media-type";
internal readonly StringInput MediaTypeInput = new(_mediaTypeName, ["-t", "--mediatype"], "Set media type for dumping (Required for DIC)");
private const string _mountedName = "mounted";
internal readonly StringInput MountedInput = new(_mountedName, ["-m", "--mounted"], "Mounted filesystem path for additional checks");
private const string _speedName = "speed";
internal readonly Int32Input SpeedInput = new(_speedName, ["-s", "--speed"], "Override default dumping speed");
private const string _useName = "use";
internal readonly StringInput UseInput = new(_useName, ["-u", "--use"], "Override configured dumping program name");
#endregion
public MainFeature()
: base(DisplayName, _flags, _description)
{
Add(UseInput);
Add(MediaTypeInput);
Add(DeviceInput);
Add(MountedInput);
Add(FileInput);
Add(SpeedInput);
Add(CustomInput);
}
/// <inheritdoc/>
public override bool ProcessArgs(string[] args, int index)
{
// If we have no arguments, just return
if (args == null || args.Length == 0)
return true;
// Read the options from config, if possible
Options = OptionsLoader.LoadFromConfig();
// The first argument is the system type
System = args[0].Trim('"').ToRedumpSystem();
// Loop through the arguments and parse out values
for (index = 1; index < args.Length; index++)
{
// Use specific program
if (UseInput.ProcessInput(args, ref index))
Options.InternalProgram = UseInput.Value.ToInternalProgram();
// Set a media type
else if (MediaTypeInput.ProcessInput(args, ref index))
MediaType = OptionsLoader.ToMediaType(MediaTypeInput.Value?.Trim('"'));
// Use a device path
else if (DeviceInput.ProcessInput(args, ref index))
DevicePath = DeviceInput.Value;
// Use a mounted path for physical checks
else if (MountedInput.ProcessInput(args, ref index))
MountedPath = MountedInput.Value;
// Use a file path
else if (FileInput.ProcessInput(args, ref index))
FilePath = FileInput.Value;
// Set an override speed
else if (SpeedInput.ProcessInput(args, ref index))
DriveSpeed = SpeedInput.Value;
// Use a custom parameters
else if (CustomInput.ProcessInput(args, ref index))
CustomParams = CustomInput.Value;
// Default, add to inputs
else
Inputs.Add(args[index]);
}
return true;
}
/// <inheritdoc/>
public override bool VerifyInputs() => true;
}
}

View File

@@ -12,7 +12,7 @@
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<VersionPrefix>3.3.2</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<!-- Package Properties -->
<Title>MPF CLI</Title>
@@ -43,7 +43,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.RedumpLib" Version="1.6.7" />
<PackageReference Include="SabreTools.CommandLine" Version="[1.3.2]" />
<PackageReference Include="SabreTools.RedumpLib" Version="[1.7.4]" />
</ItemGroup>
</Project>

View File

@@ -1,12 +1,14 @@
using System;
using System.IO;
using System.Collections.Generic;
#if NET40
using System.Threading.Tasks;
#endif
using MPF.CLI.Features;
using MPF.Frontend;
using MPF.Frontend.Features;
using MPF.Frontend.Tools;
using SabreTools.RedumpLib.Data;
using SabreTools.RedumpLib.Web;
using SabreTools.CommandLine;
using SabreTools.CommandLine.Features;
namespace MPF.CLI
{
@@ -29,483 +31,117 @@ namespace MPF.CLI
OptionsLoader.SaveToConfig(options);
// Display non-error message
DisplayHelp("First-run detected! Please fill out config.json and run again.");
Console.WriteLine("First-run detected! Please fill out config.json and run again.");
BaseFeature.DisplayHelp();
return;
}
// Try processing the standalone arguments
bool? standaloneProcessed = OptionsLoader.ProcessStandaloneArguments(args);
if (standaloneProcessed != false)
{
if (standaloneProcessed == null)
DisplayHelp();
return;
}
// Create the command set
var mainFeature = new MainFeature();
var commandSet = CreateCommands(mainFeature);
// Setup common outputs
CommandOptions opts;
MediaType mediaType;
RedumpSystem? knownSystem;
// Use interactive mode
if (args.Length > 0 && (args[0] == "-i" || args[0] == "--interactive"))
{
opts = InteractiveMode(options, out mediaType, out knownSystem);
}
// Use normal commandline parameters
else
{
// Try processing the common arguments
bool success = OptionsLoader.ProcessCommonArguments(args, out mediaType, out knownSystem, out var error);
if (!success)
{
DisplayHelp(error);
return;
}
// Validate the supplied credentials
if (options.RetrieveMatchInformation
&& !string.IsNullOrEmpty(options.RedumpUsername)
&& !string.IsNullOrEmpty(options.RedumpPassword))
{
bool? validated = RedumpClient.ValidateCredentials(options.RedumpUsername!, options.RedumpPassword!).GetAwaiter().GetResult();
string message = validated switch
{
true => "Redump username and password accepted!",
false => "Redump username and password denied!",
null => "An error occurred validating your credentials!",
};
Console.WriteLine(message);
}
// Process any custom parameters
int startIndex = 2;
opts = LoadFromArguments(args, options, ref startIndex);
}
// Validate the internal program
switch (options.InternalProgram)
{
case InternalProgram.Aaru:
if (!File.Exists(options.AaruPath))
{
DisplayHelp("A path needs to be supplied for Aaru, exiting...");
return;
}
break;
case InternalProgram.DiscImageCreator:
if (!File.Exists(options.DiscImageCreatorPath))
{
DisplayHelp("A path needs to be supplied for DIC, exiting...");
return;
}
break;
case InternalProgram.Redumper:
if (!File.Exists(options.RedumperPath))
{
DisplayHelp("A path needs to be supplied for Redumper, exiting...");
return;
}
break;
default:
DisplayHelp($"{options.InternalProgram} is not a supported dumping program, exiting...");
break;
}
// Ensure we have the values we need
if (opts.CustomParams == null && (opts.DevicePath == null || opts.FilePath == null))
{
DisplayHelp("Both a device path and file path need to be supplied, exiting...");
return;
}
// Normalize the file path
if (opts.FilePath != null)
opts.FilePath = Path.GetFullPath(opts.FilePath);
// Get the speed from the options
int speed = opts.DriveSpeed ?? FrontendTool.GetDefaultSpeedForMediaType(mediaType, options);
// Populate an environment
var drive = Drive.Create(null, opts.DevicePath ?? string.Empty);
var env = new DumpEnvironment(options,
opts.FilePath,
drive,
knownSystem,
mediaType,
options.InternalProgram,
parameters: null);
// Process the parameters
string? paramStr = opts.CustomParams ?? env.GetFullParameters(speed);
if (string.IsNullOrEmpty(paramStr))
{
DisplayHelp("No valid environment could be created, exiting...");
return;
}
env.SetExecutionContext(paramStr);
// Invoke the dumping program
Console.WriteLine($"Invoking {options.InternalProgram} using '{paramStr}'");
var dumpResult = env.Run().GetAwaiter().GetResult();
Console.WriteLine(dumpResult.Message);
if (!dumpResult)
return;
// If it was not a dumping command
if (!env.IsDumpingCommand())
{
Console.WriteLine("Execution not recognized as dumping command, skipping processing...");
return;
}
// If we have a mounted path, replace the environment
if (opts.MountedPath != null && Directory.Exists(opts.MountedPath))
{
drive = Drive.Create(null, opts.MountedPath);
env = new DumpEnvironment(options,
opts.FilePath,
drive,
knownSystem,
mediaType,
internalProgram: null,
parameters: null);
}
// Finally, attempt to do the output dance
var verifyResult = env.VerifyAndSaveDumpOutput()
.ConfigureAwait(false).GetAwaiter().GetResult();
Console.WriteLine(verifyResult.Message);
}
/// <summary>
/// Display help for MPF.CLI
/// </summary>
/// <param name="error">Error string to prefix the help text with</param>
private static void DisplayHelp(string? error = null)
{
if (error != null)
Console.WriteLine(error);
Console.WriteLine("Usage:");
Console.WriteLine("MPF.CLI <mediatype> <system> [options]");
Console.WriteLine();
Console.WriteLine("Standalone Options:");
Console.WriteLine("-h, -? Show this help text");
Console.WriteLine("-lc, --listcodes List supported comment/content site codes");
Console.WriteLine("-lm, --listmedia List supported media types");
Console.WriteLine("-ls, --listsystems List supported system types");
Console.WriteLine("-lp, --listprograms List supported dumping program outputs");
Console.WriteLine("-i, --interactive Enable interactive mode");
Console.WriteLine();
Console.WriteLine("CLI Options:");
Console.WriteLine("-u, --use <program> Override default dumping program");
Console.WriteLine("-d, --device <devicepath> Physical drive path (Required if no custom parameters set)");
Console.WriteLine("-m, --mounted <dirpath> Mounted filesystem path for additional checks");
Console.WriteLine("-f, --file \"<filepath>\" Output file path (Required if no custom parameters set)");
Console.WriteLine("-s, --speed <speed> Override default dumping speed");
Console.WriteLine("-c, --custom \"<params>\" Custom parameters to use");
Console.WriteLine();
Console.WriteLine("Custom dumping parameters, if used, will fully replace the default parameters.");
Console.WriteLine("All dumping parameters need to be supplied if doing this.");
Console.WriteLine("Otherwise, both a drive path and output file path are required.");
Console.WriteLine();
Console.WriteLine("Mounted filesystem path is only recommended on OSes that require block");
Console.WriteLine("device dumping, usually Linux and macOS.");
Console.WriteLine();
}
/// <summary>
/// Enable interactive mode for entering information
/// </summary>
private static CommandOptions InteractiveMode(Options options, out MediaType mediaType, out RedumpSystem? system)
{
// Create return values
var opts = new CommandOptions();
mediaType = MediaType.NONE;
system = null;
// Create state values
string? result = string.Empty;
root:
Console.Clear();
Console.WriteLine("MPF.CLI Interactive Mode - Main Menu");
Console.WriteLine("-------------------------");
Console.WriteLine();
Console.WriteLine($"1) Set media type (Currently '{mediaType}')");
Console.WriteLine($"2) Set system (Currently '{system}')");
Console.WriteLine($"3) Set dumping program (Currently '{options.InternalProgram}')");
Console.WriteLine($"4) Set device path (Currently '{opts.DevicePath}')");
Console.WriteLine($"5) Set mounted path (Currently '{opts.MountedPath}')");
Console.WriteLine($"6) Set file path (Currently '{opts.FilePath}')");
Console.WriteLine($"7) Set override speed (Currently '{opts.DriveSpeed}')");
Console.WriteLine($"8) Set custom parameters (Currently '{opts.CustomParams}')");
Console.WriteLine();
Console.WriteLine($"Q) Exit the program");
Console.WriteLine($"X) Start dumping");
Console.Write("> ");
result = Console.ReadLine();
switch (result)
{
case "1":
goto mediaType;
case "2":
goto system;
case "3":
goto dumpingProgram;
case "4":
goto devicePath;
case "5":
goto mountedPath;
case "6":
goto filePath;
case "7":
goto overrideSpeed;
case "8":
goto customParams;
case "q":
case "Q":
Environment.Exit(0);
break;
case "x":
case "X":
Console.Clear();
goto exit;
case "z":
case "Z":
Console.WriteLine("It is pitch black. You are likely to be eaten by a grue.");
Console.Write("> ");
Console.ReadLine();
goto root;
default:
Console.WriteLine($"Invalid selection: {result}");
Console.ReadLine();
goto root;
}
mediaType:
Console.WriteLine();
Console.WriteLine("Input the media type and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
mediaType = OptionsLoader.ToMediaType(result);
goto root;
system:
Console.WriteLine();
Console.WriteLine("Input the system and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
system = Extensions.ToRedumpSystem(result);
goto root;
dumpingProgram:
Console.WriteLine();
Console.WriteLine("Input the dumping program and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
options.InternalProgram = result.ToInternalProgram();
goto root;
devicePath:
Console.WriteLine();
Console.WriteLine("Input the device path and press Enter:");
Console.Write("> ");
opts.DevicePath = Console.ReadLine();
goto root;
mountedPath:
Console.WriteLine();
Console.WriteLine("Input the mounted path and press Enter:");
Console.Write("> ");
opts.MountedPath = Console.ReadLine();
goto root;
filePath:
Console.WriteLine();
Console.WriteLine("Input the file path and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
if (!string.IsNullOrEmpty(result))
result = Path.GetFullPath(result!);
opts.FilePath = result;
goto root;
overrideSpeed:
Console.WriteLine();
Console.WriteLine("Input the override speed and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
if (!int.TryParse(result, out int speed))
speed = -1;
opts.DriveSpeed = speed;
goto root;
customParams:
Console.WriteLine();
Console.WriteLine("Input the custom parameters and press Enter:");
Console.Write("> ");
opts.CustomParams = Console.ReadLine();
goto root;
exit:
return opts;
}
/// <summary>
/// Load the current set of options from application arguments
/// </summary>
private static CommandOptions LoadFromArguments(string[] args, Options options, ref int startIndex)
{
// Create return values
var opts = new CommandOptions();
// If we have no arguments, just return
// If we have no args, show the help and quit
if (args == null || args.Length == 0)
{
startIndex = 0;
return opts;
BaseFeature.DisplayHelp();
return;
}
// If we have an invalid start index, just return
if (startIndex < 0 || startIndex >= args.Length)
return opts;
// Get the first argument as a feature flag
string featureName = args[0];
// Loop through the arguments and parse out values
for (; startIndex < args.Length; startIndex++)
// Try processing the standalone arguments
var topLevel = commandSet.GetTopLevel(featureName);
switch (topLevel)
{
// Use specific program
if (args[startIndex].StartsWith("-u=") || args[startIndex].StartsWith("--use="))
{
string internalProgram = args[startIndex].Split('=')[1];
options.InternalProgram = internalProgram.ToInternalProgram();
}
else if (args[startIndex] == "-u" || args[startIndex] == "--use")
{
string internalProgram = args[startIndex + 1];
options.InternalProgram = internalProgram.ToInternalProgram();
startIndex++;
}
// Standalone Options
case Help: BaseFeature.DisplayHelp(); return;
case VersionFeature version: version.Execute(); return;
case ListCodesFeature lc: lc.Execute(); return;
case ListMediaTypesFeature lm: lm.Execute(); return;
case ListProgramsFeature lp: lp.Execute(); return;
case ListSystemsFeature ls: ls.Execute(); return;
// Use a device path
else if (args[startIndex].StartsWith("-d=") || args[startIndex].StartsWith("--device="))
{
opts.DevicePath = args[startIndex].Split('=')[1].Trim('"');
}
else if (args[startIndex] == "-d" || args[startIndex] == "--device")
{
opts.DevicePath = args[startIndex + 1].Trim('"');
startIndex++;
}
// Interactive Mode
case InteractiveFeature interactive:
if (!interactive.ProcessArgs(args, 0))
{
BaseFeature.DisplayHelp();
return;
}
if (!interactive.Execute())
{
BaseFeature.DisplayHelp();
return;
}
// Use a mounted path for physical checks
else if (args[startIndex].StartsWith("-m=") || args[startIndex].StartsWith("--mounted="))
{
opts.MountedPath = args[startIndex].Split('=')[1];
}
else if (args[startIndex] == "-m" || args[startIndex] == "--mounted")
{
opts.MountedPath = args[startIndex + 1];
startIndex++;
}
// Use a file path
else if (args[startIndex].StartsWith("-f=") || args[startIndex].StartsWith("--file="))
{
opts.FilePath = args[startIndex].Split('=')[1].Trim('"');
}
else if (args[startIndex] == "-f" || args[startIndex] == "--file")
{
opts.FilePath = args[startIndex + 1].Trim('"');
startIndex++;
}
// Set an override speed
else if (args[startIndex].StartsWith("-s=") || args[startIndex].StartsWith("--speed="))
{
if (!int.TryParse(args[startIndex].Split('=')[1].Trim('"'), out int speed))
speed = -1;
opts.DriveSpeed = speed;
}
else if (args[startIndex] == "-s" || args[startIndex] == "--speed")
{
if (!int.TryParse(args[startIndex + 1].Trim('"'), out int speed))
speed = -1;
opts.DriveSpeed = speed;
startIndex++;
}
// Use a custom parameters
else if (args[startIndex].StartsWith("-c=") || args[startIndex].StartsWith("--custom="))
{
opts.CustomParams = args[startIndex].Split('=')[1].Trim('"');
}
else if (args[startIndex] == "-c" || args[startIndex] == "--custom")
{
opts.CustomParams = args[startIndex + 1].Trim('"');
startIndex++;
}
// Default, we fall out
else
{
break;
}
}
return opts;
// Default Behavior
default:
if (!mainFeature.ProcessArgs(args, 0))
{
BaseFeature.DisplayHelp();
return;
}
if (!mainFeature.Execute())
{
BaseFeature.DisplayHelp();
return;
}
break;
}
}
/// <summary>
/// Represents commandline options
/// Create the command set for the program
/// </summary>
private class CommandOptions
private static CommandSet CreateCommands(MainFeature mainFeature)
{
/// <summary>
/// Path to the device to dump
/// </summary>
/// <remarks>Required if custom parameters are not set</remarks>
public string? DevicePath { get; set; } = null;
List<string> header = [
"MPF.CLI [standalone|system] [options] <path> ...",
string.Empty,
];
/// <summary>
/// Path to the mounted filesystem to check
/// </summary>
/// <remarks>Should only be used when the device path is not readable</remarks>
public string? MountedPath { get; set; } = null;
List<string> footer = [
string.Empty,
"Dumping program paths and other settings can be found in the config.json file",
"generated next to the program by default. Ensure that all settings are to user",
"preference before running MPF.CLI.",
string.Empty,
/// <summary>
/// Path to the output file
/// </summary>
/// <remarks>Required if custom parameters are not set</remarks>
public string? FilePath { get; set; } = null;
"Custom dumping parameters, if used, will fully replace the default parameters.",
"All dumping parameters need to be supplied if doing this.",
"Otherwise, both a drive path and output file path are required.",
string.Empty,
/// <summary>
/// Override drive speed
/// </summary>
public int? DriveSpeed { get; set; } = null;
"Mounted filesystem path is only recommended on OSes that require block",
"device dumping, usually Linux and macOS.",
string.Empty,
];
/// <summary>
/// Custom parameters for dumping
/// </summary>
public string? CustomParams { get; set; } = null;
var commandSet = new CommandSet(header, footer);
// Standalone Options
commandSet.Add(new Help());
commandSet.Add(new VersionFeature());
commandSet.Add(new ListCodesFeature());
commandSet.Add(new ListMediaTypesFeature());
commandSet.Add(new ListSystemsFeature());
commandSet.Add(new ListProgramsFeature());
commandSet.Add(new InteractiveFeature());
// CLI Options
commandSet.Add(mainFeature.UseInput);
commandSet.Add(mainFeature.MediaTypeInput);
commandSet.Add(mainFeature.DeviceInput);
commandSet.Add(mainFeature.MountedInput);
commandSet.Add(mainFeature.FileInput);
commandSet.Add(mainFeature.SpeedInput);
commandSet.Add(mainFeature.CustomInput);
return commandSet;
}
}
}

View File

@@ -0,0 +1,177 @@
using System;
using System.IO;
#if NET40
using System.Threading.Tasks;
#endif
using MPF.Frontend;
using SabreTools.RedumpLib.Data;
using SabreTools.RedumpLib.Web;
using LogCompression = MPF.Processors.LogCompression;
namespace MPF.Check.Features
{
internal abstract class BaseFeature : SabreTools.CommandLine.Feature
{
#region Properties
/// <summary>
/// User-defined options
/// </summary>
public Options Options { get; protected set; }
/// <summary>
/// Currently-selected system
/// </summary>
public RedumpSystem? System { get; protected set; }
/// <summary>
/// Seed submission info from an input file
/// </summary>
public SubmissionInfo? Seed { get; protected set; }
/// <summary>
/// Path to the device to scan
/// </summary>
public string? DevicePath { get; protected set; }
#endregion
protected BaseFeature(string name, string[] flags, string description, string? detailed = null)
: base(name, flags, description, detailed)
{
Options = new Options()
{
// Internal Program
InternalProgram = InternalProgram.NONE,
// Extra Dumping Options
ScanForProtection = false,
AddPlaceholders = true,
PullAllInformation = false,
AddFilenameSuffix = false,
OutputSubmissionJSON = false,
IncludeArtifacts = false,
CompressLogFiles = false,
LogCompression = LogCompression.DeflateMaximum,
DeleteUnnecessaryFiles = false,
CreateIRDAfterDumping = false,
// Protection Scanning Options
ScanArchivesForProtection = true,
IncludeDebugProtectionInformation = false,
HideDriveLetters = false,
// Redump Login Information
RetrieveMatchInformation = true,
RedumpUsername = null,
RedumpPassword = null,
};
}
/// <inheritdoc/>
public override bool Execute()
{
if (Options.InternalProgram == InternalProgram.NONE)
{
Console.Error.WriteLine("A program name needs to be provided");
return false;
}
// Validate the supplied credentials
if (Options.RetrieveMatchInformation
&& !string.IsNullOrEmpty(Options.RedumpUsername)
&& !string.IsNullOrEmpty(Options.RedumpPassword))
{
bool? validated = RedumpClient.ValidateCredentials(Options.RedumpUsername!, Options.RedumpPassword!).GetAwaiter().GetResult();
string message = validated switch
{
true => "Redump username and password accepted!",
false => "Redump username and password denied!",
null => "An error occurred validating your credentials!",
};
Console.WriteLine(message);
}
// Loop through all the rest of the args
for (int i = 0; i < Inputs.Count; i++)
{
// Check for a file
if (!File.Exists(Inputs[i].Trim('"')))
{
Console.Error.WriteLine($"{Inputs[i].Trim('"')} does not exist");
return false;
}
// Get the full file path
string filepath = Path.GetFullPath(Inputs[i].Trim('"'));
// Now populate an environment
Drive? drive = null;
if (!string.IsNullOrEmpty(DevicePath))
drive = Drive.Create(null, DevicePath!);
var env = new DumpEnvironment(Options,
filepath,
drive,
System,
internalProgram: null);
env.SetProcessor();
// Finally, attempt to do the output dance
var result = env.VerifyAndSaveDumpOutput(seedInfo: Seed)
.ConfigureAwait(false).GetAwaiter().GetResult();
Console.WriteLine(result.Message);
}
return true;
}
/// <summary>
/// Display help for MPF.Check
/// </summary>
/// <param name="error">Error string to prefix the help text with</param>
public static void DisplayHelp()
{
Console.WriteLine("Usage:");
Console.WriteLine("MPF.Check <system> [options] </path/to/output.cue/iso> ...");
Console.WriteLine();
Console.WriteLine("Standalone Options:");
Console.WriteLine("?, h, help Show this help text");
Console.WriteLine("version Print the program version");
Console.WriteLine("lc, listcodes List supported comment/content site codes");
Console.WriteLine("lm, listmedia List supported media types");
Console.WriteLine("ls, listsystems List supported system types");
Console.WriteLine("lp, listprograms List supported dumping program outputs");
Console.WriteLine("i, interactive Enable interactive mode");
Console.WriteLine();
Console.WriteLine("Check Options:");
Console.WriteLine("-u, --use <program> Dumping program output type [REQUIRED]");
Console.WriteLine(" --load-seed <path> Load a seed submission JSON for user information");
Console.WriteLine(" --no-placeholders Disable placeholder values in submission info");
Console.WriteLine(" --create-ird Create IRD from output files (PS3 only)");
Console.WriteLine(" --no-retrieve Disable retrieving match information from Redump");
Console.WriteLine("-c, --credentials <user> <pw> Redump username and password (incompatible with --no-retrieve) [WILL BE REMOVED]");
Console.WriteLine("-U, --username <user> Redump username (incompatible with --no-retrieve)");
Console.WriteLine("-P, --password <pw> Redump password (incompatible with --no-retrieve)");
Console.WriteLine(" --pull-all Pull all information from Redump (requires --username and --password)");
Console.WriteLine("-p, --path <drivepath> Physical drive path for additional checks");
Console.WriteLine("-s, --scan Enable copy protection scan (requires --path)");
Console.WriteLine(" --disable-archives Disable scanning archives (requires --scan)");
Console.WriteLine(" --enable-debug Enable debug protection information (requires --scan)");
Console.WriteLine(" --hide-drive-letters Hide drive letters from scan output (requires --scan)");
Console.WriteLine("-x, --suffix Enable adding filename suffix");
Console.WriteLine("-j, --json Enable submission JSON output");
Console.WriteLine(" --include-artifacts Include artifacts in JSON (requires --json)");
Console.WriteLine("-z, --zip Enable log file compression");
Console.WriteLine(" --log-compression Set the log compression type (requires --zip)");
Console.WriteLine("-d, --delete Enable unnecessary file deletion");
Console.WriteLine();
Console.WriteLine("WARNING: Check will overwrite both any existing submission information files as well");
Console.WriteLine("as any log archives. Please make backups of those if you need to before running Check.");
Console.WriteLine();
}
}
}

View File

@@ -0,0 +1,288 @@
using System;
using MPF.Frontend;
using MPF.Frontend.Tools;
using SabreTools.RedumpLib;
using SabreTools.RedumpLib.Data;
using LogCompression = MPF.Processors.LogCompression;
namespace MPF.Check.Features
{
internal sealed class InteractiveFeature : BaseFeature
{
#region Feature Definition
public const string DisplayName = "interactive";
private static readonly string[] _flags = ["i", "interactive"];
private const string _description = "Enable interactive mode";
#endregion
public InteractiveFeature()
: base(DisplayName, _flags, _description)
{
}
/// <inheritdoc/>
public override bool ProcessArgs(string[] args, int index)
{
// Cache all args as inputs
for (int i = 1; i < args.Length; i++)
{
Inputs.Add(args[i]);
}
// Read the options from config, if possible
Options = OptionsLoader.LoadFromConfig();
if (Options.FirstRun)
{
Options = new Options()
{
// Internal Program
InternalProgram = InternalProgram.NONE,
// Extra Dumping Options
ScanForProtection = false,
AddPlaceholders = true,
PullAllInformation = false,
AddFilenameSuffix = false,
OutputSubmissionJSON = false,
IncludeArtifacts = false,
CompressLogFiles = false,
LogCompression = LogCompression.DeflateMaximum,
DeleteUnnecessaryFiles = false,
CreateIRDAfterDumping = false,
// Protection Scanning Options
ScanArchivesForProtection = true,
IncludeDebugProtectionInformation = false,
HideDriveLetters = false,
// Redump Login Information
RetrieveMatchInformation = true,
RedumpUsername = null,
RedumpPassword = null,
};
}
// Create return values
System = null;
// These values require multiple parts to be active
bool scan = false,
enableArchives = true,
enableDebug = false,
hideDriveLetters = false;
// Create state values
string? result = string.Empty;
root:
Console.Clear();
Console.WriteLine("MPF.Check Interactive Mode - Main Menu");
Console.WriteLine("-------------------------");
Console.WriteLine();
Console.WriteLine($"1) Set system (Currently '{System}')");
Console.WriteLine($"2) Set dumping program (Currently '{Options.InternalProgram}')");
Console.WriteLine($"3) Set seed path (Currently '{Seed}')");
Console.WriteLine($"4) Add placeholders (Currently '{Options.AddPlaceholders}')");
Console.WriteLine($"5) Create IRD (Currently '{Options.CreateIRDAfterDumping}')");
Console.WriteLine($"6) Attempt Redump matches (Currently '{Options.RetrieveMatchInformation}')");
Console.WriteLine($"7) Redump credentials (Currently '{Options.RedumpUsername}')");
Console.WriteLine($"8) Pull all information (Currently '{Options.PullAllInformation}')");
Console.WriteLine($"9) Set device path (Currently '{DevicePath}')");
Console.WriteLine($"A) Scan for protection (Currently '{scan}')");
Console.WriteLine($"B) Scan archives for protection (Currently '{enableArchives}')");
Console.WriteLine($"C) Debug protection scan output (Currently '{enableDebug}')");
Console.WriteLine($"D) Hide drive letters in protection output (Currently '{hideDriveLetters}')");
Console.WriteLine($"E) Hide filename suffix (Currently '{Options.AddFilenameSuffix}')");
Console.WriteLine($"F) Output submission JSON (Currently '{Options.OutputSubmissionJSON}')");
Console.WriteLine($"G) Include JSON artifacts (Currently '{Options.IncludeArtifacts}')");
Console.WriteLine($"H) Compress logs (Currently '{Options.CompressLogFiles}')");
Console.WriteLine($"I) Log compression (Currently '{Options.LogCompression.LongName()}')");
Console.WriteLine($"J) Delete unnecessary files (Currently '{Options.DeleteUnnecessaryFiles}')");
Console.WriteLine();
Console.WriteLine($"Q) Exit the program");
Console.WriteLine($"X) Start checking");
Console.Write("> ");
result = Console.ReadLine();
switch (result)
{
case "1":
goto system;
case "2":
goto dumpingProgram;
case "3":
goto seedPath;
case "4":
Options.AddPlaceholders = !Options.AddPlaceholders;
goto root;
case "5":
Options.CreateIRDAfterDumping = !Options.CreateIRDAfterDumping;
goto root;
case "6":
Options.RetrieveMatchInformation = !Options.RetrieveMatchInformation;
goto root;
case "7":
goto redumpCredentials;
case "8":
Options.PullAllInformation = !Options.PullAllInformation;
goto root;
case "9":
goto devicePath;
case "a":
case "A":
scan = !scan;
goto root;
case "b":
case "B":
enableArchives = !enableArchives;
goto root;
case "c":
case "C":
enableDebug = !enableDebug;
goto root;
case "d":
case "D":
hideDriveLetters = !hideDriveLetters;
goto root;
case "e":
case "E":
Options.AddFilenameSuffix = !Options.AddFilenameSuffix;
goto root;
case "f":
case "F":
Options.OutputSubmissionJSON = !Options.OutputSubmissionJSON;
goto root;
case "g":
case "G":
Options.IncludeArtifacts = !Options.IncludeArtifacts;
goto root;
case "h":
case "H":
Options.CompressLogFiles = !Options.CompressLogFiles;
goto root;
case "i":
case "I":
goto logCompression;
case "j":
case "J":
Options.DeleteUnnecessaryFiles = !Options.DeleteUnnecessaryFiles;
goto root;
case "q":
case "Q":
Environment.Exit(0);
break;
case "x":
case "X":
Console.Clear();
goto exit;
case "z":
case "Z":
Console.WriteLine("It is pitch black. You are likely to be eaten by a grue.");
Console.Write("> ");
Console.ReadLine();
goto root;
default:
Console.WriteLine($"Invalid selection: {result}");
Console.ReadLine();
goto root;
}
system:
Console.WriteLine();
Console.WriteLine("For possible inputs, use the List Systems commandline option");
Console.WriteLine();
Console.WriteLine("Input the system and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
System = result.ToRedumpSystem();
goto root;
dumpingProgram:
Console.WriteLine();
Console.WriteLine("Options:");
foreach (var program in (InternalProgram[])Enum.GetValues(typeof(InternalProgram)))
{
// Skip the placeholder values
if (program == InternalProgram.NONE)
continue;
Console.WriteLine($"{program.ToString().ToLowerInvariant().PadRight(15)} => {program.LongName()}");
}
Console.WriteLine();
Console.WriteLine("Input the dumping program and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
Options.InternalProgram = result.ToInternalProgram();
goto root;
seedPath:
Console.WriteLine();
Console.WriteLine("Input the seed path and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
Seed = Builder.CreateFromFile(result);
goto root;
redumpCredentials:
Console.WriteLine();
Console.WriteLine("Enter your Redump username and press Enter:");
Console.Write("> ");
Options.RedumpUsername = Console.ReadLine();
Console.WriteLine("Enter your Redump password (hidden) and press Enter:");
Console.Write("> ");
Options.RedumpPassword = string.Empty;
while (true)
{
var key = Console.ReadKey(true);
if (key.Key == ConsoleKey.Enter)
break;
Options.RedumpPassword += key.KeyChar;
}
goto root;
devicePath:
Console.WriteLine();
Console.WriteLine("Input the device path and press Enter:");
Console.Write("> ");
DevicePath = Console.ReadLine();
goto root;
logCompression:
Console.WriteLine();
Console.WriteLine("Options:");
foreach (var compressionType in (LogCompression[])Enum.GetValues(typeof(LogCompression)))
{
Console.WriteLine($"{compressionType.ToString().ToLowerInvariant().PadRight(15)} => {compressionType.LongName()}");
}
Console.WriteLine();
Console.WriteLine("Input the log compression type and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
Options.LogCompression = result.ToLogCompression();
goto root;
exit:
// Now deal with the complex options
Options.ScanForProtection = scan && !string.IsNullOrEmpty(DevicePath);
Options.ScanArchivesForProtection = enableArchives && scan && !string.IsNullOrEmpty(DevicePath);
Options.IncludeDebugProtectionInformation = enableDebug && scan && !string.IsNullOrEmpty(DevicePath);
Options.HideDriveLetters = hideDriveLetters && scan && !string.IsNullOrEmpty(DevicePath);
return true;
}
/// <inheritdoc/>
public override bool VerifyInputs() => Inputs.Count > 0;
}
}

View File

@@ -0,0 +1,267 @@
using MPF.Frontend;
using MPF.Frontend.Tools;
using SabreTools.CommandLine.Inputs;
using SabreTools.RedumpLib;
using SabreTools.RedumpLib.Data;
using LogCompression = MPF.Processors.LogCompression;
namespace MPF.Check.Features
{
internal sealed class MainFeature : BaseFeature
{
#region Feature Definition
public const string DisplayName = "main";
/// <remarks>Flags are unused</remarks>
private static readonly string[] _flags = [];
/// <remarks>Description is unused</remarks>
private const string _description = "";
#endregion
#region Inputs
private const string _createIrdName = "create-ird";
internal readonly FlagInput CreateIrdInput = new(_createIrdName, "--create-ird", "Create IRD from output files (PS3 only)");
private const string _deleteName = "delete";
internal readonly FlagInput DeleteInput = new(_deleteName, ["-d", "--delete"], "Enable unnecessary file deletion");
private const string _disableArchivesName = "disable-archives";
internal readonly FlagInput DisableArchivesInput = new(_disableArchivesName, "--disable-archives", "Disable scanning archives (requires --scan)");
private const string _enableDebugName = "enable-debug";
internal readonly FlagInput EnableDebugInput = new(_enableDebugName, "--enable-debug", "Enable debug protection information (requires --scan)");
private const string _hideDriveLettersName = "hide-drive-letters";
internal readonly FlagInput HideDriveLettersInput = new(_hideDriveLettersName, "--hide-drive-letters", "Hide drive letters from scan output (requires --scan)");
private const string _includeArtifactsName = "include-artifacts";
internal readonly FlagInput IncludeArtifactsInput = new(_includeArtifactsName, "--include-artifacts", "Include artifacts in JSON (requires --json)");
private const string _jsonName = "json";
internal readonly FlagInput JsonInput = new(_jsonName, ["-j", "--json"], "Enable submission JSON output");
private const string _loadSeedName = "load-seed";
internal readonly StringInput LoadSeedInput = new(_loadSeedName, "--load-seed", "Load a seed submission JSON for user information");
private const string _logCompressionName = "log-compression";
internal readonly StringInput LogCompressionInput = new(_logCompressionName, "--log-compression", "Set the log compression type (requires --zip)");
private const string _noPlaceholdersName = "no-placeholders";
internal readonly FlagInput NoPlaceholdersInput = new(_noPlaceholdersName, "--no-placeholders", "Disable placeholder values in submission info");
private const string _noRetrieveName = "no-retrieve";
internal readonly FlagInput NoRetrieveInput = new(_noRetrieveName, "--no-retrieve", "Disable retrieving match information from Redump");
private const string _passwordName = "password";
internal readonly StringInput PasswordInput = new(_passwordName, ["-P", "--password"], "Redump password (incompatible with --no-retrieve)");
private const string _pathName = "path";
internal readonly StringInput PathInput = new(_pathName, ["-p", "--path"], "Physical drive path for additional checks");
private const string _pullAllName = "pull-all";
internal readonly FlagInput PullAllInput = new(_pullAllName, "--pull-all", "Pull all information from Redump (requires --username and --password)");
private const string _scanName = "scan";
internal readonly FlagInput ScanInput = new(_scanName, ["-s", "--scan"], "Enable copy protection scan (requires --path)");
private const string _suffixName = "suffix";
internal readonly FlagInput SuffixInput = new(_suffixName, ["-x", "--suffix"], "Enable adding filename suffix");
private const string _useName = "use";
internal readonly StringInput UseInput = new(_useName, ["-u", "--use"], "Override configured dumping program name");
private const string _usernameName = "username";
internal readonly StringInput UsernameInput = new(_usernameName, ["-U", "--username"], "Redump username (incompatible with --no-retrieve)");
private const string _zipName = "zip";
internal readonly FlagInput ZipInput = new(_zipName, ["-z", "--zip"], "Enable log file compression");
#endregion
public MainFeature()
: base(DisplayName, _flags, _description)
{
Add(UseInput);
Add(LoadSeedInput);
Add(NoPlaceholdersInput);
Add(CreateIrdInput);
Add(NoRetrieveInput);
// TODO: Figure out how to work with the credentials input
Add(PullAllInput);
Add(PathInput);
Add(ScanInput);
Add(DisableArchivesInput);
Add(EnableDebugInput);
Add(HideDriveLettersInput);
Add(SuffixInput);
Add(JsonInput);
Add(IncludeArtifactsInput);
Add(ZipInput);
Add(LogCompressionInput);
Add(DeleteInput);
}
/// <inheritdoc/>
public override bool ProcessArgs(string[] args, int index)
{
// These values require multiple parts to be active
bool scan = false,
enableArchives = true,
enableDebug = false,
hideDriveLetters = false;
// If we have no arguments, just return
if (args == null || args.Length == 0)
return true;
// Read the options from config, if possible
Options = OptionsLoader.LoadFromConfig();
if (Options.FirstRun)
{
Options = new Options()
{
// Internal Program
InternalProgram = InternalProgram.NONE,
// Extra Dumping Options
ScanForProtection = false,
AddPlaceholders = true,
PullAllInformation = false,
AddFilenameSuffix = false,
OutputSubmissionJSON = false,
IncludeArtifacts = false,
CompressLogFiles = false,
LogCompression = LogCompression.DeflateMaximum,
DeleteUnnecessaryFiles = false,
CreateIRDAfterDumping = false,
// Protection Scanning Options
ScanArchivesForProtection = true,
IncludeDebugProtectionInformation = false,
HideDriveLetters = false,
// Redump Login Information
RetrieveMatchInformation = true,
RedumpUsername = null,
RedumpPassword = null,
};
}
// The first argument is the system type
System = args[0].Trim('"').ToRedumpSystem();
// Loop through the arguments and parse out values
for (index = 1; index < args.Length; index++)
{
// Use specific program
if (UseInput.ProcessInput(args, ref index))
Options.InternalProgram = UseInput.Value.ToInternalProgram();
// Include seed info file
else if (LoadSeedInput.ProcessInput(args, ref index))
Seed = Builder.CreateFromFile(LoadSeedInput.Value);
// Disable placeholder values in submission info
else if (NoPlaceholdersInput.ProcessInput(args, ref index))
Options.AddPlaceholders = false;
// Create IRD from output files (PS3 only)
else if (CreateIrdInput.ProcessInput(args, ref index))
Options.CreateIRDAfterDumping = true;
// Set the log compression type (requires --zip)
else if (LogCompressionInput.ProcessInput(args, ref index))
Options.LogCompression = LogCompressionInput.Value.ToLogCompression();
// Retrieve Redump match information
else if (NoRetrieveInput.ProcessInput(args, ref index))
Options.RetrieveMatchInformation = false;
// Redump login
else if (args[index].StartsWith("-c=") || args[index].StartsWith("--credentials="))
{
string[] credentials = args[index].Split('=')[1].Split(';');
Options.RedumpUsername = credentials[0];
Options.RedumpPassword = credentials[1];
}
else if (args[index] == "-c" || args[index] == "--credentials")
{
Options.RedumpUsername = args[index + 1];
Options.RedumpPassword = args[index + 2];
index += 2;
}
// Redump username
else if (UsernameInput.ProcessInput(args, ref index))
Options.RedumpUsername = UsernameInput.Value;
// Redump password
else if (PasswordInput.ProcessInput(args, ref index))
Options.RedumpPassword = PasswordInput.Value;
// Pull all information (requires Redump login)
else if (PullAllInput.ProcessInput(args, ref index))
Options.PullAllInformation = true;
// Use a device path for physical checks
else if (PathInput.ProcessInput(args, ref index))
DevicePath = PathInput.Value;
// Scan for protection (requires device path)
else if (ScanInput.ProcessInput(args, ref index))
scan = true;
// Disable scanning archives (requires --scan)
else if (ScanInput.ProcessInput(args, ref index))
enableArchives = false;
// Enable debug protection information (requires --scan)
else if (EnableDebugInput.ProcessInput(args, ref index))
enableDebug = true;
// Hide drive letters from scan output (requires --scan)
else if (HideDriveLettersInput.ProcessInput(args, ref index))
hideDriveLetters = true;
// Add filename suffix
else if (SuffixInput.ProcessInput(args, ref index))
Options.AddFilenameSuffix = true;
// Output submission JSON
else if (JsonInput.ProcessInput(args, ref index))
Options.OutputSubmissionJSON = true;
// Include JSON artifacts
else if (IncludeArtifactsInput.ProcessInput(args, ref index))
Options.IncludeArtifacts = true;
// Compress log and extraneous files
else if (ZipInput.ProcessInput(args, ref index))
Options.CompressLogFiles = true;
// Delete unnecessary files
else if (DeleteInput.ProcessInput(args, ref index))
Options.DeleteUnnecessaryFiles = true;
// Default, add to inputs
else
Inputs.Add(args[index]);
}
// Now deal with the complex options
Options.ScanForProtection = scan && !string.IsNullOrEmpty(DevicePath);
Options.ScanArchivesForProtection = enableArchives && scan && !string.IsNullOrEmpty(DevicePath);
Options.IncludeDebugProtectionInformation = enableDebug && scan && !string.IsNullOrEmpty(DevicePath);
Options.HideDriveLetters = hideDriveLetters && scan && !string.IsNullOrEmpty(DevicePath);
return true;
}
/// <inheritdoc/>
public override bool VerifyInputs() => Inputs.Count > 0;
}
}

View File

@@ -12,7 +12,7 @@
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<VersionPrefix>3.3.2</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<!-- Package Properties -->
<Title>MPF Check</Title>
@@ -43,7 +43,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.RedumpLib" Version="1.6.7" />
<PackageReference Include="SabreTools.CommandLine" Version="[1.3.2]" />
<PackageReference Include="SabreTools.RedumpLib" Version="[1.7.4]" />
</ItemGroup>
</Project>

View File

@@ -1,13 +1,12 @@
using System;
using System.IO;
using System.Collections.Generic;
#if NET40
using System.Threading.Tasks;
#endif
using MPF.Frontend;
using MPF.Frontend.Tools;
using SabreTools.RedumpLib;
using SabreTools.RedumpLib.Data;
using SabreTools.RedumpLib.Web;
using MPF.Check.Features;
using MPF.Frontend.Features;
using SabreTools.CommandLine;
using SabreTools.CommandLine.Features;
namespace MPF.Check
{
@@ -15,555 +14,126 @@ namespace MPF.Check
{
public static void Main(string[] args)
{
// Create a default options object
var options = new Options()
{
// Internal Program
InternalProgram = InternalProgram.NONE,
// Create the command set
var mainFeature = new MainFeature();
var commandSet = CreateCommands(mainFeature);
// Extra Dumping Options
ScanForProtection = false,
AddPlaceholders = true,
PullAllInformation = false,
AddFilenameSuffix = false,
OutputSubmissionJSON = false,
IncludeArtifacts = false,
CompressLogFiles = false,
DeleteUnnecessaryFiles = false,
CreateIRDAfterDumping = false,
// Protection Scanning Options
ScanArchivesForProtection = true,
IncludeDebugProtectionInformation = false,
HideDriveLetters = false,
// Redump Login Information
RetrieveMatchInformation = true,
RedumpUsername = null,
RedumpPassword = null,
};
// Try processing the standalone arguments
bool? standaloneProcessed = OptionsLoader.ProcessStandaloneArguments(args);
if (standaloneProcessed != false)
{
if (standaloneProcessed == null)
DisplayHelp();
return;
}
// Setup common outputs
CommandOptions opts;
MediaType mediaType;
RedumpSystem? knownSystem;
int startIndex;
// Use interactive mode
if (args.Length > 0 && (args[0] == "-i" || args[0] == "--interactive"))
{
startIndex = 1;
opts = InteractiveMode(options, out mediaType, out knownSystem);
}
// Use normal commandline parameters
else
{
// Try processing the common arguments
bool success = OptionsLoader.ProcessCommonArguments(args, out mediaType, out knownSystem, out var error);
if (!success)
{
DisplayHelp(error);
return;
}
// Loop through and process options
startIndex = 2;
opts = LoadFromArguments(args, options, ref startIndex);
}
if (options.InternalProgram == InternalProgram.NONE)
{
DisplayHelp("A program name needs to be provided");
return;
}
// Validate the supplied credentials
if (options.RetrieveMatchInformation
&& !string.IsNullOrEmpty(options.RedumpUsername)
&& !string.IsNullOrEmpty(options.RedumpPassword))
{
bool? validated = RedumpClient.ValidateCredentials(options.RedumpUsername!, options.RedumpPassword!).GetAwaiter().GetResult();
string message = validated switch
{
true => "Redump username and password accepted!",
false => "Redump username and password denied!",
null => "An error occurred validating your credentials!",
};
Console.WriteLine(message);
}
// Loop through all the rest of the args
for (int i = startIndex; i < args.Length; i++)
{
// Check for a file
if (!File.Exists(args[i].Trim('"')))
{
DisplayHelp($"{args[i].Trim('"')} does not exist");
return;
}
// Get the full file path
string filepath = Path.GetFullPath(args[i].Trim('"'));
// Now populate an environment
Drive? drive = null;
if (!string.IsNullOrEmpty(opts.DevicePath))
drive = Drive.Create(null, opts.DevicePath!);
var env = new DumpEnvironment(options, filepath, drive, knownSystem, mediaType, internalProgram: null, parameters: null);
// Finally, attempt to do the output dance
var result = env.VerifyAndSaveDumpOutput(seedInfo: opts.Seed)
.ConfigureAwait(false).GetAwaiter().GetResult();
Console.WriteLine(result.Message);
}
}
/// <summary>
/// Display help for MPF.Check
/// </summary>
/// <param name="error">Error string to prefix the help text with</param>
private static void DisplayHelp(string? error = null)
{
if (error != null)
Console.WriteLine(error);
Console.WriteLine("Usage:");
Console.WriteLine("MPF.Check <mediatype> <system> [options] </path/to/output.cue/iso> ...");
Console.WriteLine();
Console.WriteLine("Standalone Options:");
Console.WriteLine("-h, -? Show this help text");
Console.WriteLine("-lc, --listcodes List supported comment/content site codes");
Console.WriteLine("-lm, --listmedia List supported media types");
Console.WriteLine("-ls, --listsystems List supported system types");
Console.WriteLine("-lp, --listprograms List supported dumping program outputs");
Console.WriteLine("-i, --interactive Enable interactive mode");
Console.WriteLine();
Console.WriteLine("Check Options:");
Console.WriteLine("-u, --use <program> Dumping program output type [REQUIRED]");
Console.WriteLine(" --load-seed <path> Load a seed submission JSON for user information");
Console.WriteLine(" --no-placeholders Disable placeholder values in submission info");
Console.WriteLine(" --create-ird Create IRD from output files (PS3 only)");
Console.WriteLine(" --no-retrieve Disable retrieving match information from Redump");
Console.WriteLine("-c, --credentials <user> <pw> Redump username and password (incompatible with --no-retrieve)");
Console.WriteLine(" --pull-all Pull all information from Redump (requires --credentials)");
Console.WriteLine("-p, --path <drivepath> Physical drive path for additional checks");
Console.WriteLine("-s, --scan Enable copy protection scan (requires --path)");
Console.WriteLine(" --disable-archives Disable scanning archives (requires --scan)");
Console.WriteLine(" --enable-debug Enable debug protection information (requires --scan)");
Console.WriteLine(" --hide-drive-letters Hide drive letters from scan output (requires --scan)");
Console.WriteLine("-x, --suffix Enable adding filename suffix");
Console.WriteLine("-j, --json Enable submission JSON output");
Console.WriteLine(" --include-artifacts Include artifacts in JSON (requires --json)");
Console.WriteLine("-z, --zip Enable log file compression");
Console.WriteLine("-d, --delete Enable unnecessary file deletion");
Console.WriteLine();
Console.WriteLine("WARNING: Check will overwrite both any existing submission information files as well");
Console.WriteLine("as any log archives. Please make backups of those if you need to before running Check.");
Console.WriteLine();
}
/// <summary>
/// Enable interactive mode for entering information
/// </summary>
private static CommandOptions InteractiveMode(Options options, out MediaType mediaType, out RedumpSystem? system)
{
// Create return values
var opts = new CommandOptions();
mediaType = MediaType.NONE;
system = null;
// These values require multiple parts to be active
bool scan = false,
enableArchives = true,
enableDebug = false,
hideDriveLetters = false;
// Create state values
string? result = string.Empty;
root:
Console.Clear();
Console.WriteLine("MPF.Check Interactive Mode - Main Menu");
Console.WriteLine("-------------------------");
Console.WriteLine();
Console.WriteLine($"1) Set media type (Currently '{mediaType}')");
Console.WriteLine($"2) Set system (Currently '{system}')");
Console.WriteLine($"3) Set dumping program (Currently '{options.InternalProgram}')");
Console.WriteLine($"4) Set seed path (Currently '{opts.Seed}')");
Console.WriteLine($"5) Add placeholders (Currently '{options.AddPlaceholders}')");
Console.WriteLine($"6) Create IRD (Currently '{options.CreateIRDAfterDumping}')");
Console.WriteLine($"7) Attempt Redump matches (Currently '{options.RetrieveMatchInformation}')");
Console.WriteLine($"8) Redump credentials (Currently '{options.RedumpUsername}')");
Console.WriteLine($"9) Pull all information (Currently '{options.PullAllInformation}')");
Console.WriteLine($"A) Set device path (Currently '{opts.DevicePath}')");
Console.WriteLine($"B) Scan for protection (Currently '{scan}')");
Console.WriteLine($"C) Scan archives for protection (Currently '{enableArchives}')");
Console.WriteLine($"D) Debug protection scan output (Currently '{enableDebug}')");
Console.WriteLine($"E) Hide drive letters in protection output (Currently '{hideDriveLetters}')");
Console.WriteLine($"F) Hide filename suffix (Currently '{options.AddFilenameSuffix}')");
Console.WriteLine($"G) Output submission JSON (Currently '{options.OutputSubmissionJSON}')");
Console.WriteLine($"H) Include JSON artifacts (Currently '{options.IncludeArtifacts}')");
Console.WriteLine($"I) Compress logs (Currently '{options.CompressLogFiles}')");
Console.WriteLine($"J) Delete unnecessary files (Currently '{options.DeleteUnnecessaryFiles}')");
Console.WriteLine();
Console.WriteLine($"Q) Exit the program");
Console.WriteLine($"X) Start checking");
Console.Write("> ");
result = Console.ReadLine();
switch (result)
{
case "1":
goto mediaType;
case "2":
goto system;
case "3":
goto dumpingProgram;
case "4":
goto seedPath;
case "5":
options.AddPlaceholders = !options.AddPlaceholders;
goto root;
case "6":
options.CreateIRDAfterDumping = !options.CreateIRDAfterDumping;
goto root;
case "7":
options.RetrieveMatchInformation = !options.RetrieveMatchInformation;
goto root;
case "8":
goto redumpCredentials;
case "9":
options.PullAllInformation = !options.PullAllInformation;
goto root;
case "a":
case "A":
goto devicePath;
case "b":
case "B":
scan = !scan;
goto root;
case "c":
case "C":
enableArchives = !enableArchives;
goto root;
case "d":
case "D":
enableDebug = !enableDebug;
goto root;
case "e":
case "E":
hideDriveLetters = !hideDriveLetters;
goto root;
case "f":
case "F":
options.AddFilenameSuffix = !options.AddFilenameSuffix;
goto root;
case "g":
case "G":
options.OutputSubmissionJSON = !options.OutputSubmissionJSON;
goto root;
case "h":
case "H":
options.IncludeArtifacts = !options.IncludeArtifacts;
goto root;
case "i":
case "I":
options.CompressLogFiles = !options.CompressLogFiles;
goto root;
case "j":
case "J":
options.DeleteUnnecessaryFiles = !options.DeleteUnnecessaryFiles;
goto root;
case "q":
case "Q":
Environment.Exit(0);
break;
case "x":
case "X":
Console.Clear();
goto exit;
case "z":
case "Z":
Console.WriteLine("It is pitch black. You are likely to be eaten by a grue.");
Console.Write("> ");
Console.ReadLine();
goto root;
default:
Console.WriteLine($"Invalid selection: {result}");
Console.ReadLine();
goto root;
}
mediaType:
Console.WriteLine();
Console.WriteLine("Input the media type and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
mediaType = OptionsLoader.ToMediaType(result);
goto root;
system:
Console.WriteLine();
Console.WriteLine("Input the system and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
system = Extensions.ToRedumpSystem(result);
goto root;
dumpingProgram:
Console.WriteLine();
Console.WriteLine("Input the dumping program and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
options.InternalProgram = result.ToInternalProgram();
goto root;
seedPath:
Console.WriteLine();
Console.WriteLine("Input the seed path and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
opts.Seed = Builder.CreateFromFile(result);
goto root;
redumpCredentials:
Console.WriteLine();
Console.WriteLine("Enter your Redumper username and press Enter:");
Console.Write("> ");
options.RedumpUsername = Console.ReadLine();
Console.WriteLine("Enter your Redumper password (hidden) and press Enter:");
Console.Write("> ");
options.RedumpPassword = string.Empty;
while (true)
{
var key = Console.ReadKey(true);
if (key.Key == ConsoleKey.Enter)
break;
options.RedumpPassword += key.KeyChar;
}
goto root;
devicePath:
Console.WriteLine();
Console.WriteLine("Input the device path and press Enter:");
Console.Write("> ");
opts.DevicePath = Console.ReadLine();
goto root;
exit:
// Now deal with the complex options
options.ScanForProtection = scan && !string.IsNullOrEmpty(opts.DevicePath);
options.ScanArchivesForProtection = enableArchives && scan && !string.IsNullOrEmpty(opts.DevicePath);
options.IncludeDebugProtectionInformation = enableDebug && scan && !string.IsNullOrEmpty(opts.DevicePath);
options.HideDriveLetters = hideDriveLetters && scan && !string.IsNullOrEmpty(opts.DevicePath);
return opts;
}
/// <summary>
/// Load the current set of options from application arguments
/// </summary>
private static CommandOptions LoadFromArguments(string[] args, Options options, ref int startIndex)
{
// Create return values
var opts = new CommandOptions();
// These values require multiple parts to be active
bool scan = false,
enableArchives = true,
enableDebug = false,
hideDriveLetters = false;
// If we have no arguments, just return
// If we have no args, show the help and quit
if (args == null || args.Length == 0)
{
startIndex = 0;
return opts;
BaseFeature.DisplayHelp();
return;
}
// If we have an invalid start index, just return
if (startIndex < 0 || startIndex >= args.Length)
return opts;
// Get the first argument as a feature flag
string featureName = args[0];
// Loop through the arguments and parse out values
for (; startIndex < args.Length; startIndex++)
// Try processing the standalone arguments
var topLevel = commandSet.GetTopLevel(featureName);
switch (topLevel)
{
// Use specific program
if (args[startIndex].StartsWith("-u=") || args[startIndex].StartsWith("--use="))
{
string internalProgram = args[startIndex].Split('=')[1];
options.InternalProgram = internalProgram.ToInternalProgram();
}
else if (args[startIndex] == "-u" || args[startIndex] == "--use")
{
string internalProgram = args[startIndex + 1];
options.InternalProgram = internalProgram.ToInternalProgram();
startIndex++;
}
// Standalone Options
case Help: BaseFeature.DisplayHelp(); return;
case VersionFeature version: version.Execute(); return;
case ListCodesFeature lc: lc.Execute(); return;
case ListMediaTypesFeature lm: lm.Execute(); return;
case ListProgramsFeature lp: lp.Execute(); return;
case ListSystemsFeature ls: ls.Execute(); return;
// Include seed info file
else if (args[startIndex].StartsWith("--load-seed="))
{
string seedInfo = args[startIndex].Split('=')[1];
opts.Seed = Builder.CreateFromFile(seedInfo);
}
else if (args[startIndex] == "--load-seed")
{
string seedInfo = args[startIndex + 1];
opts.Seed = Builder.CreateFromFile(seedInfo);
startIndex++;
}
// Interactive Mode
case InteractiveFeature interactive:
if (!interactive.ProcessArgs(args, 0))
{
BaseFeature.DisplayHelp();
return;
}
if (!interactive.VerifyInputs())
{
Console.Error.WriteLine("At least one input is required");
BaseFeature.DisplayHelp();
return;
}
if (!interactive.Execute())
{
BaseFeature.DisplayHelp();
return;
}
break;
// Default Behavior
default:
if (!mainFeature.ProcessArgs(args, 0))
{
BaseFeature.DisplayHelp();
return;
}
if (!mainFeature.VerifyInputs())
{
Console.Error.WriteLine("At least one input is required");
BaseFeature.DisplayHelp();
return;
}
if (!mainFeature.Execute())
{
BaseFeature.DisplayHelp();
return;
}
// Disable placeholder values in submission info
else if (args[startIndex].Equals("--no-placeholders"))
{
options.AddPlaceholders = false;
}
// Create IRD from output files (PS3 only)
else if (args[startIndex].Equals("--create-ird"))
{
options.CreateIRDAfterDumping = true;
}
// Retrieve Redump match information
else if (args[startIndex] == "--no-retrieve")
{
options.RetrieveMatchInformation = false;
}
// Redump login
else if (args[startIndex].StartsWith("-c=") || args[startIndex].StartsWith("--credentials="))
{
string[] credentials = args[startIndex].Split('=')[1].Split(';');
options.RedumpUsername = credentials[0];
options.RedumpPassword = credentials[1];
}
else if (args[startIndex] == "-c" || args[startIndex] == "--credentials")
{
options.RedumpUsername = args[startIndex + 1];
options.RedumpPassword = args[startIndex + 2];
startIndex += 2;
}
// Pull all information (requires Redump login)
else if (args[startIndex].Equals("--pull-all"))
{
options.PullAllInformation = true;
}
// Use a device path for physical checks
else if (args[startIndex].StartsWith("-p=") || args[startIndex].StartsWith("--path="))
{
opts.DevicePath = args[startIndex].Split('=')[1];
}
else if (args[startIndex] == "-p" || args[startIndex] == "--path")
{
opts.DevicePath = args[startIndex + 1];
startIndex++;
}
// Scan for protection (requires device path)
else if (args[startIndex].Equals("-s") || args[startIndex].Equals("--scan"))
{
scan = true;
}
// Disable scanning archives (requires --scan)
else if (args[startIndex].Equals("--disable-archives"))
{
enableArchives = false;
}
// Enable debug protection information (requires --scan)
else if (args[startIndex].Equals("--enable-debug"))
{
enableDebug = true;
}
// Hide drive letters from scan output (requires --scan)
else if (args[startIndex].Equals("--hide-drive-letters"))
{
hideDriveLetters = true;
}
// Add filename suffix
else if (args[startIndex].Equals("-x") || args[startIndex].Equals("--suffix"))
{
options.AddFilenameSuffix = true;
}
// Output submission JSON
else if (args[startIndex].Equals("-j") || args[startIndex].Equals("--json"))
{
options.OutputSubmissionJSON = true;
}
// Include JSON artifacts
else if (args[startIndex].Equals("--include-artifacts"))
{
options.IncludeArtifacts = true;
}
// Compress log and extraneous files
else if (args[startIndex].Equals("-z") || args[startIndex].Equals("--zip"))
{
options.CompressLogFiles = true;
}
// Delete unnecessary files
else if (args[startIndex].Equals("-d") || args[startIndex].Equals("--delete"))
{
options.DeleteUnnecessaryFiles = true;
}
// Default, we fall out
else
{
break;
}
}
// Now deal with the complex options
options.ScanForProtection = scan && !string.IsNullOrEmpty(opts.DevicePath);
options.ScanArchivesForProtection = enableArchives && scan && !string.IsNullOrEmpty(opts.DevicePath);
options.IncludeDebugProtectionInformation = enableDebug && scan && !string.IsNullOrEmpty(opts.DevicePath);
options.HideDriveLetters = hideDriveLetters && scan && !string.IsNullOrEmpty(opts.DevicePath);
return opts;
}
/// <summary>
/// Represents commandline options
/// Create the command set for the program
/// </summary>
private class CommandOptions
private static CommandSet CreateCommands(MainFeature mainFeature)
{
/// <summary>
/// Seed submission info from an input file
/// </summary>
public SubmissionInfo? Seed { get; set; } = null;
List<string> header = [
"MPF.CLI [standalone|system] [options] <path> ...",
string.Empty,
];
/// <summary>
/// Path to the device to scan
/// </summary>
public string? DevicePath { get; set; } = null;
List<string> footer = [
string.Empty,
"WARNING: Check will overwrite both any existing submission information files as well",
"as any log archives. Please make backups of those if you need to before running Check.",
string.Empty,
];
var commandSet = new CommandSet(header, footer);
// Standalone Options
commandSet.Add(new Help());
commandSet.Add(new VersionFeature());
commandSet.Add(new ListCodesFeature());
commandSet.Add(new ListMediaTypesFeature());
commandSet.Add(new ListSystemsFeature());
commandSet.Add(new ListProgramsFeature());
commandSet.Add(new InteractiveFeature());
// Check Options
commandSet.Add(mainFeature.UseInput);
commandSet.Add(mainFeature.LoadSeedInput);
commandSet.Add(mainFeature.NoPlaceholdersInput);
commandSet.Add(mainFeature.CreateIrdInput);
commandSet.Add(mainFeature.NoRetrieveInput);
commandSet.Add(mainFeature.UsernameInput);
commandSet.Add(mainFeature.PasswordInput);
commandSet.Add(mainFeature.PullAllInput);
commandSet.Add(mainFeature.PathInput);
commandSet.Add(mainFeature.ScanInput);
commandSet.Add(mainFeature.DisableArchivesInput);
commandSet.Add(mainFeature.EnableDebugInput);
commandSet.Add(mainFeature.HideDriveLettersInput);
commandSet.Add(mainFeature.SuffixInput);
commandSet.Add(mainFeature.JsonInput);
commandSet.Add(mainFeature.IncludeArtifactsInput);
commandSet.Add(mainFeature.ZipInput);
commandSet.Add(mainFeature.LogCompressionInput);
commandSet.Add(mainFeature.DeleteInput);
return commandSet;
}
}
}

View File

@@ -40,15 +40,15 @@ namespace MPF.ExecutionContexts.Test
[Theory]
[InlineData(null, null, null, "filename.bin", null, null)]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
[InlineData(RedumpSystem.SegaDreamcast, MediaType.GDROM, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
[InlineData(RedumpSystem.SegaDreamcast, MediaType.GDROM, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
[InlineData(RedumpSystem.HDDVDVideo, MediaType.HDDVD, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
[InlineData(RedumpSystem.BDVideo, MediaType.BluRay, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
[InlineData(RedumpSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
[InlineData(RedumpSystem.NintendoWii, MediaType.NintendoWiiOpticalDisc, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
[InlineData(RedumpSystem.NintendoWiiU, MediaType.NintendoWiiUOpticalDisc, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.FloppyDisk, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
[InlineData(RedumpSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
[InlineData(RedumpSystem.NintendoWii, MediaType.NintendoWiiOpticalDisc, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
[InlineData(RedumpSystem.NintendoWiiU, MediaType.NintendoWiiUOpticalDisc, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.FloppyDisk, "/dev/sr0", "filename.bin", 2, "--debug True --verbose True media dump --force True --private True --store-encrypted True --title-keys False --trim True --speed 2 --retry-passes 1000 /dev/sr0 \"filename.bin\"")]
public void DefaultValueTest(RedumpSystem? system,
MediaType? type,
string? drivePath,

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0;net8.0;net9.0</TargetFrameworks>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
@@ -14,13 +14,13 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeCoverage" Version="17.13.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.6.7" />
<PackageReference Include="Microsoft.CodeCoverage" Version="17.14.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
<PackageReference Include="SabreTools.RedumpLib" Version="[1.7.4]" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.abstractions" Version="2.0.3" />
<PackageReference Include="xunit.analyzers" Version="1.21.0" />
<PackageReference Include="xunit.analyzers" Version="1.24.0" />
<PackageReference Include="xunit.assert" Version="2.9.3" />
<PackageReference Include="xunit.core" Version="2.9.3" />
<PackageReference Include="xunit.extensibility.core" Version="2.9.3" />
@@ -29,7 +29,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.2">
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -41,9 +41,9 @@ namespace MPF.ExecutionContexts.Test
};
[Theory]
[InlineData(null, null, null, "filename.bin", null, "")]
[InlineData(null, null, null, "filename.bin", null, "disc --verbose --skeleton --retries=1000 --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, "/dev/sr0", "path/filename.bin", 2, "disc --verbose --skeleton --drive=/dev/sr0 --speed=2 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, "/dev/sr0", "path/filename.bin", 2, "disc --verbose --drive=/dev/sr0 --speed=2 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, "/dev/sr0", "path/filename.bin", 2, "disc --verbose --skeleton --drive=/dev/sr0 --speed=2 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
[InlineData(RedumpSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc, "/dev/sr0", "path/filename.bin", 2, "disc --verbose --drive=/dev/sr0 --speed=2 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
[InlineData(RedumpSystem.NintendoWii, MediaType.NintendoWiiOpticalDisc, "/dev/sr0", "path/filename.bin", 2, "disc --verbose --drive=/dev/sr0 --speed=2 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
[InlineData(RedumpSystem.HDDVDVideo, MediaType.HDDVD, "/dev/sr0", "path/filename.bin", 2, "disc --verbose --drive=/dev/sr0 --speed=2 --retries=1000 --image-path=\"path\" --image-name=\"filename\" --drive-type=GENERIC --drive-read-method=BE --drive-sector-order=DATA_C2_SUB --plextor-leadin-retries=1000")]
@@ -66,11 +66,11 @@ namespace MPF.ExecutionContexts.Test
#region Disc
[Theory]
[InlineData("disc -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("disc --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("disc -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("disc --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void DiscTest(string parameters)
{
string? expected = "disc --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
string? expected = "disc --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
@@ -93,11 +93,11 @@ namespace MPF.ExecutionContexts.Test
#region Rings
[Theory]
[InlineData("rings -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("rings --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("rings -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("rings --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void RingsTest(string parameters)
{
string? expected = "rings --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
string? expected = "rings --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
@@ -109,11 +109,11 @@ namespace MPF.ExecutionContexts.Test
#region Dump
[Theory]
[InlineData("dump -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("dump --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("dump -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("dump --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void DumpTest(string parameters)
{
string? expected = "dump --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
string? expected = "dump --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
@@ -125,11 +125,11 @@ namespace MPF.ExecutionContexts.Test
#region DumpExtra
[Theory]
[InlineData("dump::extra -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("dump::extra --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("dump::extra -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("dump::extra --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void DumpExtraTest(string parameters)
{
string? expected = "dump::extra --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
string? expected = "dump::extra --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
@@ -141,11 +141,11 @@ namespace MPF.ExecutionContexts.Test
#region Refine
[Theory]
[InlineData("refine -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("refine --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("refine -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("refine --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void RefineTest(string parameters)
{
string? expected = "refine --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
string? expected = "refine --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
@@ -157,11 +157,11 @@ namespace MPF.ExecutionContexts.Test
#region Verify
[Theory]
[InlineData("verify -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("verify --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("verify -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("verify --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void VerifyTest(string parameters)
{
string? expected = "verify --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
string? expected = "verify --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
@@ -173,11 +173,11 @@ namespace MPF.ExecutionContexts.Test
#region DVDKey
[Theory]
[InlineData("dvdkey -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("dvdkey --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("dvdkey -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("dvdkey --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void DVDKeyTest(string parameters)
{
string? expected = "dvdkey --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
string? expected = "dvdkey --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
@@ -189,11 +189,11 @@ namespace MPF.ExecutionContexts.Test
#region Eject
[Theory]
[InlineData("eject -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("eject --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("eject -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("eject --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void EjectTest(string parameters)
{
string? expected = "eject --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
string? expected = "eject --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
@@ -205,11 +205,11 @@ namespace MPF.ExecutionContexts.Test
#region DVDIsoKey
[Theory]
[InlineData("dvdisokey -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("dvdisokey --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("dvdisokey -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("dvdisokey --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void DVDIsoKeyTest(string parameters)
{
string? expected = "dvdisokey --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
string? expected = "dvdisokey --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
@@ -221,11 +221,11 @@ namespace MPF.ExecutionContexts.Test
#region Protection
[Theory]
[InlineData("protection -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("protection --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
[InlineData("protection -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("protection --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs --disable-cdtext")]
public void ProtectionTest(string parameters)
{
string? expected = "protection --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
string? expected = "protection --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
@@ -237,11 +237,11 @@ namespace MPF.ExecutionContexts.Test
#region Split
[Theory]
[InlineData("split -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("split --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("split -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("split --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void SplitTest(string parameters)
{
string? expected = "split --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
string? expected = "split --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
@@ -253,11 +253,11 @@ namespace MPF.ExecutionContexts.Test
#region Hash
[Theory]
[InlineData("hash -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("hash --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("hash -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("hash --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void HashTest(string parameters)
{
string? expected = "hash --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
string? expected = "hash --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
@@ -269,11 +269,11 @@ namespace MPF.ExecutionContexts.Test
#region Info
[Theory]
[InlineData("info -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("info --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("info -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("info --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void InfoTest(string parameters)
{
string? expected = "info --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
string? expected = "info --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
@@ -285,11 +285,11 @@ namespace MPF.ExecutionContexts.Test
#region Skeleton
[Theory]
[InlineData("skeleton -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("skeleton --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("skeleton -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("skeleton --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void SkeletonTest(string parameters)
{
string? expected = "skeleton --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
string? expected = "skeleton --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
@@ -301,11 +301,11 @@ namespace MPF.ExecutionContexts.Test
#region Subchannel
[Theory]
[InlineData("subchannel -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("subchannel --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("subchannel -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("subchannel --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void SubchannelTest(string parameters)
{
string? expected = "subchannel --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
string? expected = "subchannel --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
@@ -317,11 +317,11 @@ namespace MPF.ExecutionContexts.Test
#region Debug
[Theory]
[InlineData("debug -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("debug --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("debug -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("debug --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void DebugTest(string parameters)
{
string? expected = "debug --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
string? expected = "debug --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
@@ -333,11 +333,11 @@ namespace MPF.ExecutionContexts.Test
#region FixMSF
[Theory]
[InlineData("fixmsf -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("fixmsf --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("fixmsf -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("fixmsf --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void FixMSFTest(string parameters)
{
string? expected = "fixmsf --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
string? expected = "fixmsf --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
@@ -348,11 +348,11 @@ namespace MPF.ExecutionContexts.Test
#region DebugFlip
[Theory]
[InlineData("debug::flip -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("debug::flip --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("debug::flip -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("debug::flip --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void DebugFlipTest(string parameters)
{
string? expected = "debug::flip --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
string? expected = "debug::flip --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);
@@ -363,11 +363,11 @@ namespace MPF.ExecutionContexts.Test
#region DriveTest
[Theory]
[InlineData("drive::test -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("drive::test --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("drive::test -h --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
[InlineData("drive::test --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=path --image-name=image --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs")]
public void DriveTestTest(string parameters)
{
string? expected = "drive::test --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
string? expected = "drive::test --help --version --verbose --auto-eject --skeleton --drive=dr --speed=8 --retries=0 --image-path=\"path\" --image-name=\"image\" --overwrite --drive-type=dt --drive-read-offset=0 --drive-c2-shift=0 --drive-pregap-start=0 --drive-read-method=drm --drive-sector-order=dso --plextor-skip-leadin --plextor-leadin-retries=0 --asus-skip-leadout --disable-cdtext --force-offset=0 --audio-silence-threshold=0 --correct-offset-shift --offset-shift-relocate --force-split --leave-unchanged --force-qtoc --skip-fill=0 --iso9660-trim --lba-start=0 --lba-end=0 --refine-subchannel --refine-sector-mode --skip=0 --dump-write-offset=0 --dump-read-size=0 --overread-leadout --force-unscrambled --legacy-subs";
var context = new ExecutionContext(parameters);
string? actual = context.GenerateParameters();
Assert.Equal(expected, actual);

View File

@@ -638,11 +638,6 @@ namespace MPF.ExecutionContexts.Aaru
(_inputs[FlagStrings.SpeedLong] as Int8Input)?.SetValue((sbyte)driveSpeed);
}
// First check to see if the combination of system and MediaType is valid
var validTypes = RedumpSystem.MediaTypes();
if (!validTypes.Contains(MediaType))
return;
// Set retry count
int rereadCount = GetInt32Setting(options, SettingConstants.RereadCount, SettingConstants.RereadCountDefault);
if (rereadCount > 0)
@@ -673,57 +668,13 @@ namespace MPF.ExecutionContexts.Aaru
(_inputs[FlagStrings.PrivateLong] as BooleanInput)?.SetValue(true);
}
// TODO: Look at dump-media formats and the like and see what options there are there to fill in defaults
// Now sort based on disc type
switch (MediaType)
{
case SabreTools.RedumpLib.Data.MediaType.CDROM:
// Currently no defaults set
break;
case SabreTools.RedumpLib.Data.MediaType.DVD:
this[FlagStrings.StoreEncryptedLong] = true; // TODO: Make this configurable
(_inputs[FlagStrings.StoreEncryptedLong] as BooleanInput)?.SetValue(true);
this[FlagStrings.TitleKeysLong] = false; // TODO: Make this configurable
(_inputs[FlagStrings.TitleKeysLong] as BooleanInput)?.SetValue(false);
this[FlagStrings.TrimLong] = true; // TODO: Make this configurable
(_inputs[FlagStrings.TrimLong] as BooleanInput)?.SetValue(true);
break;
case SabreTools.RedumpLib.Data.MediaType.GDROM:
// Currently no defaults set
break;
case SabreTools.RedumpLib.Data.MediaType.HDDVD:
this[FlagStrings.StoreEncryptedLong] = true; // TODO: Make this configurable
(_inputs[FlagStrings.StoreEncryptedLong] as BooleanInput)?.SetValue(true);
this[FlagStrings.TitleKeysLong] = false; // TODO: Make this configurable
(_inputs[FlagStrings.TitleKeysLong] as BooleanInput)?.SetValue(false);
this[FlagStrings.TrimLong] = true; // TODO: Make this configurable
(_inputs[FlagStrings.TrimLong] as BooleanInput)?.SetValue(true);
break;
case SabreTools.RedumpLib.Data.MediaType.BluRay:
this[FlagStrings.StoreEncryptedLong] = true; // TODO: Make this configurable
(_inputs[FlagStrings.StoreEncryptedLong] as BooleanInput)?.SetValue(true);
this[FlagStrings.TitleKeysLong] = false; // TODO: Make this configurable
(_inputs[FlagStrings.TitleKeysLong] as BooleanInput)?.SetValue(false);
this[FlagStrings.TrimLong] = true; // TODO: Make this configurable
(_inputs[FlagStrings.TrimLong] as BooleanInput)?.SetValue(true);
break;
// Special Formats
case SabreTools.RedumpLib.Data.MediaType.NintendoGameCubeGameDisc:
// Currently no defaults set
break;
case SabreTools.RedumpLib.Data.MediaType.NintendoWiiOpticalDisc:
// Currently no defaults set
break;
case SabreTools.RedumpLib.Data.MediaType.NintendoWiiUOpticalDisc:
// Currently no defaults set
break;
// Non-optical
case SabreTools.RedumpLib.Data.MediaType.FloppyDisk:
// Currently no defaults set
break;
}
// Set generic, sane defaults to cover all bases
this[FlagStrings.StoreEncryptedLong] = true;
(_inputs[FlagStrings.StoreEncryptedLong] as BooleanInput)?.SetValue(true);
this[FlagStrings.TitleKeysLong] = false;
(_inputs[FlagStrings.TitleKeysLong] as BooleanInput)?.SetValue(false);
this[FlagStrings.TrimLong] = true;
(_inputs[FlagStrings.TrimLong] as BooleanInput)?.SetValue(true);
}
/// <inheritdoc/>

View File

@@ -11,7 +11,7 @@
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<VersionPrefix>3.3.2</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<WarningsNotAsErrors>NU5104</WarningsNotAsErrors>
<!-- Package Properties -->
@@ -32,7 +32,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.RedumpLib" Version="1.6.7" />
<PackageReference Include="SabreTools.RedumpLib" Version="[1.7.4]" />
</ItemGroup>
</Project>

View File

@@ -21,6 +21,8 @@ namespace MPF.ExecutionContexts.Redumper
public const string Info = "info";
public const string Skeleton = "skeleton";
public const string FlashMT1339 = "flash::mt1339";
public const string FlashSD616 = "flash::sd616";
public const string FlashPlextor = "flash::plextor";
public const string Subchannel = "subchannel";
public const string Debug = "debug";
public const string FixMSF = "fixmsf";

View File

@@ -49,11 +49,6 @@ namespace MPF.ExecutionContexts.Redumper
#region Flag Values
/// <summary>
/// Mode being run
/// </summary>
public string? ModeValue { get; set; }
/// <summary>
/// Set of all command flags
/// </summary>
@@ -87,6 +82,7 @@ namespace MPF.ExecutionContexts.Redumper
[FlagStrings.PlextorSkipLeadin] = new FlagInput(FlagStrings.PlextorSkipLeadin),
[FlagStrings.PlextorLeadinRetries] = new Int32Input(FlagStrings.PlextorLeadinRetries),
[FlagStrings.PlextorLeadinForceStore] = new FlagInput(FlagStrings.PlextorLeadinForceStore),
[FlagStrings.KreonPartialSS] = new FlagInput(FlagStrings.KreonPartialSS),
[FlagStrings.AsusSkipLeadout] = new FlagInput(FlagStrings.AsusSkipLeadout),
[FlagStrings.AsusLeadoutRetries] = new Int32Input(FlagStrings.AsusLeadoutRetries),
[FlagStrings.DisableCDText] = new FlagInput(FlagStrings.DisableCDText),
@@ -113,6 +109,7 @@ namespace MPF.ExecutionContexts.Redumper
[FlagStrings.LBAStart] = new Int32Input(FlagStrings.LBAStart),
[FlagStrings.LBAEnd] = new Int32Input(FlagStrings.LBAEnd),
[FlagStrings.RefineSubchannel] = new FlagInput(FlagStrings.RefineSubchannel),
[FlagStrings.RefineSectorMode] = new FlagInput(FlagStrings.RefineSectorMode),
[FlagStrings.Skip] = new StringInput(FlagStrings.Skip),
[FlagStrings.DumpWriteOffset] = new Int32Input(FlagStrings.DumpWriteOffset),
[FlagStrings.DumpReadSize] = new Int32Input(FlagStrings.DumpReadSize),
@@ -183,6 +180,7 @@ namespace MPF.ExecutionContexts.Redumper
FlagStrings.PlextorSkipLeadin,
FlagStrings.PlextorLeadinRetries,
FlagStrings.PlextorLeadinForceStore,
FlagStrings.KreonPartialSS,
FlagStrings.AsusSkipLeadout,
FlagStrings.AsusLeadoutRetries,
FlagStrings.DisableCDText,
@@ -209,6 +207,7 @@ namespace MPF.ExecutionContexts.Redumper
FlagStrings.LBAStart,
FlagStrings.LBAEnd,
FlagStrings.RefineSubchannel,
FlagStrings.RefineSectorMode,
FlagStrings.Skip,
FlagStrings.DumpWriteOffset,
FlagStrings.DumpReadSize,
@@ -237,9 +236,9 @@ namespace MPF.ExecutionContexts.Redumper
var parameters = new StringBuilder();
// Command Mode
ModeValue ??= CommandStrings.NONE;
if (ModeValue != CommandStrings.NONE)
parameters.Append($"{ModeValue} ");
BaseCommand ??= CommandStrings.NONE;
if (BaseCommand != CommandStrings.NONE)
parameters.Append($"{BaseCommand} ");
// Loop though and append all existing
foreach (var kvp in _inputs)
@@ -266,8 +265,8 @@ namespace MPF.ExecutionContexts.Redumper
public override bool IsDumpingCommand()
{
// `dump` command does not provide hashes so will error out after dump if run via MPF
return ModeValue == CommandStrings.NONE
|| ModeValue == CommandStrings.Disc;
return BaseCommand == CommandStrings.NONE
|| BaseCommand == CommandStrings.Disc;
}
/// <inheritdoc/>
@@ -287,25 +286,13 @@ namespace MPF.ExecutionContexts.Redumper
int? driveSpeed,
Dictionary<string, string?> options)
{
BaseCommand = CommandStrings.NONE;
switch (MediaType)
{
case SabreTools.RedumpLib.Data.MediaType.CDROM:
case SabreTools.RedumpLib.Data.MediaType.DVD:
case SabreTools.RedumpLib.Data.MediaType.NintendoGameCubeGameDisc:
case SabreTools.RedumpLib.Data.MediaType.NintendoWiiOpticalDisc:
case SabreTools.RedumpLib.Data.MediaType.HDDVD:
case SabreTools.RedumpLib.Data.MediaType.BluRay:
case SabreTools.RedumpLib.Data.MediaType.NintendoWiiUOpticalDisc:
ModeValue = CommandStrings.Disc;
break;
default:
BaseCommand = null;
return;
}
BaseCommand = CommandStrings.Disc;
this[FlagStrings.Drive] = true;
(_inputs[FlagStrings.Drive] as StringInput)?.SetValue(drivePath ?? string.Empty);
if (drivePath != null)
{
this[FlagStrings.Drive] = true;
(_inputs[FlagStrings.Drive] as StringInput)?.SetValue(drivePath);
}
if (driveSpeed != null && driveSpeed > 0)
{
@@ -326,27 +313,27 @@ namespace MPF.ExecutionContexts.Redumper
}
if (GetBooleanSetting(options, SettingConstants.EnableSkeleton, SettingConstants.EnableSkeletonDefault))
{
// Enable skeleton for CD dumps only by default
// Enable skeleton for CD and DVD only, by default
switch (MediaType)
{
case SabreTools.RedumpLib.Data.MediaType.CDROM:
switch (RedumpSystem)
{
case SabreTools.RedumpLib.Data.RedumpSystem.SuperAudioCD:
break;
default:
this[FlagStrings.Skeleton] = true;
(_inputs[FlagStrings.Skeleton] as FlagInput)?.SetValue(true);
break;
}
case SabreTools.RedumpLib.Data.MediaType.DVD:
this[FlagStrings.Skeleton] = true;
(_inputs[FlagStrings.Skeleton] as FlagInput)?.SetValue(true);
break;
// If the type is unknown, also enable
case null:
this[FlagStrings.Skeleton] = true;
(_inputs[FlagStrings.Skeleton] as FlagInput)?.SetValue(true);
break;
default:
break;
}
}
string? readMethod = GetStringSetting(options, SettingConstants.ReadMethod, SettingConstants.ReadMethodDefault);
if (!string.IsNullOrEmpty(readMethod) && readMethod != ReadMethod.NONE.ToString())
{
this[FlagStrings.DriveReadMethod] = true;
@@ -386,7 +373,7 @@ namespace MPF.ExecutionContexts.Redumper
}
int retries = GetInt32Setting(options, SettingConstants.RereadCount, SettingConstants.RereadCountDefault);
if(retries > 0)
if (retries > 0)
{
this[FlagStrings.Retries] = true;
(_inputs[FlagStrings.Retries] as Int32Input)?.SetValue(retries);
@@ -398,13 +385,17 @@ namespace MPF.ExecutionContexts.Redumper
this[FlagStrings.PlextorLeadinRetries] = true;
(_inputs[FlagStrings.PlextorLeadinRetries] as Int32Input)?.SetValue(leadinRetries);
}
if (GetBooleanSetting(options, SettingConstants.RefineSectorMode, SettingConstants.RefineSectorModeDefault))
{
this[FlagStrings.RefineSectorMode] = true;
(_inputs[FlagStrings.RefineSectorMode] as FlagInput)?.SetValue(true);
}
}
/// <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;
@@ -413,7 +404,7 @@ namespace MPF.ExecutionContexts.Redumper
string[] parts = SplitParameterString(parameters!);
// Setup the modes
ModeValue = null;
BaseCommand = null;
// All modes should be cached separately
int index = 0;
@@ -440,16 +431,18 @@ namespace MPF.ExecutionContexts.Redumper
case CommandStrings.Info:
case CommandStrings.Skeleton:
case CommandStrings.FlashMT1339:
case CommandStrings.FlashSD616:
case CommandStrings.FlashPlextor:
case CommandStrings.Subchannel:
case CommandStrings.Debug:
case CommandStrings.FixMSF:
case CommandStrings.DebugFlip:
case CommandStrings.DriveTest:
// Only allow one mode per command
if (ModeValue != null)
if (BaseCommand != null)
continue;
ModeValue = part;
BaseCommand = part;
break;
// Default is either a flag or an invalid mode

View File

@@ -41,6 +41,7 @@ namespace MPF.ExecutionContexts.Redumper
public const string PlextorSkipLeadin = "--plextor-skip-leadin";
public const string PlextorLeadinRetries = "--plextor-leadin-retries";
public const string PlextorLeadinForceStore = "--plextor-leadin-force-store";
public const string KreonPartialSS = "--kreon-partial-ss";
public const string AsusSkipLeadout = "--asus-skip-leadout";
public const string AsusLeadoutRetries = "--asus-leadout-retries";
public const string DisableCDText = "--disable-cdtext";
@@ -79,6 +80,7 @@ namespace MPF.ExecutionContexts.Redumper
public const string LBAStart = "--lba-start";
public const string LBAEnd = "--lba-end";
public const string RefineSubchannel = "--refine-subchannel";
public const string RefineSectorMode = "--refine-sector-mode";
public const string Skip = "--skip";
public const string DumpWriteOffset = "--dump-write-offset";
public const string DumpReadSize = "--dump-read-size";

View File

@@ -17,6 +17,9 @@ namespace MPF.ExecutionContexts.Redumper
public const string ReadMethod = "RedumperReadMethod";
public static readonly string ReadMethodDefault = Redumper.ReadMethod.NONE.ToString();
public const string RefineSectorMode = "RedumperRefineSectorMode";
public const bool RefineSectorModeDefault = false;
public const string RereadCount = "RedumperRereadCount";
public const int RereadCountDefault = 20;

View File

@@ -22,9 +22,15 @@ namespace MPF.Frontend.Test
? Drive.Create(InternalDriveType.Floppy, letter.ToString())
: Drive.Create(InternalDriveType.Optical, letter.ToString());
var env = new DumpEnvironment(options, string.Empty, drive, RedumpSystem.IBMPCcompatible, mediaType, null, parameters);
var env = new DumpEnvironment(options,
string.Empty,
drive,
RedumpSystem.IBMPCcompatible,
null);
env.SetExecutionContext(mediaType, parameters);
env.SetProcessor();
bool actual = env.ParametersValid();
bool actual = env.ParametersValid(mediaType);
Assert.Equal(expected, actual);
}
}

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using SabreTools.RedumpLib.Data;
using Xunit;
using LogCompression = MPF.Processors.LogCompression;
using RedumperDriveType = MPF.ExecutionContexts.Redumper.DriveType;
using RedumperReadMethod = MPF.ExecutionContexts.Redumper.ReadMethod;
using RedumperSectorOrder = MPF.ExecutionContexts.Redumper.SectorOrder;
@@ -27,6 +28,29 @@ namespace MPF.Frontend.Test
{
string? actual = prog.LongName();
Assert.Equal(expected, actual);
if (prog != null)
{
actual = EnumExtensions.GetLongName(prog);
Assert.Equal(expected, actual);
}
}
[Theory]
[InlineData(null, "Unknown")]
[InlineData(LogCompression.DeflateDefault, "ZIP using Deflate (Level 5)")]
[InlineData(LogCompression.DeflateMaximum, "ZIP using Deflate (Level 9)")]
[InlineData(LogCompression.Zstd19, "ZIP using Zstd (Level 19)")]
public void LongName_LogCompression(LogCompression? comp, string? expected)
{
string? actual = comp.LongName();
Assert.Equal(expected, actual);
if (comp != null)
{
actual = EnumExtensions.GetLongName(comp);
Assert.Equal(expected, actual);
}
}
[Theory]
@@ -38,6 +62,12 @@ namespace MPF.Frontend.Test
{
string? actual = method.LongName();
Assert.Equal(expected, actual);
if (method != null)
{
actual = EnumExtensions.GetLongName(method);
Assert.Equal(expected, actual);
}
}
[Theory]
@@ -51,6 +81,12 @@ namespace MPF.Frontend.Test
{
string? actual = order.LongName();
Assert.Equal(expected, actual);
if (order != null)
{
actual = EnumExtensions.GetLongName(order);
Assert.Equal(expected, actual);
}
}
[Theory]
@@ -67,6 +103,12 @@ namespace MPF.Frontend.Test
{
string? actual = type.LongName();
Assert.Equal(expected, actual);
if (type != null)
{
actual = EnumExtensions.GetLongName(type);
Assert.Equal(expected, actual);
}
}
#endregion

View File

@@ -13,8 +13,8 @@ namespace MPF.Frontend.Test
[InlineData(MediaType.HDDVD, 24)]
[InlineData(MediaType.BluRay, 16)]
[InlineData(MediaType.NintendoWiiUOpticalDisc, 16)]
[InlineData(MediaType.LaserDisc, 1)]
[InlineData(null, 1)]
[InlineData(MediaType.LaserDisc, 72)]
[InlineData(null, 72)]
public void GetAllowedDriveSpeedForMediaTypeTest(MediaType? mediaType, int maxExpected)
{
var actual = InterfaceConstants.GetSpeedsForMediaType(mediaType);

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0;net8.0;net9.0</TargetFrameworks>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
@@ -14,13 +14,13 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeCoverage" Version="17.13.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.6.7" />
<PackageReference Include="Microsoft.CodeCoverage" Version="17.14.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
<PackageReference Include="SabreTools.RedumpLib" Version="[1.7.4]" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.abstractions" Version="2.0.3" />
<PackageReference Include="xunit.analyzers" Version="1.21.0" />
<PackageReference Include="xunit.analyzers" Version="1.24.0" />
<PackageReference Include="xunit.assert" Version="2.9.3" />
<PackageReference Include="xunit.core" Version="2.9.3" />
<PackageReference Include="xunit.extensibility.core" Version="2.9.3" />
@@ -29,7 +29,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.2">
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -81,6 +81,8 @@ namespace MPF.Frontend.Test.Tools
[InlineData("1.2.3.4..bin", true, "1.2.3.4..bin")]
[InlineData("dir/filename.bin", false, "dir/filename.bin")]
[InlineData("dir/filename.bin", true, "dir/filename.bin")]
[InlineData(" dir / filename.bin", false, "dir/filename.bin")]
[InlineData(" dir / filename.bin", true, "dir/filename.bin")]
[InlineData("\0dir/\0filename.bin", false, "_dir/_filename.bin")]
[InlineData("\0dir/\0filename.bin", true, "_dir/_filename.bin")]
public void NormalizeOutputPathsTest(string? path, bool getFullPath, string expected)

View File

@@ -9,24 +9,6 @@ namespace MPF.Frontend.Test.Tools
{
public class InfoToolTests
{
[Theory]
[InlineData(null, "")]
[InlineData(" ", " ")]
[InlineData("super\\blah.bin", "super\\blah.bin")]
[InlineData("super\\hero\\blah.bin", "super\\hero\\blah.bin")]
[InlineData("super.hero\\blah.bin", "super.hero\\blah.bin")]
[InlineData("superhero\\blah.rev.bin", "superhero\\blah.rev.bin")]
[InlineData("super&hero\\blah.bin", "super&hero\\blah.bin")]
[InlineData("superhero\\blah&foo.bin", "superhero\\blah&foo.bin")]
public void NormalizeOutputPathsTest(string? outputPath, string? expectedPath)
{
if (!string.IsNullOrEmpty(expectedPath))
expectedPath = Path.GetFullPath(expectedPath);
string actualPath = FrontendTool.NormalizeOutputPaths(outputPath, true);
Assert.Equal(expectedPath, actualPath);
}
[Fact]
public void ProcessSpecialFieldsCompleteTest()
{

View File

@@ -8,12 +8,114 @@ namespace MPF.Frontend.Test.Tools
{
public class ProtectionToolTests
{
#region SanitizeContextSensitiveProtections
[Fact]
public void SanitizeContextSensitiveProtections_Empty_NoException()
{
Dictionary<string, List<string>>? protections = [];
var actual = ProtectionTool.SanitizeContextSensitiveProtections(protections);
Assert.NotNull(actual);
Assert.Empty(actual);
}
[Fact]
public void SanitizeContextSensitiveProtections_NoMatch_NoChange()
{
Dictionary<string, List<string>>? protections = [];
protections["File1"] = ["Protection 1", "Protection 2"];
var actual = ProtectionTool.SanitizeContextSensitiveProtections(protections);
Assert.NotNull(actual);
string[] keys = [.. actual.Keys];
Assert.Contains("File1", keys);
}
[Fact]
public void SanitizeContextSensitiveProtections_Match_NoSub_NoChange()
{
Dictionary<string, List<string>>? protections = [];
protections["File1"] = ["Protection 1", "Protection 2"];
protections["File2"] = ["SecuROM Release Control - ANYTHING", "Protection 2"];
protections["File3"] = ["Protection 1", "SecuROM Release Control -"];
var actual = ProtectionTool.SanitizeContextSensitiveProtections(protections);
Assert.NotNull(actual);
string[] keys = [.. actual.Keys];
Assert.Contains("File1", keys);
Assert.Contains("File2", keys);
Assert.Contains("File3", keys);
}
[Fact]
public void SanitizeContextSensitiveProtections_Match_Sub_Change()
{
Dictionary<string, List<string>>? protections = [];
protections["File1"] = ["Protection 1", "Protection 2"];
protections["File2"] = ["SecuROM Release Control - ANYTHING"];
protections["File2/FileA"] = ["ANYTHING GitHub ANYTHING"];
protections["File2/FileB"] = ["SecuROM 7"];
protections["File2/FileC"] = ["SecuROM 8"];
protections["File2/FileD"] = ["SecuROM Content Activation"];
protections["File2/FileE"] = ["SecuROM Data File Activation"];
protections["File2/FileF"] = ["Unlock"];
var actual = ProtectionTool.SanitizeContextSensitiveProtections(protections);
Assert.NotNull(actual);
string[] keys = [.. actual.Keys];
Assert.Contains("File1", keys);
Assert.Contains("File2", keys);
Assert.Contains("File2/FileA", keys);
Assert.DoesNotContain("File2/FileB", keys);
Assert.DoesNotContain("File2/FileC", keys);
Assert.DoesNotContain("File2/FileD", keys);
Assert.DoesNotContain("File2/FileE", keys);
Assert.DoesNotContain("File2/FileF", keys);
}
[Fact]
public void SanitizeContextSensitiveProtections_MultiMatch_Sub_Change()
{
Dictionary<string, List<string>>? protections = [];
protections["File1"] = ["Protection 1", "Protection 2"];
protections["File2"] = ["SecuROM Release Control - ANYTHING"];
protections["File2/FileA"] = ["ANYTHING GitHub ANYTHING"];
protections["File2/FileB"] = ["SecuROM 7"];
protections["File2/FileC"] = ["SecuROM 8"];
protections["File3"] = ["SecuROM Release Control - ANYTHING"];
protections["File3/FileD"] = ["SecuROM Content Activation"];
protections["File3/FileE"] = ["SecuROM Data File Activation"];
protections["File3/FileF"] = ["Unlock"];
var actual = ProtectionTool.SanitizeContextSensitiveProtections(protections);
Assert.NotNull(actual);
string[] keys = [.. actual.Keys];
Assert.Contains("File1", keys);
Assert.Contains("File2", keys);
Assert.Contains("File2/FileA", keys);
Assert.DoesNotContain("File2/FileB", keys);
Assert.DoesNotContain("File2/FileC", keys);
Assert.Contains("File3", keys);
Assert.DoesNotContain("File3/FileD", keys);
Assert.DoesNotContain("File3/FileE", keys);
Assert.DoesNotContain("File3/FileF", keys);
}
#endregion
#region SanitizeFoundProtections
[Fact]
public void SanitizeFoundProtections_Exception()
{
List<string> protections =
[
"Anything Else Protection",
"[Access issue when opening file",
"[Exception opening file",
];
@@ -581,9 +683,9 @@ namespace MPF.Frontend.Test.Tools
[Theory]
[InlineData(0, "Macrovision Protected Application [SafeDisc 0.00.000], SafeDisc 0.00.000, SafeDisc Lite")]
[InlineData(1, "Macrovision Protected Application [SafeDisc 0.00.000 / SRV Tool APP], SafeDisc 0.00.000, SafeDisc Lite")]
[InlineData(2, "Macrovision Security Driver, Macrovision Security Driver [SafeDisc 1.11.111], SafeDisc 0.00.000, SafeDisc 0.00.000-1.11.111, SafeDisc Lite")]
[InlineData(3, "Macrovision Security Driver, Macrovision Security Driver [SafeDisc 1.11.111], SafeDisc 0.00.000, SafeDisc Lite")]
[InlineData(4, "Macrovision Security Driver, Macrovision Security Driver [SafeDisc 1.11.111], SafeDisc Lite")]
[InlineData(2, "SafeDisc 0.00.000, SafeDisc 0.00.000-1.11.111, SafeDisc 3+ (DVD), SafeDisc Lite")]
[InlineData(3, "SafeDisc 0.00.000, SafeDisc 3+ (DVD), SafeDisc Lite")]
[InlineData(4, "SafeDisc 3+ (DVD), SafeDisc Lite")]
[InlineData(5, "Macrovision Security Driver, SafeDisc Lite")]
[InlineData(6, "Macrovision Protection File, SafeDisc 2+, SafeDisc 3+ (DVD), SafeDisc Lite")]
[InlineData(7, "SafeDisc 3+ (DVD)")]
@@ -592,11 +694,11 @@ namespace MPF.Frontend.Test.Tools
{
List<string> protections =
[
"Macrovision Protected Application [SafeDisc 0.00.000]",
"Macrovision Protected Application [SafeDisc 0.00.000]",
"Macrovision Protected Application [SafeDisc 0.00.000 / SRV Tool APP]",
"SafeDisc 0.00.000-1.11.111",
"SafeDisc 0.00.000",
"Macrovision Security Driver [SafeDisc 1.11.111]",
"Macrovision Security Driver 1.11.111 / SafeDisc 1.11.111",
"Macrovision Security Driver",
"SafeDisc Lite",
"SafeDisc 3+ (DVD)",
@@ -615,6 +717,38 @@ namespace MPF.Frontend.Test.Tools
Assert.Equal(expected, sanitized);
}
[Fact]
public void SanitizeFoundProtectsion_SafeDisc_MacrovisionSecurityDriver()
{
List<string> protections =
[
"Macrovision Protection File [Likely indicates either SafeDisc 1.45.011+ (CD) or CDS-300]",
"Macrovision Security Driver 4.00.060 / SafeDisc 4.00.000-4.70.000",
"SafeDisc 4.00.000-4.00.003",
"SafeDisc 4.00.002, Macrovision Protected Application"
];
string expected = "SafeDisc 4.00.002";
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Equal(expected, sanitized);
}
[Fact]
public void SanitizeFoundProtections_SecuROM()
{
List<string> protections =
[
"SecuROM Release Control",
"SecuROM Release Control - ANYTHING",
"SecuROM Release Control - ANYTHING ELSE",
"SecuROM Release Control - EVEN MORE",
];
string sanitized = ProtectionTool.SanitizeFoundProtections(protections);
Assert.Equal("SecuROM Release Control", sanitized);
}
[Theory]
[InlineData(0)]
[InlineData(1)]
@@ -669,5 +803,7 @@ namespace MPF.Frontend.Test.Tools
}
#endregion
#endregion
}
}

View File

@@ -61,11 +61,6 @@ namespace MPF.Frontend
/// </summary>
private readonly RedumpSystem? _system;
/// <summary>
/// Currently selected media type
/// </summary>
private readonly MediaType? _type;
#endregion
#region Passthrough Fields
@@ -114,16 +109,12 @@ namespace MPF.Frontend
/// <param name="outputPath"></param>
/// <param name="drive"></param>
/// <param name="system"></param>
/// <param name="type"></param>
/// <param name="internalProgram"></param>
/// <param name="parameters"></param>
public DumpEnvironment(Options options,
string? outputPath,
Drive? drive,
RedumpSystem? system,
MediaType? type,
InternalProgram? internalProgram,
string? parameters)
InternalProgram? internalProgram)
{
// Set options object
_options = options;
@@ -134,12 +125,7 @@ namespace MPF.Frontend
// UI information
_drive = drive;
_system = system ?? options.DefaultSystem;
_type = type ?? MediaType.NONE;
_internalProgram = internalProgram ?? options.InternalProgram;
// Dumping program
SetExecutionContext(parameters);
SetProcessor();
}
#region Internal Program Management
@@ -147,28 +133,28 @@ namespace MPF.Frontend
/// <summary>
/// Check output path for matching logs from all dumping programs
/// </summary>
public InternalProgram? CheckForMatchingProgram(string? outputDirectory, string outputFilename)
public InternalProgram? CheckForMatchingProgram(MediaType? mediaType, string? outputDirectory, string outputFilename)
{
// If a complete dump exists from a different program
InternalProgram? programFound = null;
if (programFound == null && _internalProgram != InternalProgram.Redumper)
{
var processor = new Processors.Redumper(_system, _type);
var missingFiles = processor.FoundAllFiles(outputDirectory, outputFilename);
var processor = new Processors.Redumper(_system);
var missingFiles = processor.FoundAllFiles(mediaType, outputDirectory, outputFilename);
if (missingFiles.Count == 0)
programFound = InternalProgram.Redumper;
}
if (programFound == null && _internalProgram != InternalProgram.DiscImageCreator)
{
var processor = new Processors.DiscImageCreator(_system, _type);
var missingFiles = processor.FoundAllFiles(outputDirectory, outputFilename);
var processor = new Processors.DiscImageCreator(_system);
var missingFiles = processor.FoundAllFiles(mediaType, outputDirectory, outputFilename);
if (missingFiles.Count == 0)
programFound = InternalProgram.DiscImageCreator;
}
if (programFound == null && _internalProgram != InternalProgram.Aaru)
{
var processor = new Processors.Aaru(_system, _type);
var missingFiles = processor.FoundAllFiles(outputDirectory, outputFilename);
var processor = new Processors.Aaru(_system);
var missingFiles = processor.FoundAllFiles(mediaType, outputDirectory, outputFilename);
if (missingFiles.Count == 0)
programFound = InternalProgram.Aaru;
}
@@ -179,26 +165,26 @@ namespace MPF.Frontend
/// <summary>
/// Check output path for partial logs from all dumping programs
/// </summary>
public InternalProgram? CheckForPartialProgram(string? outputDirectory, string outputFilename)
public InternalProgram? CheckForPartialProgram(MediaType? mediaType, string? outputDirectory, string outputFilename)
{
// If a complete dump exists from a different program
InternalProgram? programFound = null;
if (programFound == null && _internalProgram != InternalProgram.Redumper)
{
var processor = new Processors.Redumper(_system, _type);
if (processor.FoundAnyFiles(outputDirectory, outputFilename))
var processor = new Processors.Redumper(_system);
if (processor.FoundAnyFiles(mediaType, outputDirectory, outputFilename))
programFound = InternalProgram.Redumper;
}
if (programFound == null && _internalProgram != InternalProgram.DiscImageCreator)
{
var processor = new Processors.DiscImageCreator(_system, _type);
if (processor.FoundAnyFiles(outputDirectory, outputFilename))
var processor = new Processors.DiscImageCreator(_system);
if (processor.FoundAnyFiles(mediaType, outputDirectory, outputFilename))
programFound = InternalProgram.DiscImageCreator;
}
if (programFound == null && _internalProgram != InternalProgram.Aaru)
{
var processor = new Processors.Aaru(_system, _type);
if (processor.FoundAnyFiles(outputDirectory, outputFilename))
var processor = new Processors.Aaru(_system);
if (processor.FoundAnyFiles(mediaType, outputDirectory, outputFilename))
programFound = InternalProgram.Aaru;
}
@@ -208,8 +194,9 @@ namespace MPF.Frontend
/// <summary>
/// Set the parameters object based on the internal program and parameters string
/// </summary>
/// <param name="mediaType">MediaType for specialized dumping parameters</param>
/// <param name="parameters">String representation of the parameters</param>
public bool SetExecutionContext(string? parameters)
public bool SetExecutionContext(MediaType? mediaType, string? parameters)
{
_executionContext = _internalProgram switch
{
@@ -226,7 +213,7 @@ namespace MPF.Frontend
if (_executionContext != null)
{
_executionContext.RedumpSystem = _system;
_executionContext.MediaType = _type;
_executionContext.MediaType = mediaType;
// Set some parameters, if not already set
OutputPath ??= _executionContext.OutputPath!;
@@ -243,13 +230,13 @@ namespace MPF.Frontend
{
_processor = _internalProgram switch
{
InternalProgram.Aaru => new Processors.Aaru(_system, _type),
InternalProgram.CleanRip => new CleanRip(_system, _type),
InternalProgram.DiscImageCreator => new DiscImageCreator(_system, _type),
InternalProgram.PS3CFW => new PS3CFW(_system, _type),
InternalProgram.Redumper => new Redumper(_system, _type),
InternalProgram.UmdImageCreator => new UmdImageCreator(_system, _type),
InternalProgram.XboxBackupCreator => new XboxBackupCreator(_system, _type),
InternalProgram.Aaru => new Processors.Aaru(_system),
InternalProgram.CleanRip => new CleanRip(_system),
InternalProgram.DiscImageCreator => new DiscImageCreator(_system),
InternalProgram.PS3CFW => new PS3CFW(_system),
InternalProgram.Redumper => new Redumper(_system),
InternalProgram.UmdImageCreator => new UmdImageCreator(_system),
InternalProgram.XboxBackupCreator => new XboxBackupCreator(_system),
// If no dumping program found, set to null
InternalProgram.NONE => null,
@@ -262,12 +249,13 @@ namespace MPF.Frontend
/// <summary>
/// Get the full parameter string for either DiscImageCreator or Aaru
/// </summary>
/// <param name="mediaType">MediaType for specialized dumping parameters</param>
/// <param name="driveSpeed">Nullable int representing the drive speed</param>
/// <returns>String representing the params, null on error</returns>
public string? GetFullParameters(int? driveSpeed)
public string? GetFullParameters(MediaType? mediaType, int? driveSpeed)
{
// Populate with the correct params for inputs (if we're not on the default option)
if (_system != null && _type != MediaType.NONE)
if (_system != null && mediaType != MediaType.NONE)
{
// If drive letter is invalid, skip this
if (_drive == null)
@@ -276,9 +264,9 @@ namespace MPF.Frontend
// Set the proper parameters
_executionContext = _internalProgram switch
{
InternalProgram.Aaru => new ExecutionContexts.Aaru.ExecutionContext(_system, _type, _drive.Name, OutputPath, driveSpeed, _options.Settings),
InternalProgram.DiscImageCreator => new ExecutionContexts.DiscImageCreator.ExecutionContext(_system, _type, _drive.Name, OutputPath, driveSpeed, _options.Settings),
InternalProgram.Redumper => new ExecutionContexts.Redumper.ExecutionContext(_system, _type, _drive.Name, OutputPath, driveSpeed, _options.Settings),
InternalProgram.Aaru => new ExecutionContexts.Aaru.ExecutionContext(_system, mediaType, _drive.Name, OutputPath, driveSpeed, _options.Settings),
InternalProgram.DiscImageCreator => new ExecutionContexts.DiscImageCreator.ExecutionContext(_system, mediaType, _drive.Name, OutputPath, driveSpeed, _options.Settings),
InternalProgram.Redumper => new ExecutionContexts.Redumper.ExecutionContext(_system, mediaType, _drive.Name, OutputPath, driveSpeed, _options.Settings),
// If no dumping program found, set to null
InternalProgram.NONE => null,
@@ -304,9 +292,9 @@ namespace MPF.Frontend
/// </summary>
/// <param name="type">MediaType value to check</param>
/// <returns>True if the media has variable dumping speeds, false otherwise</returns>
public bool DoesSupportDriveSpeed()
public bool DoesSupportDriveSpeed(MediaType? mediaType)
{
return _type switch
return mediaType switch
{
MediaType.CDROM
or MediaType.DVD
@@ -320,22 +308,22 @@ namespace MPF.Frontend
};
}
/// <inheritdoc cref="BaseProcessor.FoundAllFiles(string?, string)"/>
public bool FoundAllFiles(string? outputDirectory, string outputFilename)
/// <inheritdoc cref="BaseProcessor.FoundAllFiles(MediaType?, string?, string)"/>
public bool FoundAllFiles(MediaType? mediaType, string? outputDirectory, string outputFilename)
{
if (_processor == null)
return false;
return _processor.FoundAllFiles(outputDirectory, outputFilename).Count == 0;
return _processor.FoundAllFiles(mediaType, outputDirectory, outputFilename).Count == 0;
}
/// <inheritdoc cref="BaseProcessor.FoundAnyFiles(string?, string)"/>
public bool FoundAnyFiles(string? outputDirectory, string outputFilename)
/// <inheritdoc cref="BaseProcessor.FoundAnyFiles(MediaType?, string?, string)"/>
public bool FoundAnyFiles(MediaType? mediaType, string? outputDirectory, string outputFilename)
{
if (_processor == null)
return false;
return _processor.FoundAnyFiles(outputDirectory, outputFilename);
return _processor.FoundAnyFiles(mediaType, outputDirectory, outputFilename);
}
/// <inheritdoc cref="BaseExecutionContext.GetDefaultExtension(MediaType?)"/>
@@ -359,15 +347,18 @@ namespace MPF.Frontend
/// <summary>
/// Verify that, given a system and a media type, they are correct
/// </summary>
public ResultEventArgs GetSupportStatus()
public ResultEventArgs GetSupportStatus(MediaType? mediaType)
{
// No system chosen, update status
if (_system == null)
return ResultEventArgs.Failure("Please select a valid system");
// If we're on an unsupported type, update the status accordingly
return _type switch
return mediaType switch
{
// Null means it will be handled by the program
null => ResultEventArgs.Success("Ready to dump"),
// Fully supported types
MediaType.BluRay
or MediaType.CDROM
@@ -377,22 +368,22 @@ namespace MPF.Frontend
or MediaType.CompactFlash
or MediaType.SDCard
or MediaType.FlashDrive
or MediaType.HDDVD => ResultEventArgs.Success($"{_type.LongName()} ready to dump"),
or MediaType.HDDVD => ResultEventArgs.Success($"{mediaType.LongName()} ready to dump"),
// Partially supported types
MediaType.GDROM
or MediaType.NintendoGameCubeGameDisc
or MediaType.NintendoWiiOpticalDisc
or MediaType.NintendoWiiUOpticalDisc => ResultEventArgs.Success($"{_type.LongName()} partially supported for dumping"),
or MediaType.NintendoWiiUOpticalDisc => ResultEventArgs.Success($"{mediaType.LongName()} partially supported for dumping"),
// Special case for other supported tools
MediaType.UMD => ResultEventArgs.Failure($"{_type.LongName()} supported for submission info parsing"),
MediaType.UMD => ResultEventArgs.Failure($"{mediaType.LongName()} supported for submission info parsing"),
// Specifically unknown type
MediaType.NONE => ResultEventArgs.Failure($"Please select a valid media type"),
MediaType.NONE => ResultEventArgs.Failure("Please select a valid media type"),
// Undumpable but recognized types
_ => ResultEventArgs.Failure($"{_type.LongName()} media are not supported for dumping"),
_ => ResultEventArgs.Failure($"{mediaType.LongName()} media are not supported for dumping"),
};
}
@@ -420,8 +411,9 @@ namespace MPF.Frontend
/// <summary>
/// Execute the initial invocation of the dumping programs
/// </summary>
/// <param name="mediaType">MediaType for specialized dumping parameters</param>
/// <param name="progress">Optional result progress callback</param>
public async Task<ResultEventArgs> Run(IProgress<ResultEventArgs>? progress = null)
public async Task<ResultEventArgs> Run(MediaType? mediaType, IProgress<ResultEventArgs>? progress = null)
{
// If we don't have parameters
if (_executionContext == null)
@@ -436,7 +428,7 @@ namespace MPF.Frontend
}
// Check that we have the basics for dumping
ResultEventArgs result = IsValidForDump();
ResultEventArgs result = IsValidForDump(mediaType);
if (!result)
return result;
@@ -494,13 +486,10 @@ namespace MPF.Frontend
var outputDirectory = Path.GetDirectoryName(OutputPath);
var outputFilename = Path.GetFileName(OutputPath);
// Check to make sure that the output had all the correct files
List<string> missingFiles = _processor.FoundAllFiles(outputDirectory, outputFilename);
if (missingFiles.Count > 0)
{
resultProgress.Report(ResultEventArgs.Failure($"There were files missing from the output:\n{string.Join("\n", [.. missingFiles])}"));
return ResultEventArgs.Failure("Error! Please check output directory as dump may be incomplete!");
}
// Determine the media type from the processor
MediaType? mediaType = _processor.DetermineMediaType(outputDirectory, outputFilename);
if (mediaType == null)
return ResultEventArgs.Failure("Could not determine the media type from output files...");
// Extract the information from the output files
resultProgress.Report(ResultEventArgs.Success("Extracting output information from output files..."));
@@ -508,12 +497,15 @@ namespace MPF.Frontend
OutputPath,
_drive,
_system,
_type,
mediaType,
_options,
_processor,
resultProgress,
protectionProgress);
resultProgress.Report(ResultEventArgs.Success("Extracting information complete!"));
if (submissionInfo == null)
return ResultEventArgs.Failure("There was an issue extracting information!");
else
resultProgress.Report(ResultEventArgs.Success("Extracting information complete!"));
// Inject seed submission info data, if necessary
if (seedInfo != null)
@@ -526,12 +518,12 @@ namespace MPF.Frontend
// Get user-modifiable information if configured to
if (_options.PromptForDiscInformation && processUserInfo != null)
{
resultProgress.Report(ResultEventArgs.Success("Waiting for additional disc information..."));
resultProgress.Report(ResultEventArgs.Success("Waiting for additional media information..."));
bool? filledInfo = processUserInfo.Invoke(_options, ref submissionInfo);
if (filledInfo == true)
resultProgress.Report(ResultEventArgs.Success("Additional disc information added!"));
resultProgress.Report(ResultEventArgs.Success("Additional media information added!"));
else
resultProgress.Report(ResultEventArgs.Success("Disc information skipped!"));
resultProgress.Report(ResultEventArgs.Success("Media information skipped!"));
}
// Process special fields for site codes
@@ -593,7 +585,7 @@ namespace MPF.Frontend
await Task.Run(() =>
#endif
{
bool compressSuccess = _processor.CompressLogFiles(outputDirectory, outputFilename, filenameSuffix, out string compressResult);
bool compressSuccess = _processor.CompressLogFiles(mediaType, _options.LogCompression, outputDirectory, outputFilename, filenameSuffix, out string compressResult);
if (compressSuccess)
resultProgress.Report(ResultEventArgs.Success(compressResult));
else
@@ -607,7 +599,7 @@ namespace MPF.Frontend
if (_options.DeleteUnnecessaryFiles)
{
resultProgress.Report(ResultEventArgs.Success("Deleting unnecessary files..."));
bool deleteSuccess = _processor.DeleteUnnecessaryFiles(outputDirectory, outputFilename, out string deleteResult);
bool deleteSuccess = _processor.DeleteUnnecessaryFiles(mediaType, outputDirectory, outputFilename, out string deleteResult);
if (deleteSuccess)
resultProgress.Report(ResultEventArgs.Success(deleteResult));
else
@@ -615,10 +607,10 @@ namespace MPF.Frontend
}
// Create PS3 IRD, if required
if (_options.CreateIRDAfterDumping && _system == RedumpSystem.SonyPlayStation3 && _type == MediaType.BluRay)
if (_options.CreateIRDAfterDumping && _system == RedumpSystem.SonyPlayStation3 && mediaType == MediaType.BluRay)
{
resultProgress.Report(ResultEventArgs.Success("Creating IRD... please wait!"));
bool deleteSuccess = await WriteIRD(OutputPath, submissionInfo?.Extras?.DiscKey, submissionInfo?.Extras?.DiscID, submissionInfo?.Extras?.PIC, submissionInfo?.SizeAndChecksums?.Layerbreak, submissionInfo?.SizeAndChecksums?.CRC32);
bool deleteSuccess = await IRDTool.WriteIRD(OutputPath, submissionInfo?.Extras?.DiscKey, submissionInfo?.Extras?.DiscID, submissionInfo?.Extras?.PIC, submissionInfo?.SizeAndChecksums?.Layerbreak, submissionInfo?.SizeAndChecksums?.CRC32);
if (deleteSuccess)
resultProgress.Report(ResultEventArgs.Success("IRD created!"));
else
@@ -633,18 +625,18 @@ namespace MPF.Frontend
/// Checks if the parameters are valid
/// </summary>
/// <returns>True if the configuration is valid, false otherwise</returns>
internal bool ParametersValid()
internal bool ParametersValid(MediaType? mediaType)
{
// Missing drive means it can never be valid
if (_drive == null)
return false;
bool parametersValid = _executionContext?.IsValid() ?? false;
bool floppyValid = !(_drive.InternalDriveType == InternalDriveType.Floppy ^ _type == MediaType.FloppyDisk);
bool floppyValid = !(_drive.InternalDriveType == InternalDriveType.Floppy ^ mediaType == MediaType.FloppyDisk);
// TODO: HardDisk being in the Removable category is a hack, fix this later
bool removableDiskValid = !((_drive.InternalDriveType == InternalDriveType.Removable || _drive.InternalDriveType == InternalDriveType.HardDisk)
^ (_type == MediaType.CompactFlash || _type == MediaType.SDCard || _type == MediaType.FlashDrive || _type == MediaType.HardDisk));
^ (mediaType == MediaType.CompactFlash || mediaType == MediaType.SDCard || mediaType == MediaType.FlashDrive || mediaType == MediaType.HardDisk));
return parametersValid && floppyValid && removableDiskValid;
}
@@ -653,10 +645,10 @@ namespace MPF.Frontend
/// Validate the current environment is ready for a dump
/// </summary>
/// <returns>Result instance with the outcome</returns>
private ResultEventArgs IsValidForDump()
private ResultEventArgs IsValidForDump(MediaType? mediaType)
{
// Validate that everything is good
if (_executionContext == null || !ParametersValid())
if (_executionContext == null || !ParametersValid(mediaType))
return ResultEventArgs.Failure("Error! Current configuration is not supported!");
// Fix the output paths, just in case
@@ -676,7 +668,7 @@ namespace MPF.Frontend
return ResultEventArgs.Failure("Error! Cannot dump same drive that executable resides on!");
// Validate that the current configuration is supported
return GetSupportStatus();
return GetSupportStatus(mediaType);
}
#endregion
@@ -842,66 +834,6 @@ namespace MPF.Frontend
return true;
}
/// <summary>
/// Create an IRD and write it to the specified output directory with optional filename suffix
/// </summary>
/// <param name="outputDirectory">Output folder to use as the base path</param>
/// <param name="filenameSuffix">Optional suffix to append to the filename</param>
/// <param name="outputFilename">Output filename to use as the base path</param>
/// <returns>True on success, false on error</returns>
private static async Task<bool> WriteIRD(string isoPath,
string? discKeyString,
string? discIDString,
string? picString,
long? layerbreak,
string? crc32)
{
try
{
// Output IRD file path
string irdPath = Path.ChangeExtension(isoPath, ".ird");
// Parse disc key from submission info (Required)
byte[]? discKey = ProcessingTool.ParseHexKey(discKeyString);
if (discKey == null)
return false;
// Parse Disc ID from submission info (Optional)
byte[]? discID = ProcessingTool.ParseDiscID(discIDString);
// Parse PIC from submission info (Optional)
byte[]? pic = ProcessingTool.ParsePIC(picString);
// Parse CRC32 strings into ISO hash for Unique ID field (Optional)
uint? uid = ProcessingTool.ParseCRC32(crc32);
// Ensure layerbreak value is valid (Optional)
layerbreak = ProcessingTool.ParseLayerbreak(layerbreak);
// Create Redump-style reproducible IRD
#if NET40
LibIRD.ReIRD ird = await Task.Factory.StartNew(() =>
#else
LibIRD.ReIRD ird = await Task.Run(() =>
#endif
new LibIRD.ReIRD(isoPath, discKey, layerbreak, uid));
if (pic != null)
ird.PIC = pic;
if (discID != null && ird.DiscID[15] != 0x00)
ird.DiscID = discID;
// Write IRD to file
ird.Write(irdPath);
return true;
}
catch (Exception)
{
// We don't care what the error is
return false;
}
}
#endregion
}
}

View File

@@ -6,6 +6,7 @@ using System.Collections.Concurrent;
#endif
using System.Reflection;
using SabreTools.RedumpLib.Data;
using LogCompression = MPF.Processors.LogCompression;
using RedumperDriveType = MPF.ExecutionContexts.Redumper.DriveType;
using RedumperReadMethod = MPF.ExecutionContexts.Redumper.ReadMethod;
using RedumperSectorOrder = MPF.ExecutionContexts.Redumper.SectorOrder;
@@ -61,6 +62,14 @@ namespace MPF.Frontend
}
}
/// <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)
=> ((InternalProgram?)prog).LongName();
/// <summary>
/// Get the string representation of the InternalProgram enum values
/// </summary>
@@ -92,6 +101,31 @@ namespace MPF.Frontend
};
}
/// <summary>
/// Get the string representation of the LogCompression enum values
/// </summary>
/// <param name="comp">LogCompression value to convert</param>
/// <returns>String representing the value, if possible</returns>
public static string LongName(this LogCompression comp)
=> ((LogCompression?)comp).LongName();
/// <summary>
/// Get the string representation of the LogCompression enum values
/// </summary>
/// <param name="comp">LogCompression value to convert</param>
/// <returns>String representing the value, if possible</returns>
public static string LongName(this LogCompression? comp)
{
return comp switch
{
LogCompression.DeflateDefault => "ZIP using Deflate (Level 5)",
LogCompression.DeflateMaximum => "ZIP using Deflate (Level 9)",
LogCompression.Zstd19 => "ZIP using Zstd (Level 19)",
_ => "Unknown",
};
}
/// <summary>
/// Get the string representation of the RedumperReadMethod enum values
/// </summary>
@@ -232,6 +266,28 @@ namespace MPF.Frontend
};
}
/// <summary>
/// Get the LogCompression enum value for a given string
/// </summary>
/// <param name="logCompression">String value to convert</param>
/// <returns>LogCompression represented by teh string, if possible</returns>
public static LogCompression ToLogCompression(this string? logCompression)
{
return (logCompression?.ToLowerInvariant()) switch
{
"deflate"
or "deflatedefault"
or "zip" => LogCompression.DeflateDefault,
"deflatemaximum"
or "max"
or "maximum" => LogCompression.DeflateMaximum,
"zstd"
or "zstd19" => LogCompression.Zstd19,
_ => LogCompression.DeflateDefault,
};
}
/// <summary>
/// Get the RedumperReadMethod enum value for a given string
/// </summary>

View File

@@ -0,0 +1,38 @@
using System;
using SabreTools.CommandLine;
namespace MPF.Frontend.Features
{
public class ListCodesFeature : Feature
{
#region Feature Definition
public const string DisplayName = "listcodes";
private static readonly string[] _flags = ["lc", "listcodes"];
private const string _description = "List supported comment/content site codes";
#endregion
public ListCodesFeature()
: base(DisplayName, _flags, _description)
{
}
/// <inheritdoc/>
public override bool Execute()
{
Console.WriteLine("Supported Site Codes:");
foreach (string siteCode in SabreTools.RedumpLib.Data.Extensions.ListSiteCodes())
{
Console.WriteLine(siteCode);
}
return true;
}
/// <inheritdoc/>
public override bool VerifyInputs() => true;
}
}

View File

@@ -0,0 +1,38 @@
using System;
using SabreTools.CommandLine;
namespace MPF.Frontend.Features
{
public class ListMediaTypesFeature : Feature
{
#region Feature Definition
public const string DisplayName = "listmedia";
private static readonly string[] _flags = ["lm", "listmedia"];
private const string _description = "List supported media types";
#endregion
public ListMediaTypesFeature()
: base(DisplayName, _flags, _description)
{
}
/// <inheritdoc/>
public override bool Execute()
{
Console.WriteLine("Supported Media Types:");
foreach (string mediaType in SabreTools.RedumpLib.Data.Extensions.ListMediaTypes())
{
Console.WriteLine(mediaType);
}
return true;
}
/// <inheritdoc/>
public override bool VerifyInputs() => true;
}
}

View File

@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using SabreTools.CommandLine;
namespace MPF.Frontend.Features
{
public class ListProgramsFeature : Feature
{
#region Feature Definition
public const string DisplayName = "listprograms";
private static readonly string[] _flags = ["lp", "listprograms"];
private const string _description = "List supported dumping program outputs";
#endregion
public ListProgramsFeature()
: base(DisplayName, _flags, _description)
{
}
/// <inheritdoc/>
public override bool Execute()
{
Console.WriteLine("Supported Programs:");
foreach (string program in ListPrograms())
{
Console.WriteLine(program);
}
return true;
}
/// <inheritdoc/>
public override bool VerifyInputs() => true;
/// <summary>
/// List all programs with their short usable names
/// </summary>
private static List<string> ListPrograms()
{
var programs = new List<string>();
foreach (var val in Enum.GetValues(typeof(InternalProgram)))
{
if (((InternalProgram)val!) == InternalProgram.NONE)
continue;
programs.Add($"{((InternalProgram?)val).ShortName()} - {((InternalProgram?)val).LongName()}");
}
return programs;
}
}
}

View File

@@ -0,0 +1,38 @@
using System;
using SabreTools.CommandLine;
namespace MPF.Frontend.Features
{
public class ListSystemsFeature : Feature
{
#region Feature Definition
public const string DisplayName = "listsystems";
private static readonly string[] _flags = ["ls", "listsystems"];
private const string _description = "List supported system types";
#endregion
public ListSystemsFeature()
: base(DisplayName, _flags, _description)
{
}
/// <inheritdoc/>
public override bool Execute()
{
Console.WriteLine("Supported Systems:");
foreach (string system in SabreTools.RedumpLib.Data.Extensions.ListSystems())
{
Console.WriteLine(system);
}
return true;
}
/// <inheritdoc/>
public override bool VerifyInputs() => true;
}
}

View File

@@ -0,0 +1,34 @@
using System;
using MPF.Frontend.Tools;
using SabreTools.CommandLine;
namespace MPF.Frontend.Features
{
public class VersionFeature : Feature
{
#region Feature Definition
public const string DisplayName = "version";
private static readonly string[] _flags = ["version"];
private const string _description = "Display the program version";
#endregion
public VersionFeature()
: base(DisplayName, _flags, _description)
{
}
/// <inheritdoc/>
public override bool Execute()
{
Console.WriteLine(FrontendTool.GetCurrentVersion() ?? "Unknown version");
return true;
}
/// <inheritdoc/>
public override bool VerifyInputs() => true;
}
}

View File

@@ -33,11 +33,6 @@ namespace MPF.Frontend
/// </summary>
public static List<int> BD => _speedValues.FindAll(s => s <= 16);
/// <summary>
/// Set of accepted speeds for all other media
/// </summary>
public static List<int> Unknown => [1];
/// <summary>
/// Get list of all drive speeds for a given MediaType
/// </summary>
@@ -55,7 +50,9 @@ namespace MPF.Frontend
MediaType.HDDVD => HDDVD,
MediaType.BluRay
or MediaType.NintendoWiiUOpticalDisc => BD,
_ => Unknown,
// Default to CD speed range
_ => CD,
};
}
}

View File

@@ -10,7 +10,7 @@
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<VersionPrefix>3.3.2</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<!-- Package Properties -->
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
@@ -31,12 +31,14 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="BinaryObjectScanner" Version="3.3.4" />
<PackageReference Include="LibIRD" Version="0.9.3" />
<PackageReference Include="BinaryObjectScanner" Version="[3.4.5]" />
<PackageReference Include="LibIRD" Version="[1.0.0]" />
<PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0" Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net452`))" />
<PackageReference Include="Microsoft.Net.Http" Version="2.2.29" Condition="$(TargetFramework.StartsWith(`net452`))" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.6.7" />
<PackageReference Include="MinThreadingBridge" Version="0.11.4" Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR $(TargetFramework.StartsWith(`net40`))" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
<PackageReference Include="SabreTools.CommandLine" Version="[1.3.2]" />
<PackageReference Include="SabreTools.RedumpLib" Version="[1.7.4]" />
<PackageReference Include="System.Net.Http" Version="4.3.4" Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net452`))" />
</ItemGroup>

View File

@@ -2,6 +2,7 @@
using SabreTools.RedumpLib.Data;
using AaruSettings = MPF.ExecutionContexts.Aaru.SettingConstants;
using DICSettings = MPF.ExecutionContexts.DiscImageCreator.SettingConstants;
using LogCompression = MPF.Processors.LogCompression;
using RedumperDriveType = MPF.ExecutionContexts.Redumper.DriveType;
using RedumperReadMethod = MPF.ExecutionContexts.Redumper.ReadMethod;
using RedumperSectorOrder = MPF.ExecutionContexts.Redumper.SectorOrder;
@@ -123,6 +124,15 @@ namespace MPF.Frontend
set { Settings["CheckForUpdatesOnStartup"] = value.ToString(); }
}
/// <summary>
/// Try to copy the update URL to the clipboard if one is found
/// </summary>
public bool CopyUpdateUrlToClipboard
{
get { return GetBooleanSetting(Settings, "CopyUpdateUrlToClipboard", true); }
set { Settings["CopyUpdateUrlToClipboard"] = value.ToString(); }
}
/// <summary>
/// Fast update label - Skips disc checks and updates path only
/// </summary>
@@ -149,7 +159,7 @@ namespace MPF.Frontend
get
{
var valueString = GetStringSetting(Settings, "DefaultSystem", RedumpSystem.IBMPCcompatible.LongName());
var valueEnum = Extensions.ToRedumpSystem(valueString ?? string.Empty);
var valueEnum = (valueString ?? string.Empty).ToRedumpSystem();
return valueEnum;
}
set
@@ -427,6 +437,15 @@ namespace MPF.Frontend
set { Settings[RedumperSettings.RereadCount] = value.ToString(); }
}
/// <summary>
/// Enable the refine sector mode flag by default
/// </summary>
public bool RedumperRefineSectorMode
{
get { return GetBooleanSetting(Settings, RedumperSettings.RefineSectorMode, RedumperSettings.RefineSectorModeDefault); }
set { Settings[RedumperSettings.RefineSectorMode] = value.ToString(); }
}
#endregion
#region Extra Dumping Options
@@ -450,7 +469,7 @@ namespace MPF.Frontend
}
/// <summary>
/// Show the disc information window after dumping
/// Show the media information window after dumping
/// </summary>
public bool PromptForDiscInformation
{
@@ -486,7 +505,7 @@ namespace MPF.Frontend
}
/// <summary>
/// Show disc eject reminder before the disc information window is shown
/// Show disc eject reminder before the media information window is shown
/// </summary>
public bool ShowDiscEjectReminder
{
@@ -539,6 +558,22 @@ namespace MPF.Frontend
set { Settings["CompressLogFiles"] = value.ToString(); }
}
/// <summary>
/// Compression type used during log compression
/// </summary>
public LogCompression LogCompression
{
get
{
var valueString = GetStringSetting(Settings, "LogCompression", LogCompression.DeflateMaximum.ToString());
return valueString.ToLogCompression();
}
set
{
Settings["LogCompression"] = value.ToString();
}
}
/// <summary>
/// Delete unnecessary files to reduce space
/// </summary>
@@ -561,15 +596,6 @@ namespace MPF.Frontend
#region Skip Options
/// <summary>
/// Skip detecting media type on disc scan
/// </summary>
public bool SkipMediaTypeDetection
{
get { return GetBooleanSetting(Settings, "SkipMediaTypeDetection", false); }
set { Settings["SkipMediaTypeDetection"] = value.ToString(); }
}
/// <summary>
/// Skip detecting known system on disc scan
/// </summary>

108
MPF.Frontend/Progress.cs Normal file
View File

@@ -0,0 +1,108 @@
#if NET20 || NET35 || NET40
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Threading;
using System.Diagnostics;
namespace MPF.Frontend
{
/// <summary>
/// Provides an IProgress{T} that invokes callbacks for each reported progress value.
/// </summary>
/// <typeparam name="T">Specifies the type of the progress report value.</typeparam>
/// <remarks>
/// Any handler provided to the constructor or event handlers registered with
/// the <see cref="ProgressChanged"/> event are invoked through a
/// <see cref="SynchronizationContext"/> instance captured
/// when the instance is constructed. If there is no current SynchronizationContext
/// at the time of construction, the callbacks will be invoked on the ThreadPool.
/// </remarks>
/// <see href="https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Progress.cs"/>
internal class Progress<T> : IProgress<T> where T : EventArgs
{
/// <summary>The synchronization context captured upon construction. This will never be null.</summary>
private readonly SynchronizationContext? _synchronizationContext;
/// <summary>The handler specified to the constructor. This may be null.</summary>
private readonly Action<T>? _handler;
/// <summary>A cached delegate used to post invocation to the synchronization context.</summary>
private readonly SendOrPostCallback _invokeHandlers;
/// <summary>Initializes the <see cref="Progress{T}"/>.</summary>
public Progress()
{
// Capture the current synchronization context.
// If there is no current context, we use a default instance targeting the ThreadPool.
_synchronizationContext = SynchronizationContext.Current ?? ProgressStatics.DefaultContext;
Debug.Assert(_synchronizationContext != null);
_invokeHandlers = new SendOrPostCallback(InvokeHandlers);
}
/// <summary>Initializes the <see cref="Progress{T}"/> with the specified callback.</summary>
/// <param name="handler">
/// A handler to invoke for each reported progress value. This handler will be invoked
/// in addition to any delegates registered with the <see cref="ProgressChanged"/> event.
/// Depending on the <see cref="SynchronizationContext"/> instance captured by
/// the <see cref="Progress{T}"/> at construction, it's possible that this handler instance
/// could be invoked concurrently with itself.
/// </param>
/// <exception cref="ArgumentNullException">The <paramref name="handler"/> is null (<see langword="Nothing" /> in Visual Basic).</exception>
public Progress(Action<T> handler) : this()
{
_handler = handler ?? throw new ArgumentNullException(nameof(handler));
}
/// <summary>Raised for each reported progress value.</summary>
/// <remarks>
/// Handlers registered with this event will be invoked on the
/// <see cref="SynchronizationContext"/> captured when the instance was constructed.
/// </remarks>
public event EventHandler<T>? ProgressChanged;
/// <summary>Reports a progress change.</summary>
/// <param name="value">The value of the updated progress.</param>
protected virtual void OnReport(T value)
{
// If there's no handler, don't bother going through the sync context.
// Inside the callback, we'll need to check again, in case
// an event handler is removed between now and then.
Action<T>? handler = _handler;
EventHandler<T>? changedEvent = ProgressChanged;
if (handler != null || changedEvent != null)
{
// Post the processing to the sync context.
// (If T is a value type, it will get boxed here.)
_synchronizationContext?.Post(_invokeHandlers, value);
}
}
/// <summary>Reports a progress change.</summary>
/// <param name="value">The value of the updated progress.</param>
void IProgress<T>.Report(T value) { OnReport(value); }
/// <summary>Invokes the action and event callbacks.</summary>
/// <param name="state">The progress value.</param>
private void InvokeHandlers(object? state)
{
T value = (T)state!;
Action<T>? handler = _handler;
EventHandler<T>? changedEvent = ProgressChanged;
handler?.Invoke(value);
changedEvent?.Invoke(this, value);
}
}
/// <summary>Holds static values for <see cref="Progress{T}"/>.</summary>
/// <remarks>This avoids one static instance per type T.</remarks>
internal static class ProgressStatics
{
/// <summary>A default synchronization context that targets the ThreadPool.</summary>
internal static readonly SynchronizationContext DefaultContext = new();
}
}
#endif

View File

@@ -2,6 +2,7 @@ using System;
using System.IO;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using SabreTools.RedumpLib.Data;
namespace MPF.Frontend.Tools
@@ -522,7 +523,6 @@ namespace MPF.Frontend.Tools
/// <param name="path">Path value to normalize</param>
public static string NormalizeOutputPaths(string? path, bool getFullPath)
{
// The easy way
try
{
// If we have an invalid path
@@ -536,21 +536,27 @@ namespace MPF.Frontend.Tools
// Remove invalid path characters
foreach (char c in Path.GetInvalidPathChars())
{
path = path.Replace(c, '_');
}
// Try getting the combined path and returning that directly
string fullPath = getFullPath ? Path.GetFullPath(path) : path;
var fullDirectory = Path.GetDirectoryName(fullPath);
string fullFile = Path.GetFileName(fullPath);
var fullDirectory = Path.GetDirectoryName(fullPath)?.Trim();
string fullFile = Path.GetFileName(fullPath).Trim();
// Remove invalid filename characters
foreach (char c in Path.GetInvalidFileNameChars())
{
fullFile = fullFile.Replace(c, '_');
}
if (string.IsNullOrEmpty(fullDirectory))
return fullFile;
else
return Path.Combine(fullDirectory, fullFile);
// Rebuild the path, if necessary
if (!string.IsNullOrEmpty(fullDirectory))
fullFile = Path.Combine(fullDirectory, fullFile);
// Remove spaces before and after separators
return Regex.Replace(fullFile, @"\s*([\\|/])\s*", @"$1");
}
catch { }

View File

@@ -0,0 +1,99 @@
using System;
using System.IO;
using System.Threading.Tasks;
using MPF.Processors;
namespace MPF.Frontend.Tools
{
internal static class IRDTool
{
/// <summary>
/// Create an IRD and write it next to the input ISO path
/// </summary>
/// <param name="isoPath">Path to the original ISO</param>
/// <param name="discKeyString">Required hexadecimal disc key as a string</param>
/// <param name="discIDString">Optional hexadecimal disc ID as a string</param>
/// <param name="picString">Optional string representation of the PIC information</param>
/// <param name="layerbreak">Optional disc layerbreak value</param>
/// <param name="crc32">Optional ISO CRC-32 value for the Unique ID field</param>
/// <returns>True on success, false on error</returns>
public static async Task<bool> WriteIRD(string isoPath,
string? discKeyString,
string? discIDString,
string? picString,
long? layerbreak,
string? crc32)
{
try
{
// Parse string values into required formats
byte[]? discKey = ProcessingTool.ParseHexKey(discKeyString);
byte[]? discID = ProcessingTool.ParseDiscID(discIDString);
byte[]? pic = ProcessingTool.ParsePIC(picString);
uint? uid = ProcessingTool.ParseCRC32(crc32);
return await WriteIRD(isoPath, discKey, discID, pic, layerbreak, uid);
}
catch (Exception)
{
// We don't care what the error is
return false;
}
}
/// <summary>
/// Create an IRD and write it next to the input ISO path
/// </summary>
/// <param name="isoPath">Path to the original ISO</param>
/// <param name="discKey">Required hexadecimal disc key as a byte array</param>
/// <param name="discID">Optional hexadecimal disc ID as a byte array</param>
/// <param name="pic">Optional byte array representation of the PIC information</param>
/// <param name="layerbreak">Optional disc layerbreak value</param>
/// <param name="uid">Optional ISO CRC-32 value for the Unique ID field</param>
/// <returns>True on success, false on error</returns>
public static async Task<bool> WriteIRD(string isoPath,
byte[]? discKey,
byte[]? discID,
byte[]? pic,
long? layerbreak,
uint? uid)
{
try
{
// Fail on a missing disc key
if (discKey == null)
return false;
// Output IRD file path
string irdPath = Path.ChangeExtension(isoPath, ".ird");
// Ensure layerbreak value is valid
layerbreak = ProcessingTool.ParseLayerbreak(layerbreak);
// Create Redump-style reproducible IRD
#if NET40
LibIRD.ReIRD ird = await Task.Factory.StartNew(() =>
#else
LibIRD.ReIRD ird = await Task.Run(() =>
#endif
new LibIRD.ReIRD(isoPath, discKey, layerbreak, uid));
// Set optional fields if valid
if (pic != null)
ird.PIC = pic;
if (discID != null && ird.DiscID[15] != 0x00)
ird.DiscID = discID;
// Write IRD to file
ird.Write(irdPath);
return true;
}
catch (Exception)
{
// We don't care what the error is
return false;
}
}
}
}

View File

@@ -32,97 +32,6 @@ namespace MPF.Frontend.Tools
#region Arguments
/// <summary>
/// Process any standalone arguments for the program
/// </summary>
/// <returns>True if one of the arguments was processed, false otherwise</returns>
public static bool? ProcessStandaloneArguments(string[] args)
{
// Help options
if (args.Length == 0 || args[0] == "-h" || args[0] == "-?")
return null;
// List options
if (args[0] == "-lc" || args[0] == "--listcodes")
{
Console.WriteLine("Supported Site Codes:");
foreach (string siteCode in Extensions.ListSiteCodes())
{
Console.WriteLine(siteCode);
}
return true;
}
else if (args[0] == "-lm" || args[0] == "--listmedia")
{
Console.WriteLine("Supported Media Types:");
foreach (string mediaType in Extensions.ListMediaTypes())
{
Console.WriteLine(mediaType);
}
return true;
}
else if (args[0] == "-lp" || args[0] == "--listprograms")
{
Console.WriteLine("Supported Programs:");
foreach (string program in ListPrograms())
{
Console.WriteLine(program);
}
return true;
}
else if (args[0] == "-ls" || args[0] == "--listsystems")
{
Console.WriteLine("Supported Systems:");
foreach (string system in Extensions.ListSystems())
{
Console.WriteLine(system);
}
return true;
}
return false;
}
/// <summary>
/// Process common arguments for all functionality
/// </summary>
/// <returns>True if all arguments pass, false otherwise</returns>
public static bool ProcessCommonArguments(string[] args, out MediaType mediaType, out RedumpSystem? system, out string? message)
{
// All other use requires at least 3 arguments
if (args.Length < 3)
{
mediaType = MediaType.NONE;
system = null;
message = "Invalid number of arguments";
return false;
}
// Check the MediaType
mediaType = ToMediaType(args[0].Trim('"'));
if (mediaType == MediaType.NONE)
{
system = null;
message = $"{args[0]} is not a recognized media type";
return false;
}
// Check the RedumpSystem
system = Extensions.ToRedumpSystem(args[1].Trim('"'));
if (system == null)
{
message = $"{args[1]} is not a recognized system";
return false;
}
message = null;
return true;
}
/// <summary>
/// Get the MediaType enum value for a given string
/// </summary>
@@ -266,24 +175,6 @@ namespace MPF.Frontend.Tools
};
}
/// <summary>
/// List all programs with their short usable names
/// </summary>
private static List<string> ListPrograms()
{
var programs = new List<string>();
foreach (var val in Enum.GetValues(typeof(InternalProgram)))
{
if (((InternalProgram)val!) == InternalProgram.NONE)
continue;
programs.Add($"{((InternalProgram?)val).ShortName()} - {((InternalProgram?)val).LongName()}");
}
return programs;
}
#endregion
#region Configuration
@@ -297,12 +188,9 @@ namespace MPF.Frontend.Tools
if (string.IsNullOrEmpty(ConfigurationPath))
return new Options();
// Ensure the file exists
// If the file does not exist
if (!File.Exists(ConfigurationPath) || new FileInfo(ConfigurationPath).Length == 0)
{
File.Create(ConfigurationPath).Dispose();
return new Options();
}
var serializer = JsonSerializer.Create();
var stream = File.Open(ConfigurationPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

View File

@@ -545,11 +545,11 @@ namespace MPF.Frontend.Tools
// Read the app.pkg header
using var fileStream = new FileStream(appPkgPath, FileMode.Open, FileAccess.Read);
var appPkgHeaderDeserializer = new SabreTools.Serialization.Deserializers.AppPkgHeader();
var appPkgHeaderDeserializer = new SabreTools.Serialization.Readers.AppPkgHeader();
var appPkgHeader = appPkgHeaderDeserializer.Deserialize(fileStream);
if (appPkgHeader != null)
pkgInfo += $"{appPkgHeader.ContentID}" + Environment.NewLine;
pkgInfo += $"{appPkgHeader.ContentID}{Environment.NewLine}";
}
if (pkgInfo == "")
@@ -696,11 +696,11 @@ namespace MPF.Frontend.Tools
// Read the app_sc.pkg header
using var fileStream = new FileStream(appPkgPath, FileMode.Open, FileAccess.Read);
var appPkgHeaderDeserializer = new SabreTools.Serialization.Deserializers.AppPkgHeader();
var appPkgHeaderDeserializer = new SabreTools.Serialization.Readers.AppPkgHeader();
var appPkgHeader = appPkgHeaderDeserializer.Deserialize(fileStream);
if (appPkgHeader != null)
pkgInfo += $"{appPkgHeader.ContentID}" + Environment.NewLine;
pkgInfo += $"{appPkgHeader.ContentID}{Environment.NewLine}";
}
if (pkgInfo == "")

View File

@@ -72,7 +72,7 @@ namespace MPF.Frontend.Tools
/// <param name="options">Options object that determines what to scan</param>
/// <param name="progress">Optional progress callback</param>
/// <returns>Set of all detected copy protections with an optional error string</returns>
public static async Task<ProtectionDictionary> RunProtectionScanOnPath(string path,
public static async Task<Dictionary<string, List<string>>> RunProtectionScanOnPath(string path,
Options options,
IProgress<ProtectionProgress>? progress = null)
{
@@ -97,9 +97,6 @@ namespace MPF.Frontend.Tools
if (found == null || found.Count == 0)
return [];
// Filter out any empty protections
found.ClearEmptyKeys();
// Return the filtered set of protections
return found;
}
@@ -109,7 +106,7 @@ namespace MPF.Frontend.Tools
/// </summary>
/// <param name="protections">Dictionary of file to list of protection mappings</param>
/// <returns>Detected protections, if any</returns>
public static string? FormatProtections(ProtectionDictionary? protections)
public static string? FormatProtections(Dictionary<string, List<string>>? protections)
{
// If the filtered list is empty in some way, return
if (protections == null)
@@ -117,6 +114,9 @@ namespace MPF.Frontend.Tools
else if (protections.Count == 0)
return "None found [OMIT FROM SUBMISSION]";
// Sanitize context-sensitive protections
protections = SanitizeContextSensitiveProtections(protections);
// Get a list of distinct found protections
#if NET20
var protectionValues = new List<string>();
@@ -137,7 +137,7 @@ namespace MPF.Frontend.Tools
.Distinct()
.ToList();
#endif
// Sanitize and join protections for writing
string protectionString = SanitizeFoundProtections(protectionValues);
if (string.IsNullOrEmpty(protectionString))
@@ -166,7 +166,7 @@ namespace MPF.Frontend.Tools
try
{
var antiModchip = new BinaryObjectScanner.Protection.PSXAntiModchip();
foreach (string file in IOExtensions.SafeGetFiles(path!, "*", SearchOption.AllDirectories))
foreach (string file in path!.SafeGetFiles("*", SearchOption.AllDirectories))
{
try
{
@@ -184,6 +184,66 @@ namespace MPF.Frontend.Tools
});
}
/// <summary>
/// Sanitize unnecessary protections where context matters
/// </summary>
/// <param name="protections">Dictionary of file to list of protection mappings</param>
/// <returns>Dictionary with all necessary items filtered out</returns>
public static Dictionary<string, List<string>> SanitizeContextSensitiveProtections(Dictionary<string, List<string>> protections)
{
// Setup the output dictionary
Dictionary<string, List<string>> filtered = [];
// Setup a list for keys that need additional processing
List<string> foundKeys = [];
// Loop through the keys and add relevant ones
string[] paths = [.. protections.Keys];
foreach (var path in paths)
{
if (!protections.TryGetValue(path, out var values) || values == null || values.Count == 0)
continue;
// Always copy the values if they're valid
filtered[path] = values;
if (values.Exists(s => s.StartsWith("SecuROM Release Control -")))
foundKeys.Add(path);
}
// If there are no keys found
if (foundKeys.Count == 0)
return filtered;
// Process the keys as necessary
foreach (var key in foundKeys)
{
// Get all matching paths
var matchingPaths = Array.FindAll(paths, s => s != key && s.StartsWith(key));
if (matchingPaths.Length == 0)
continue;
// Loop through the matching paths
foreach (var path in matchingPaths)
{
if (!filtered.TryGetValue(path, out var values) || values == null || values.Count == 0)
continue;
if (values.Exists(s => !s.Contains("GitHub") &&
(s.Contains("SecuROM 7")
|| s.Contains("SecuROM 8")
|| s.Contains("SecuROM Content Activation")
|| s.Contains("SecuROM Data File Activation")
|| s.Contains("Unlock"))))
{
filtered.Remove(path);
}
}
}
return filtered;
}
/// <summary>
/// Sanitize unnecessary protection duplication from output
/// </summary>
@@ -200,7 +260,12 @@ namespace MPF.Frontend.Tools
// EXCEPTIONS
if (foundProtections.Exists(p => p.StartsWith("[Exception opening file")))
{
foundProtections = foundProtections.FindAll(p => !p.StartsWith("[Exception opening file"));
foundProtections = foundProtections.FindAll(p => !p.StartsWith("[Exception opening file") && !p.StartsWith("[Access issue when opening file"));
foundProtections.Add("Exception occurred while scanning [RESCAN NEEDED]");
}
if (foundProtections.Exists(p => p.StartsWith("[Access issue when opening file")))
{
foundProtections = foundProtections.FindAll(p => !p.StartsWith("[Exception opening file") && !p.StartsWith("[Access issue when opening file"));
foundProtections.Add("Exception occurred while scanning [RESCAN NEEDED]");
}
@@ -310,9 +375,8 @@ namespace MPF.Frontend.Tools
// Best case scenario for SafeDisc 2+: A full SafeDisc version is found in a line starting with "Macrovision Protected Application".
// All other SafeDisc detections can be safely scrubbed.
// TODO: Scrub "Macrovision Protected Application, " from before the SafeDisc version.
if (foundProtections.Exists(p => Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled)
&& p.StartsWith("Macrovision Protected Application")
&& p.Contains("Macrovision Protected Application")
&& !p.Contains("SRV Tool APP")))
{
foundProtections = foundProtections.FindAll(p => !p.StartsWith("Macrovision Protection File"))
@@ -326,11 +390,14 @@ namespace MPF.Frontend.Tools
.FindAll(p => p != "SafeDisc 1/Lite")
.FindAll(p => p != "SafeDisc 2+")
.FindAll(p => p != "SafeDisc 3+ (DVD)");
foundProtections = foundProtections.ConvertAll(p => p
.Replace("Macrovision Protected Application, ", string.Empty)
.Replace(", Macrovision Protected Application", string.Empty));
}
// Next best case for SafeDisc 2+: A full SafeDisc version is found from the "SafeDisc SRV Tool APP".
else if (foundProtections.Exists(p => Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled)
&& p.StartsWith("Macrovision Protected Application")
&& p.Contains("Macrovision Protected Application")
&& p.Contains("SRV Tool APP")))
{
foundProtections = foundProtections.FindAll(p => !p.StartsWith("Macrovision Protection File"))
@@ -374,7 +441,6 @@ namespace MPF.Frontend.Tools
}
// Next best case for SafeDisc 1: A SafeDisc version range is found from "SECDRV.SYS".
// TODO: Scrub "Macrovision Security Driver {Version}" from before the SafeDisc version.
else if (foundProtections.Exists(p => p.StartsWith("Macrovision Security Driver")
&& Regex.IsMatch(p, @"SafeDisc 1\.[0-9]{2}\.[0-9]{3}-[1-2]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled)
|| Regex.IsMatch(p, @"SafeDisc 1\.[0-9]{2}\.[0-9]{3}$")))
@@ -386,10 +452,12 @@ namespace MPF.Frontend.Tools
.FindAll(p => p != "SafeDisc")
.FindAll(p => p != "SafeDisc 1")
.FindAll(p => p != "SafeDisc 1/Lite");
foundProtections = foundProtections.ConvertAll(p => p.StartsWith("Macrovision Security Driver") && p.Split('/').Length > 1
? p.Split('/')[1].TrimStart()
: p);
}
// Next best case for SafeDisc 2+: A SafeDisc version range is found from "SECDRV.SYS".
// TODO: Scrub "Macrovision Security Driver {Version}" from before the SafeDisc version.
else if (foundProtections.Exists(p => p.StartsWith("Macrovision Security Driver")))
{
foundProtections = foundProtections.FindAll(p => !p.StartsWith("Macrovision Protection File"))
@@ -401,6 +469,9 @@ namespace MPF.Frontend.Tools
.FindAll(p => p != "SafeDisc 1/Lite")
.FindAll(p => p != "SafeDisc 2+")
.FindAll(p => p != "SafeDisc 3+ (DVD)");
foundProtections = foundProtections.ConvertAll(p => p.StartsWith("Macrovision Security Driver") && p.Split('/').Length > 1
? p.Split('/')[1].TrimStart()
: p);
}
// Only SafeDisc Lite is found.
@@ -429,7 +500,11 @@ namespace MPF.Frontend.Tools
}
// SecuROM
// TODO: Figure this one out
if (foundProtections.Exists(p => p.StartsWith("SecuROM Release Control")))
{
foundProtections = foundProtections.FindAll(p => !p.StartsWith("SecuROM Release Control"));
foundProtections.Add("SecuROM Release Control");
}
// SolidShield
// TODO: Figure this one out

View File

@@ -51,16 +51,12 @@ namespace MPF.Frontend.Tools
IProgress<ResultEventArgs>? resultProgress = null,
IProgress<ProtectionProgress>? protectionProgress = null)
{
// Ensure the current disc combination should exist
if (!system.MediaTypes().Contains(mediaType))
return null;
// Split the output path for easier use
var outputDirectory = Path.GetDirectoryName(outputPath);
string outputFilename = Path.GetFileName(outputPath);
// Check that all of the relevant files are there
List<string> missingFiles = processor.FoundAllFiles(outputDirectory, outputFilename);
List<string> missingFiles = processor.FoundAllFiles(mediaType, outputDirectory, outputFilename);
if (missingFiles.Count > 0)
{
resultProgress?.Report(ResultEventArgs.Failure($"There were files missing from the output:\n{string.Join("\n", [.. missingFiles])}"));
@@ -77,9 +73,9 @@ namespace MPF.Frontend.Tools
SubmissionInfo info = CreateDefaultSubmissionInfo(processor, system, mediaType, options.AddPlaceholders);
// Get specific tool output handling
processor?.GenerateSubmissionInfo(info, basePath, options.EnableRedumpCompatibility);
processor.GenerateSubmissionInfo(info, mediaType, basePath, options.EnableRedumpCompatibility);
if (options.IncludeArtifacts)
info.Artifacts = processor?.GenerateArtifacts(outputDirectory, outputFilename);
info.Artifacts = processor.GenerateArtifacts(mediaType, outputDirectory, outputFilename);
// Add a placeholder for the logs link
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.LogsLink] = "[Please provide a link to your logs here]";
@@ -93,7 +89,7 @@ namespace MPF.Frontend.Tools
info.TracksAndWriteOffsets.ClrMameProData = null;
// Add the volume label to comments, if possible or necessary
string? volLabels = FormatVolumeLabels(drive?.VolumeLabel, processor?.VolumeLabels);
string? volLabels = FormatVolumeLabels(drive?.VolumeLabel, processor.VolumeLabels);
if (volLabels != null)
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.VolumeLabel] = volLabels;
@@ -116,7 +112,7 @@ namespace MPF.Frontend.Tools
{
resultProgress?.Report(ResultEventArgs.Success("Running copy protection scan... this might take a while!"));
ProtectionDictionary? protections = null;
Dictionary<string, List<string>>? protections = null;
try
{
if (options.ScanForProtection && drive?.Name != null)
@@ -171,9 +167,9 @@ namespace MPF.Frontend.Tools
// Login to Redump, if possible
var wc = new RedumpClient();
if (options.RedumpUsername != null && options.RedumpPassword != null)
if (!string.IsNullOrEmpty(options.RedumpUsername) && !string.IsNullOrEmpty(options.RedumpPassword))
{
bool? loggedIn = await wc.Login(options.RedumpUsername, options.RedumpPassword);
bool? loggedIn = await wc.Login(options.RedumpUsername!, options.RedumpPassword!);
if (loggedIn == null)
{
resultProgress?.Report(ResultEventArgs.Failure("There was an unknown error connecting to Redump, skipping..."));
@@ -459,6 +455,11 @@ namespace MPF.Frontend.Tools
if (driveLabel != null && driveLabel.Length == 0)
driveLabel = null;
// Treat "path" labels as null -- Indicates a mounted path
// This can over-match if a label contains a directory separator somehow
if (driveLabel != null && (driveLabel.Contains("/") || driveLabel.Contains("\\")))
driveLabel = null;
// Must have at least one label to format
if (driveLabel == null && (labels == null || labels.Count == 0))
return null;
@@ -997,7 +998,7 @@ namespace MPF.Frontend.Tools
/// <summary>
/// Set a comment field if it doesn't already have a value
/// </summary>
private static void SetCommentFieldIfNotExists(SubmissionInfo info, SiteCode key, Drive? drive, Func<Drive?, string?> valueFunc)
private static void SetCommentFieldIfNotExists(SubmissionInfo info, SiteCode key, Drive? drive, System.Func<Drive?, string?> valueFunc)
{
// If the field has a valid value, skip
if (CommentFieldExists(info, key, out _))
@@ -1061,7 +1062,7 @@ namespace MPF.Frontend.Tools
/// </summary>
/// <param name="oldDict">ProtectionDictionary to format</param>
/// <returns>Reformatted dictionary on success, empty on error</returns>
private static Dictionary<string, List<string>?> ReformatProtectionDictionary(ProtectionDictionary? oldDict)
private static Dictionary<string, List<string>?> ReformatProtectionDictionary(Dictionary<string, List<string>>? oldDict)
{
// Null or empty protections return empty
if (oldDict == null || oldDict.Count == 0)

View File

@@ -66,34 +66,6 @@ namespace MPF.Frontend.ViewModels
}
private bool _systemTypeComboBoxEnabled;
/// <summary>
/// Currently selected media type value
/// </summary>
public MediaType? CurrentMediaType
{
get => _currentMediaType;
set
{
_currentMediaType = value;
TriggerPropertyChanged(nameof(CurrentMediaType));
}
}
private MediaType? _currentMediaType;
/// <summary>
/// Indicates the status of the media type combo box
/// </summary>
public bool MediaTypeComboBoxEnabled
{
get => _mediaTypeComboBoxEnabled;
set
{
_mediaTypeComboBoxEnabled = value;
TriggerPropertyChanged(nameof(MediaTypeComboBoxEnabled));
}
}
private bool _mediaTypeComboBoxEnabled;
/// <summary>
/// Currently provided input path
/// </summary>
@@ -229,20 +201,6 @@ namespace MPF.Frontend.ViewModels
#region List Properties
/// <summary>
/// Current list of supported media types
/// </summary>
public List<Element<MediaType>>? MediaTypes
{
get => _mediaTypes;
set
{
_mediaTypes = value;
TriggerPropertyChanged(nameof(MediaTypes));
}
}
private List<Element<MediaType>>? _mediaTypes;
/// <summary>
/// Current list of supported system profiles
/// </summary>
@@ -287,16 +245,13 @@ namespace MPF.Frontend.ViewModels
SystemTypeComboBoxEnabled = true;
InputPathTextBoxEnabled = true;
InputPathBrowseButtonEnabled = true;
MediaTypeComboBoxEnabled = true;
DumpingProgramComboBoxEnabled = true;
CheckDumpButtonEnabled = false;
CancelButtonEnabled = true;
MediaTypes = [];
Systems = RedumpSystemComboBoxItem.GenerateElements();
InternalPrograms = [];
PopulateMediaType();
PopulateInternalPrograms();
EnableEventHandlers();
}
@@ -327,15 +282,6 @@ namespace MPF.Frontend.ViewModels
/// Change the currently selected system
/// </summary>
public void ChangeSystem()
{
PopulateMediaType();
CheckDumpButtonEnabled = ShouldEnableCheckDumpButton();
}
/// <summary>
/// Change the currently selected media type
/// </summary>
public void ChangeMediaType()
{
CheckDumpButtonEnabled = ShouldEnableCheckDumpButton();
}
@@ -369,7 +315,6 @@ namespace MPF.Frontend.ViewModels
InputPathTextBoxEnabled = true;
InputPathBrowseButtonEnabled = true;
DumpingProgramComboBoxEnabled = true;
PopulateMediaType();
CheckDumpButtonEnabled = ShouldEnableCheckDumpButton();
CancelButtonEnabled = true;
}
@@ -382,7 +327,6 @@ namespace MPF.Frontend.ViewModels
SystemTypeComboBoxEnabled = false;
InputPathTextBoxEnabled = false;
InputPathBrowseButtonEnabled = false;
MediaTypeComboBoxEnabled = false;
DumpingProgramComboBoxEnabled = false;
CheckDumpButtonEnabled = false;
CancelButtonEnabled = false;
@@ -392,35 +336,6 @@ namespace MPF.Frontend.ViewModels
#region Population
/// <summary>
/// Populate media type according to system type
/// </summary>
private void PopulateMediaType()
{
// Disable other UI updates
bool cachedCanExecuteSelectionChanged = CanExecuteSelectionChanged;
DisableEventHandlers();
if (CurrentSystem != null)
{
var mediaTypeValues = CurrentSystem.MediaTypes();
int index = mediaTypeValues.FindIndex(m => m == CurrentMediaType);
MediaTypes = mediaTypeValues.ConvertAll(m => new Element<MediaType>(m ?? MediaType.NONE));
MediaTypeComboBoxEnabled = MediaTypes.Count > 1;
CurrentMediaType = (index > -1 ? MediaTypes[index] : MediaTypes[0]);
}
else
{
MediaTypeComboBoxEnabled = false;
MediaTypes = null;
CurrentMediaType = null;
}
// Reenable event handlers, if necessary
if (cachedCanExecuteSelectionChanged) EnableEventHandlers();
}
/// <summary>
/// Populate media type according to system type
/// </summary>
@@ -451,7 +366,7 @@ namespace MPF.Frontend.ViewModels
private bool ShouldEnableCheckDumpButton()
{
return CurrentSystem != null && CurrentMediaType != null && !string.IsNullOrEmpty(InputPath);
return CurrentSystem != null && !string.IsNullOrEmpty(InputPath);
}
/// <summary>
@@ -478,13 +393,13 @@ namespace MPF.Frontend.ViewModels
/// Performs MPF.Check functionality
/// </summary>
/// <returns>An error message if failed, otherwise string.Empty/null</returns>
public async Task<string?> CheckDump(ProcessUserInfoDelegate processUserInfo)
public async Task<ResultEventArgs> CheckDump(ProcessUserInfoDelegate processUserInfo)
{
if (string.IsNullOrEmpty(InputPath))
return "Invalid Input path";
return ResultEventArgs.Failure("Invalid Input path");
if (!File.Exists(InputPath!.Trim('"')))
return "Input Path is not a valid file";
return ResultEventArgs.Failure("Input Path is not a valid file");
// Disable UI while Check is running
DisableUIElements();
@@ -502,9 +417,8 @@ namespace MPF.Frontend.ViewModels
Path.GetFullPath(InputPath.Trim('"')),
null,
CurrentSystem,
CurrentMediaType,
CurrentProgram,
parameters: null);
CurrentProgram);
env.SetProcessor();
// Finally, attempt to do the output dance
var result = await env.VerifyAndSaveDumpOutput(
@@ -517,7 +431,7 @@ namespace MPF.Frontend.ViewModels
if (cachedCanExecuteSelectionChanged)
EnableEventHandlers();
return result.Message;
return result;
}
/// <summary>

View File

@@ -674,7 +674,7 @@ namespace MPF.Frontend.ViewModels
// Set the selected index
CurrentDrive = (index != -1 ? Drives[index] : Drives[0]);
Status = "Valid drive found! Choose your Media Type";
Status = "Valid drive found!";
CopyProtectScanButtonEnabled = true;
// Get the current system type
@@ -770,11 +770,11 @@ namespace MPF.Frontend.ViewModels
public void ChangeDumpingProgram()
{
VerboseLogLn($"Changed dumping program to: {((InternalProgram?)CurrentProgram).LongName()}");
EnsureDiscInformation();
EnsureMediaInformation();
// New output name depends on new environment
GetOutputNames(false);
// New environment depends on new output name
EnsureDiscInformation();
EnsureMediaInformation();
}
/// <summary>
@@ -787,7 +787,7 @@ namespace MPF.Frontend.ViewModels
SetSupportedDriveSpeed();
GetOutputNames(false);
EnsureDiscInformation();
EnsureMediaInformation();
}
/// <summary>
@@ -798,7 +798,7 @@ namespace MPF.Frontend.ViewModels
VerboseLogLn($"Changed system to: {CurrentSystem.LongName()}");
PopulateMediaType();
GetOutputNames(false);
EnsureDiscInformation();
EnsureMediaInformation();
}
/// <summary>
@@ -1063,7 +1063,7 @@ namespace MPF.Frontend.ViewModels
SetSupportedDriveSpeed();
_environment = DetermineEnvironment();
GetOutputNames(true);
EnsureDiscInformation();
EnsureMediaInformation();
// Enable event handlers
EnableEventHandlers();
@@ -1100,7 +1100,7 @@ namespace MPF.Frontend.ViewModels
// Set the initial environment and UI values
_environment = DetermineEnvironment();
GetOutputNames(true);
EnsureDiscInformation();
EnsureMediaInformation();
// Enable event handlers
EnableEventHandlers();
@@ -1213,14 +1213,8 @@ namespace MPF.Frontend.ViewModels
if (defaultMediaType == MediaType.NONE)
defaultMediaType = MediaType.CDROM;
// If we're skipping detection, set the default value
if (Options.SkipMediaTypeDetection)
{
VerboseLogLn($"Media type detection disabled, defaulting to {defaultMediaType.LongName()}.");
CurrentMediaType = defaultMediaType;
}
// If the drive is marked active, try to read from it
else if (CurrentDrive.MarkedActive)
if (CurrentDrive.MarkedActive)
{
VerboseLog($"Trying to detect media type for drive {CurrentDrive.Name} [{CurrentDrive.DriveFormat}] using size and filesystem.. ");
MediaType? detectedMediaType = CurrentDrive.GetMediaType(CurrentSystem);
@@ -1238,8 +1232,7 @@ namespace MPF.Frontend.ViewModels
CurrentMediaType = detectedMediaType;
}
}
// All other cases, just use the default
// Otherwise just use the default
else
{
VerboseLogLn($"Drive marked as empty, defaulting to {defaultMediaType.LongName()}.");
@@ -1253,14 +1246,15 @@ namespace MPF.Frontend.ViewModels
/// <returns>Filled DumpEnvironment Parent</returns>
private DumpEnvironment DetermineEnvironment()
{
return new DumpEnvironment(
var env = new DumpEnvironment(
Options,
EvaluateOutputPath(OutputPath),
CurrentDrive,
CurrentSystem,
CurrentMediaType,
CurrentProgram,
Parameters);
CurrentProgram);
env.SetExecutionContext(CurrentMediaType, Parameters);
env.SetProcessor();
return env;
}
/// <summary>
@@ -1361,15 +1355,19 @@ namespace MPF.Frontend.ViewModels
}
/// <summary>
/// Ensure information is consistent with the currently selected disc type
/// Ensure information is consistent with the currently selected media type
/// </summary>
public void EnsureDiscInformation()
public void EnsureMediaInformation()
{
// If the drive list is empty, ignore updates
if (Drives.Count == 0)
return;
// Get the current environment information
_environment = DetermineEnvironment();
// Get the status to write out
ResultEventArgs result = _environment.GetSupportStatus();
ResultEventArgs result = _environment.GetSupportStatus(CurrentMediaType);
if (CurrentProgram == InternalProgram.NONE)
Status = "No dumping program found";
else
@@ -1379,12 +1377,12 @@ namespace MPF.Frontend.ViewModels
StartStopButtonEnabled = result && ShouldEnableDumpingButton();
// If we're in a type that doesn't support drive speeds
DriveSpeedComboBoxEnabled = _environment.DoesSupportDriveSpeed();
DriveSpeedComboBoxEnabled = _environment.DoesSupportDriveSpeed(CurrentMediaType);
// If input params are enabled, generate the full parameters from the environment
if (ParametersCheckBoxEnabled)
{
var generated = _environment.GetFullParameters(DriveSpeed);
var generated = _environment.GetFullParameters(CurrentMediaType, DriveSpeed);
if (generated != null)
Parameters = generated;
}
@@ -1615,7 +1613,7 @@ namespace MPF.Frontend.ViewModels
try
{
if (Directory.Exists(Path.Combine(drive.Name, "$SystemUpdate"))
&& IOExtensions.SafeGetFiles(Path.Combine(drive.Name, "$SystemUpdate")).Length > 0
&& Path.Combine(drive.Name, "$SystemUpdate").SafeGetFiles().Length > 0
&& drive.TotalSize <= 500_000_000)
{
return RedumpSystem.MicrosoftXbox360;
@@ -1638,7 +1636,7 @@ namespace MPF.Frontend.ViewModels
if (!File.Exists(catalogjs))
return RedumpSystem.MicrosoftXboxOne;
SabreTools.Models.Xbox.Catalog? catalog = SabreTools.Serialization.Deserializers.Catalog.DeserializeFile(catalogjs);
SabreTools.Data.Models.Xbox.Catalog? catalog = new SabreTools.Serialization.Readers.Catalog().Deserialize(catalogjs);
if (catalog != null && catalog.Version != null && catalog.Packages != null)
{
if (!double.TryParse(catalog.Version, out double version))
@@ -1664,6 +1662,12 @@ namespace MPF.Frontend.ViewModels
}
catch { }
// Playmaji Polymega
if (File.Exists(Path.Combine(drive.Name, "Get Polymega App.url")))
{
return RedumpSystem.PlaymajiPolymega;
}
try
{
// Sega Saturn / Sega Dreamcast / Sega Mega-CD / Sega-CD
@@ -1824,13 +1828,13 @@ namespace MPF.Frontend.ViewModels
try
{
if (Directory.Exists(Path.Combine(drive.Name, "AUDIO_TS"))
&& IOExtensions.SafeGetFiles(Path.Combine(drive.Name, "AUDIO_TS")).Length > 0)
&& Path.Combine(drive.Name, "AUDIO_TS").SafeGetFiles().Length > 0)
{
return RedumpSystem.DVDAudio;
}
else if (Directory.Exists(Path.Combine(drive.Name, "VIDEO_TS"))
&& IOExtensions.SafeGetFiles(Path.Combine(drive.Name, "VIDEO_TS")).Length > 0)
&& Path.Combine(drive.Name, "VIDEO_TS").SafeGetFiles().Length > 0)
{
return RedumpSystem.DVDVideo;
}
@@ -1841,7 +1845,7 @@ namespace MPF.Frontend.ViewModels
try
{
if (Directory.Exists(Path.Combine(drive.Name, "HVDVD_TS"))
&& IOExtensions.SafeGetFiles(Path.Combine(drive.Name, "HVDVD_TS")).Length > 0)
&& Path.Combine(drive.Name, "HVDVD_TS").SafeGetFiles().Length > 0)
{
return RedumpSystem.HDDVDVideo;
}
@@ -1852,7 +1856,7 @@ namespace MPF.Frontend.ViewModels
try
{
if (Directory.Exists(Path.Combine(drive.Name, "PHOTO_CD"))
&& IOExtensions.SafeGetFiles(Path.Combine(drive.Name, "PHOTO_CD")).Length > 0)
&& Path.Combine(drive.Name, "PHOTO_CD").SafeGetFiles().Length > 0)
{
return RedumpSystem.PhotoCD;
}
@@ -1863,7 +1867,7 @@ namespace MPF.Frontend.ViewModels
try
{
if (Directory.Exists(Path.Combine(drive.Name, "VCD"))
&& IOExtensions.SafeGetFiles(Path.Combine(drive.Name, "VCD")).Length > 0)
&& Path.Combine(drive.Name, "VCD").SafeGetFiles().Length > 0)
{
return RedumpSystem.VideoCD;
}
@@ -1882,7 +1886,7 @@ namespace MPF.Frontend.ViewModels
public void ProcessCustomParameters()
{
// Set the execution context and processor
if (_environment?.SetExecutionContext(Parameters) != true)
if (_environment?.SetExecutionContext(CurrentMediaType, Parameters) != true)
return;
if (_environment?.SetProcessor() != true)
return;
@@ -2007,32 +2011,51 @@ namespace MPF.Frontend.ViewModels
/// </summary>
private static string? GetFormattedVolumeLabel(Drive? drive)
{
// If the drive is invalid
if (drive == null)
return null;
string? volumeLabel = DiscNotDetectedValue;
// If the drive is marked as inactive
if (!drive.MarkedActive)
return volumeLabel;
return DiscNotDetectedValue;
if (!string.IsNullOrEmpty(drive.VolumeLabel))
// Use internal serials where appropriate
string? volumeLabel = string.IsNullOrEmpty(drive.VolumeLabel) ? null : drive.VolumeLabel;
switch (GetRedumpSystem(drive))
{
volumeLabel = drive.VolumeLabel;
}
else
{
// No Volume Label found, fallback to something sensible
switch (GetRedumpSystem(drive))
{
case RedumpSystem.SonyPlayStation:
case RedumpSystem.SonyPlayStation2:
string? serial = PhysicalTool.GetPlayStationSerial(drive);
volumeLabel = serial ?? "track";
break;
case RedumpSystem.SonyPlayStation:
case RedumpSystem.SonyPlayStation2:
string? ps12Serial = PhysicalTool.GetPlayStationSerial(drive);
volumeLabel ??= ps12Serial ?? "track";
break;
default:
volumeLabel = "track";
break;
}
case RedumpSystem.SonyPlayStation3:
string? ps3Serial = PhysicalTool.GetPlayStation3Serial(drive);
if (volumeLabel == "PS3VOLUME")
volumeLabel = ps3Serial ?? volumeLabel;
else
volumeLabel ??= ps3Serial ?? "track";
break;
case RedumpSystem.SonyPlayStation4:
string? ps4Serial = PhysicalTool.GetPlayStation4Serial(drive);
if (volumeLabel == "PS4VOLUME")
volumeLabel = ps4Serial ?? volumeLabel;
else
volumeLabel ??= ps4Serial ?? "track";
break;
case RedumpSystem.SonyPlayStation5:
string? ps5Serial = PhysicalTool.GetPlayStation5Serial(drive);
if (volumeLabel == "PS5VOLUME")
volumeLabel = ps5Serial ?? volumeLabel;
else
volumeLabel ??= ps5Serial ?? "track";
break;
default:
volumeLabel ??= "track";
break;
}
foreach (char c in Path.GetInvalidFileNameChars())
@@ -2080,6 +2103,10 @@ namespace MPF.Frontend.ViewModels
/// </summary>
public void SetSupportedDriveSpeed()
{
// Skip trying to set speeds if no drives
if (Drives.Count == 0)
return;
// Set the drive speed list that's appropriate
DriveSpeeds = InterfaceConstants.GetSpeedsForMediaType(CurrentMediaType);
VerboseLogLn($"Supported media speeds: {string.Join(", ", [.. DriveSpeeds.ConvertAll(ds => ds.ToString())])}");
@@ -2093,8 +2120,7 @@ namespace MPF.Frontend.ViewModels
/// </summary>
private bool ShouldEnableDumpingButton()
{
return Drives != null
&& Drives.Count > 0
return Drives.Count > 0
&& CurrentSystem != null
&& CurrentMediaType != null
&& ProgramSupportsMedia();
@@ -2163,30 +2189,13 @@ namespace MPF.Frontend.ViewModels
{
// Ask user to confirm before exiting application during a dump
AskBeforeQuit = true;
// One last check to determine environment, just in case
_environment = DetermineEnvironment();
// Force an internal drive refresh in case the user entered things manually
_environment.RefreshDrive();
// If still in custom parameter mode, check that users meant to continue or not
if (ParametersCheckBoxEnabled == false && _displayUserMessage != null)
{
bool? result = _displayUserMessage("Custom Changes", "It looks like you have custom parameters that have not been saved. Would you like to dump with these custom parameters?", 2, true);
if (result == true)
{
ParametersCheckBoxEnabled = true;
ProcessCustomParameters();
}
else
{
// Re-allow quick exiting
AskBeforeQuit = false;
return;
}
}
try
{
// Run pre-dumping validation checks
@@ -2216,7 +2225,7 @@ namespace MPF.Frontend.ViewModels
_environment.ReportStatus += ProgressUpdated;
// Run the program with the parameters
ResultEventArgs result = await _environment.Run(resultProgress);
ResultEventArgs result = await _environment.Run(CurrentMediaType, resultProgress);
// If we didn't execute a dumping command we cannot get submission output
if (!_environment.IsDumpingCommand())
@@ -2236,9 +2245,12 @@ namespace MPF.Frontend.ViewModels
if (result)
{
result = await _environment.VerifyAndSaveDumpOutput(
resultProgress,
protectionProgress,
_processUserInfo);
resultProgress: resultProgress,
protectionProgress: protectionProgress,
processUserInfo: _processUserInfo);
if (!result)
ErrorLogLn(result.Message);
}
else
{
@@ -2283,6 +2295,7 @@ namespace MPF.Frontend.ViewModels
MediaScanButtonEnabled = false;
UpdateVolumeLabelEnabled = false;
CopyProtectScanButtonEnabled = false;
StartStopButtonEnabled = false;
}
else
{
@@ -2303,6 +2316,7 @@ namespace MPF.Frontend.ViewModels
MediaScanButtonEnabled = true;
UpdateVolumeLabelEnabled = true;
CopyProtectScanButtonEnabled = true;
StartStopButtonEnabled = true;
}
}
@@ -2344,7 +2358,7 @@ namespace MPF.Frontend.ViewModels
string outputFilename = Path.GetFileName(_environment.OutputPath);
// If a complete or partial dump already exists
bool foundAllFiles = _environment.FoundAllFiles(outputDirectory, outputFilename);
bool foundAllFiles = _environment.FoundAllFiles(CurrentMediaType, outputDirectory, outputFilename);
if (foundAllFiles && _displayUserMessage != null)
{
bool? mbresult = _displayUserMessage("Overwrite?", "A complete dump already exists! Are you sure you want to overwrite?", 2, true);
@@ -2357,7 +2371,7 @@ namespace MPF.Frontend.ViewModels
else
{
// If a partial dump exists
bool foundAnyFiles = _environment.FoundAnyFiles(outputDirectory, outputFilename);
bool foundAnyFiles = _environment.FoundAnyFiles(CurrentMediaType, outputDirectory, outputFilename);
if (foundAnyFiles && _displayUserMessage != null)
{
bool? mbresult = _displayUserMessage("Overwrite?", $"A partial dump already exists! Dumping here may cause issues. Are you sure you want to overwrite?", 2, true);
@@ -2370,7 +2384,7 @@ namespace MPF.Frontend.ViewModels
else
{
// If a complete dump exists from a different program
InternalProgram? completeProgramFound = _environment.CheckForMatchingProgram(outputDirectory, outputFilename);
InternalProgram? completeProgramFound = _environment.CheckForMatchingProgram(CurrentMediaType, outputDirectory, outputFilename);
if (completeProgramFound != null && _displayUserMessage != null)
{
bool? mbresult = _displayUserMessage("Overwrite?", $"A complete dump from {completeProgramFound} already exists! Dumping here may cause issues. Are you sure you want to overwrite?", 2, true);
@@ -2383,7 +2397,7 @@ namespace MPF.Frontend.ViewModels
else
{
// If a partial dump exists from a different program
InternalProgram? partialProgramFound = _environment.CheckForPartialProgram(outputDirectory, outputFilename);
InternalProgram? partialProgramFound = _environment.CheckForPartialProgram(CurrentMediaType, outputDirectory, outputFilename);
if (partialProgramFound != null && _displayUserMessage != null)
{
bool? mbresult = _displayUserMessage("Overwrite?", $"A partial dump from {partialProgramFound} already exists! Dumping here may cause issues. Are you sure you want to overwrite?", 2, true);

View File

@@ -6,7 +6,7 @@ using SabreTools.RedumpLib.Data;
namespace MPF.Frontend.ViewModels
{
public class DiscInformationViewModel
public class MediaInformationViewModel
{
#region Fields
@@ -194,7 +194,7 @@ namespace MPF.Frontend.ViewModels
/// <summary>
/// Constructor
/// </summary>
public DiscInformationViewModel(Options options, SubmissionInfo? submissionInfo)
public MediaInformationViewModel(Options options, SubmissionInfo? submissionInfo)
{
Options = options;
SubmissionInfo = submissionInfo?.Clone() as SubmissionInfo ?? new SubmissionInfo();

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.ComponentModel;
using MPF.Frontend.ComboBoxItems;
using LogCompression = MPF.Processors.LogCompression;
using RedumperDriveType = MPF.ExecutionContexts.Redumper.DriveType;
using RedumperReadMethod = MPF.ExecutionContexts.Redumper.ReadMethod;
using RedumperSectorOrder = MPF.ExecutionContexts.Redumper.SectorOrder;
@@ -50,6 +51,11 @@ namespace MPF.Frontend.ViewModels
/// </summary>
public static List<Element<InternalProgram>> InternalPrograms => PopulateInternalPrograms();
/// <summary>
/// List of available log compression methods
/// </summary>
public static List<Element<LogCompression>> LogCompressions => PopulateLogCompressions();
/// <summary>
/// Current list of supported Redumper read methods
/// </summary>
@@ -99,6 +105,16 @@ namespace MPF.Frontend.ViewModels
return internalPrograms.ConvertAll(ip => new Element<InternalProgram>(ip));
}
/// <summary>
/// Get a complete list of supported log compression methods
/// </summary>
/// <returns></returns>
private static List<Element<LogCompression>> PopulateLogCompressions()
{
var logCompressions = new List<LogCompression> { LogCompression.DeflateDefault, LogCompression.DeflateMaximum, LogCompression.Zstd19 };
return logCompressions.ConvertAll(lc => new Element<LogCompression>(lc));
}
/// <summary>
/// Get a complete list of supported redumper drive read methods
/// </summary>

View File

@@ -11,6 +11,41 @@ namespace MPF.Processors.Test
// TODO: Add tests around remaining helper methods
public class AaruTests
{
// TODO: Create minimal sidecars for all other supported types
#region DetermineMediaType
[Fact]
public void DetermineMediaType_Empty_Null()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new Aaru(RedumpSystem.IBMPCcompatible);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Null(actual);
}
[Fact]
public void DetermineMediaType_Invalid_Null()
{
string? outputDirectory = null;
string outputFilename = "INVALID";
var processor = new Aaru(RedumpSystem.IBMPCcompatible);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Null(actual);
}
[Fact]
public void DetermineMediaType_CD_Valid_CD()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Aaru", "CDROM");
string outputFilename = "test";
var processor = new Aaru(RedumpSystem.IBMPCcompatible);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.CDROM, actual);
}
#endregion
#region GetOutputFiles
[Fact]
@@ -18,9 +53,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, null);
var processor = new Aaru(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(null, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -29,9 +64,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var processor = new Aaru(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Equal(8, actual.Count);
}
@@ -40,9 +75,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.DVD);
var processor = new Aaru(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.DVD, outputDirectory, outputFilename);
Assert.Equal(7, actual.Count);
}
@@ -51,9 +86,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.HDDVD);
var processor = new Aaru(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.HDDVD, outputDirectory, outputFilename);
Assert.Equal(7, actual.Count);
}
@@ -62,9 +97,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.BluRay);
var processor = new Aaru(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.BluRay, outputDirectory, outputFilename);
Assert.Equal(7, actual.Count);
}
@@ -73,9 +108,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.ApertureCard);
var processor = new Aaru(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.ApertureCard, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -88,8 +123,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
var processor = new Aaru(RedumpSystem.IBMPCcompatible);
var actual = processor.FoundAllFiles(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Equal(7, actual.Count);
}
@@ -98,8 +133,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Aaru", "CDROM");
string outputFilename = "test.aaruf";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
var processor = new Aaru(RedumpSystem.IBMPCcompatible);
var actual = processor.FoundAllFiles(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -112,8 +147,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
var processor = new Aaru(RedumpSystem.IBMPCcompatible);
var actual = processor.FoundAnyFiles(MediaType.CDROM, outputDirectory, outputFilename);
Assert.False(actual);
}
@@ -122,8 +157,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Aaru", "CDROM");
string outputFilename = "test.aaruf";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
var processor = new Aaru(RedumpSystem.IBMPCcompatible);
var actual = processor.FoundAnyFiles(MediaType.CDROM, outputDirectory, outputFilename);
Assert.True(actual);
}
@@ -132,8 +167,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Aaru", "CDROM-zip");
string outputFilename = "test.aaruf";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
var processor = new Aaru(RedumpSystem.IBMPCcompatible);
var actual = processor.FoundAnyFiles(MediaType.CDROM, outputDirectory, outputFilename);
Assert.True(actual);
}
@@ -146,8 +181,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GenerateArtifacts(outputDirectory, outputFilename);
var processor = new Aaru(RedumpSystem.IBMPCcompatible);
var actual = processor.GenerateArtifacts(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -156,8 +191,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Aaru", "CDROM");
string outputFilename = "test.aaruf";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GenerateArtifacts(outputDirectory, outputFilename);
var processor = new Aaru(RedumpSystem.IBMPCcompatible);
var actual = processor.GenerateArtifacts(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Equal(7, actual.Count);
}
@@ -170,8 +205,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GetDeleteableFilePaths(outputDirectory, outputFilename);
var processor = new Aaru(RedumpSystem.IBMPCcompatible);
var actual = processor.GetDeleteableFilePaths(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -180,8 +215,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Aaru", "CDROM");
string outputFilename = "test.aaruf";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GetDeleteableFilePaths(outputDirectory, outputFilename);
var processor = new Aaru(RedumpSystem.IBMPCcompatible);
var actual = processor.GetDeleteableFilePaths(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -194,8 +229,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GetZippableFilePaths(outputDirectory, outputFilename);
var processor = new Aaru(RedumpSystem.IBMPCcompatible);
var actual = processor.GetZippableFilePaths(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -204,8 +239,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Aaru", "CDROM");
string outputFilename = "test.aaruf";
var processor = new Aaru(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GetZippableFilePaths(outputDirectory, outputFilename);
var processor = new Aaru(RedumpSystem.IBMPCcompatible);
var actual = processor.GetZippableFilePaths(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Equal(7, actual.Count);
}
@@ -385,5 +420,149 @@ namespace MPF.Processors.Test
}
#endregion
#region GetDiscTypeFromStrings
[Theory]
[InlineData(null, "ANY", null)]
[InlineData("", "ANY", null)]
[InlineData("INVALID", "ANY", null)]
[InlineData("3\" floppy", "ANY", MediaType.FloppyDisk)]
[InlineData("3.5\" floppy", "ANY", MediaType.FloppyDisk)]
[InlineData("3.5\" magneto-optical", "ANY", MediaType.Floptical)]
[InlineData("3.5\" SyQuest cartridge", "ANY", null)]
[InlineData("3.9\" SyQuest cartridge", "ANY", null)]
[InlineData("5.25\" floppy", "ANY", MediaType.FloppyDisk)]
[InlineData("5.25\" magneto-optical", "ANY", MediaType.Floptical)]
[InlineData("5.25\" SyQuest cartridge", "ANY", null)]
[InlineData("8\" floppy", "ANY", MediaType.FloppyDisk)]
[InlineData("300mm magneto optical", "ANY", MediaType.Floptical)]
[InlineData("356mm magneto-optical", "ANY", MediaType.Floptical)]
[InlineData("Advanced Digital Recording", "ANY", null)]
[InlineData("Advanced Intelligent Tape", "ANY", null)]
[InlineData("Archival Disc", "ANY", null)]
[InlineData("BeeCard", "ANY", null)]
[InlineData("Blu-ray", "Wii U Optical Disc", MediaType.NintendoWiiUOpticalDisc)]
[InlineData("Blu-ray", "ANY", MediaType.BluRay)]
[InlineData("Borsu", "ANY", null)]
[InlineData("Compact Cassette", "ANY", MediaType.Cassette)]
[InlineData("Compact Disc", "ANY", MediaType.CDROM)]
[InlineData("Compact Flash", "ANY", MediaType.CompactFlash)]
[InlineData("CompacTape", "ANY", null)]
[InlineData("CRVdisc", "ANY", null)]
[InlineData("Data8", "ANY", null)]
[InlineData("DataPlay", "ANY", null)]
[InlineData("DataStore", "ANY", null)]
[InlineData("DDCD", "ANY", MediaType.CDROM)]
[InlineData("DECtape", "ANY", null)]
[InlineData("DemiDiskette", "ANY", null)]
[InlineData("Digital Audio Tape", "ANY", null)]
[InlineData("Digital Data Storage", "ANY", MediaType.DataCartridge)]
[InlineData("Digital Linear Tape", "ANY", null)]
[InlineData("DIR", "ANY", null)]
[InlineData("DST", "ANY", null)]
[InlineData("DTF", "ANY", null)]
[InlineData("DTF2", "ANY", null)]
[InlineData("DV tape", "ANY", null)]
[InlineData("DVD", "GameCube Game Disc", MediaType.NintendoGameCubeGameDisc)]
[InlineData("DVD", "Wii Optical Disc", MediaType.NintendoWiiOpticalDisc)]
[InlineData("DVD", "ANY", MediaType.DVD)]
[InlineData("EVD", "ANY", null)]
[InlineData("Exatape", "ANY", null)]
[InlineData("Express Card", "ANY", null)]
[InlineData("FDDVD", "ANY", null)]
[InlineData("Flextra", "ANY", null)]
[InlineData("Floptical", "ANY", MediaType.Floptical)]
[InlineData("FVD", "ANY", null)]
[InlineData("GD", "ANY", MediaType.GDROM)]
[InlineData("Hard Disk Drive", "ANY", MediaType.HardDisk)]
[InlineData("HD DVD", "ANY", MediaType.HDDVD)]
[InlineData("HD VMD", "ANY", null)]
[InlineData("HiFD", "ANY", MediaType.FloppyDisk)]
[InlineData("HiTC", "ANY", null)]
[InlineData("HuCard", "ANY", MediaType.Cartridge)]
[InlineData("HVD", "ANY", null)]
[InlineData("HyperFlex", "ANY", null)]
[InlineData("IBM 3470", "ANY", null)]
[InlineData("IBM 3480", "ANY", null)]
[InlineData("IBM 3490", "ANY", null)]
[InlineData("IBM 3490E", "ANY", null)]
[InlineData("IBM 3592", "ANY", null)]
[InlineData("Iomega Bernoulli Box", "ANY", MediaType.IomegaBernoulliDisk)]
[InlineData("Iomega Bernoulli Box II", "ANY", MediaType.IomegaBernoulliDisk)]
[InlineData("Iomega Ditto", "ANY", null)]
[InlineData("Iomega Jaz", "ANY", MediaType.IomegaJaz)]
[InlineData("Iomega PocketZip", "ANY", MediaType.IomegaZip)]
[InlineData("Iomega REV", "ANY", null)]
[InlineData("Iomega ZIP", "ANY", MediaType.IomegaZip)]
[InlineData("Kodak Verbatim", "ANY", null)]
[InlineData("LaserDisc", "ANY", MediaType.LaserDisc)]
[InlineData("Linear Tape-Open", "ANY", null)]
[InlineData("LT1", "ANY", null)]
[InlineData("Magneto-optical", "ANY", MediaType.Floptical)]
[InlineData("Memory Stick", "ANY", MediaType.SDCard)]
[InlineData("MiniCard", "ANY", null)]
[InlineData("MiniDisc", "ANY", null)]
[InlineData("MultiMediaCard", "ANY", MediaType.SDCard)]
[InlineData("Nintendo 3DS Game Card", "ANY", MediaType.Cartridge)]
[InlineData("Nintendo 64 Disk", "ANY", MediaType.Nintendo64DD)]
[InlineData("Nintendo 64 Game Pak", "ANY", MediaType.Cartridge)]
[InlineData("Nintendo Disk Card", "ANY", MediaType.NintendoFamicomDiskSystem)]
[InlineData("Nintendo DS Game Card", "ANY", MediaType.Cartridge)]
[InlineData("Nintendo DSi Game Card", "ANY", MediaType.Cartridge)]
[InlineData("Nintendo Entertainment System Game Pak", "ANY", MediaType.Cartridge)]
[InlineData("Nintendo Famicom Game Pak", "ANY", MediaType.Cartridge)]
[InlineData("Nintendo Game Boy Advance Game Pak", "ANY", MediaType.Cartridge)]
[InlineData("Nintendo Game Boy Game Pak", "ANY", MediaType.Cartridge)]
[InlineData("Nintendo Switch Game Card", "ANY", MediaType.Cartridge)]
[InlineData("Optical Disc Archive", "ANY", null)]
[InlineData("Orb", "ANY", null)]
[InlineData("PCMCIA Card", "ANY", null)]
[InlineData("PD650", "ANY", null)]
[InlineData("PlayStation Memory Card", "ANY", null)]
[InlineData("Quarter-inch cartridge", "ANY", MediaType.DataCartridge)]
[InlineData("Quarter-inch mini cartridge", "ANY", MediaType.DataCartridge)]
[InlineData("QuickDisk", "ANY", null)]
[InlineData("RDX", "ANY", null)]
[InlineData("SACD", "ANY", MediaType.DVD)]
[InlineData("Scalable Linear Recording", "ANY", null)]
[InlineData("Secure Digital", "ANY", MediaType.SDCard)]
[InlineData("SmartMedia", "ANY", MediaType.SDCard)]
[InlineData("Sony Professional Disc", "ANY", null)]
[InlineData("Sony Professional Disc for DATA", "ANY", null)]
[InlineData("STK 4480", "ANY", null)]
[InlineData("STK 4490", "ANY", null)]
[InlineData("STK 9490", "ANY", null)]
[InlineData("STK T-9840", "ANY", null)]
[InlineData("STK T-9940", "ANY", null)]
[InlineData("STK T-10000", "ANY", null)]
[InlineData("Super Advanced Intelligent Tape", "ANY", null)]
[InlineData("Super Digital Linear Tape", "ANY", null)]
[InlineData("Super Nintendo Game Pak", "ANY", MediaType.Cartridge)]
[InlineData("Super Nintendo Game Pak (US)", "ANY", MediaType.Cartridge)]
[InlineData("SuperDisk", "ANY", MediaType.FloppyDisk)]
[InlineData("SVOD", "ANY", null)]
[InlineData("Travan", "ANY", null)]
[InlineData("UDO", "ANY", null)]
[InlineData("UHD144", "ANY", null)]
[InlineData("UMD", "ANY", MediaType.UMD)]
[InlineData("Unknown", "ANY", null)]
[InlineData("USB flash drive", "ANY", MediaType.FlashDrive)]
[InlineData("VCDHD", "ANY", null)]
[InlineData("VideoFloppy", "ANY", null)]
[InlineData("VideoNow", "ANY", MediaType.CDROM)]
[InlineData("VXA", "ANY", MediaType.FlashDrive)]
[InlineData("Wafer", "ANY", null)]
[InlineData("xD", "ANY", null)]
[InlineData("XQD", "ANY", null)]
[InlineData("Zoned Hard Disk Drive", "ANY", MediaType.HardDisk)]
[InlineData("ZX Microdrive", "ANY", null)]
public void GetDiscTypeFromStringsTest(string? discType, string? discSubType, MediaType? expected)
{
var actual = Aaru.GetDiscTypeFromStrings(discType, discSubType);
Assert.Equal(expected, actual);
}
#endregion
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.IO;
using SabreTools.Data.Models.Logiqx;
using Xunit;
namespace MPF.Processors.Test
@@ -85,6 +86,43 @@ namespace MPF.Processors.Test
#endregion
#region GenerateDatafile
[Fact]
public void GenerateDatafile_Empty_Null()
{
string iso = string.Empty;
Datafile? actual = BaseProcessor.GenerateDatafile(iso);
Assert.Null(actual);
}
[Fact]
public void GenerateDatafile_Invalid_Null()
{
string iso = "INVALID";
Datafile? actual = BaseProcessor.GenerateDatafile(iso);
Assert.Null(actual);
}
[Fact]
public void GenerateDatafile_Valid_Filled()
{
string iso = Path.Combine(Environment.CurrentDirectory, "TestData", "PS3CFW", "BluRay", "test.iso");
var actual = BaseProcessor.GenerateDatafile(iso);
Assert.NotNull(actual);
Assert.NotNull(actual.Game);
var game = Assert.Single(actual.Game);
Assert.NotNull(game.Rom);
var rom = Assert.Single(game.Rom);
Assert.Equal("9", rom.Size);
Assert.Equal("560b9f59", rom.CRC);
Assert.Equal("edbb6676247e65c2245dd4883ed9fc24", rom.MD5);
Assert.Equal("1b33ad54d78085be5ecb1cf1b3e9da821e708075", rom.SHA1);
}
#endregion
#region GetPIC
[Fact]

View File

@@ -7,17 +7,111 @@ namespace MPF.Processors.Test
{
public class CleanRipTests
{
#region DetermineMediaType
[Fact]
public void DetermineMediaType_GC_Empty_GC()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new CleanRip(RedumpSystem.NintendoGameCube);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.NintendoGameCubeGameDisc, actual);
}
[Fact]
public void DetermineMediaType_Wii_Null_Wii()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new CleanRip(RedumpSystem.NintendoWii);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.NintendoWiiOpticalDisc, actual);
}
[Fact]
public void DetermineMediaType_Other_Null_Null()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new CleanRip(RedumpSystem.IBMPCcompatible);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Null(actual);
}
[Fact]
public void DetermineMediaType_GC_Invalid_GC()
{
string? outputDirectory = null;
string outputFilename = "INVALID";
var processor = new CleanRip(RedumpSystem.NintendoGameCube);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.NintendoGameCubeGameDisc, actual);
}
[Fact]
public void DetermineMediaType_Wii_Invalid_Wii()
{
string? outputDirectory = null;
string outputFilename = "INVALID";
var processor = new CleanRip(RedumpSystem.NintendoWii);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.NintendoWiiOpticalDisc, actual);
}
[Fact]
public void DetermineMediaType_Other_Invalid_Invalid()
{
string? outputDirectory = null;
string outputFilename = "INVALID";
var processor = new CleanRip(RedumpSystem.IBMPCcompatible);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Null(actual);
}
[Fact]
public void DetermineMediaType_GC_Valid_GC()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "CleanRip", "DVD");
string outputFilename = "test";
var processor = new CleanRip(RedumpSystem.NintendoGameCube);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.NintendoGameCubeGameDisc, actual);
}
[Fact]
public void DetermineMediaType_Wii_Valid_Wii()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "CleanRip", "DVD");
string outputFilename = "test";
var processor = new CleanRip(RedumpSystem.NintendoWii);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.NintendoWiiOpticalDisc, actual);
}
[Fact]
public void DetermineMediaType_Other_Valid_Valid()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "CleanRip", "DVD");
string outputFilename = "test";
var processor = new CleanRip(RedumpSystem.IBMPCcompatible);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Null(actual);
}
#endregion
#region GetOutputFiles
[Fact]
public void GetOutputFiles_Null_Empty()
public void GetOutputFiles_Null_Populated()
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new CleanRip(RedumpSystem.NintendoGameCube, null);
var processor = new CleanRip(RedumpSystem.NintendoGameCube);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Empty(actual);
var actual = processor.GetOutputFiles(null, outputDirectory, outputFilename);
Assert.Equal(3, actual.Count);
}
[Fact]
@@ -25,9 +119,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var processor = new CleanRip(RedumpSystem.NintendoGameCube);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.DVD, outputDirectory, outputFilename);
Assert.Equal(3, actual.Count);
}
@@ -36,9 +130,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc);
var processor = new CleanRip(RedumpSystem.NintendoGameCube);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.NintendoGameCubeGameDisc, outputDirectory, outputFilename);
Assert.Equal(3, actual.Count);
}
@@ -47,21 +141,21 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.NintendoWiiOpticalDisc);
var processor = new CleanRip(RedumpSystem.NintendoWii);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.NintendoWiiOpticalDisc, outputDirectory, outputFilename);
Assert.Equal(3, actual.Count);
}
[Fact]
public void GetOutputFiles_Other_Empty()
public void GetOutputFiles_Other_Populated()
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.ApertureCard);
var processor = new CleanRip(RedumpSystem.NintendoGameCube);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Empty(actual);
var actual = processor.GetOutputFiles(MediaType.ApertureCard, outputDirectory, outputFilename);
Assert.Equal(3, actual.Count);
}
#endregion
@@ -73,8 +167,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
var processor = new CleanRip(RedumpSystem.NintendoGameCube);
var actual = processor.FoundAllFiles(MediaType.DVD, outputDirectory, outputFilename);
Assert.Equal(3, actual.Count);
}
@@ -83,8 +177,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "CleanRip", "DVD");
string outputFilename = "test.iso";
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
var processor = new CleanRip(RedumpSystem.NintendoGameCube);
var actual = processor.FoundAllFiles(MediaType.DVD, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -97,8 +191,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
var processor = new CleanRip(RedumpSystem.NintendoGameCube);
var actual = processor.FoundAnyFiles(MediaType.DVD, outputDirectory, outputFilename);
Assert.False(actual);
}
@@ -107,8 +201,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "CleanRip", "DVD");
string outputFilename = "test.iso";
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
var processor = new CleanRip(RedumpSystem.NintendoGameCube);
var actual = processor.FoundAnyFiles(MediaType.DVD, outputDirectory, outputFilename);
Assert.True(actual);
}
@@ -117,8 +211,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "CleanRip", "DVD-zip");
string outputFilename = "test.iso";
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
var processor = new CleanRip(RedumpSystem.NintendoGameCube);
var actual = processor.FoundAnyFiles(MediaType.DVD, outputDirectory, outputFilename);
Assert.True(actual);
}
@@ -131,8 +225,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var actual = processor.GenerateArtifacts(outputDirectory, outputFilename);
var processor = new CleanRip(RedumpSystem.NintendoGameCube);
var actual = processor.GenerateArtifacts(MediaType.DVD, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -141,8 +235,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "CleanRip", "DVD");
string outputFilename = "test.iso";
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var actual = processor.GenerateArtifacts(outputDirectory, outputFilename);
var processor = new CleanRip(RedumpSystem.NintendoGameCube);
var actual = processor.GenerateArtifacts(MediaType.DVD, outputDirectory, outputFilename);
Assert.Equal(2, actual.Count);
}
@@ -155,8 +249,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var actual = processor.GetDeleteableFilePaths(outputDirectory, outputFilename);
var processor = new CleanRip(RedumpSystem.NintendoGameCube);
var actual = processor.GetDeleteableFilePaths(MediaType.DVD, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -165,8 +259,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "CleanRip", "DVD");
string outputFilename = "test.iso";
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var actual = processor.GetDeleteableFilePaths(outputDirectory, outputFilename);
var processor = new CleanRip(RedumpSystem.NintendoGameCube);
var actual = processor.GetDeleteableFilePaths(MediaType.DVD, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -179,8 +273,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var actual = processor.GetZippableFilePaths(outputDirectory, outputFilename);
var processor = new CleanRip(RedumpSystem.NintendoGameCube);
var actual = processor.GetZippableFilePaths(MediaType.DVD, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -189,8 +283,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "CleanRip", "DVD");
string outputFilename = "test.iso";
var processor = new CleanRip(RedumpSystem.NintendoGameCube, MediaType.DVD);
var actual = processor.GetZippableFilePaths(outputDirectory, outputFilename);
var processor = new CleanRip(RedumpSystem.NintendoGameCube);
var actual = processor.GetZippableFilePaths(MediaType.DVD, outputDirectory, outputFilename);
Assert.Equal(2, actual.Count);
}

View File

@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using SabreTools.Models.Logiqx;
using SabreTools.Data.Models.Logiqx;
using SabreTools.RedumpLib.Data;
using Xunit;
@@ -10,6 +10,70 @@ namespace MPF.Processors.Test
// TODO: Add tests around remaining helper methods
public class DiscImageCreatorTests
{
#region DetermineMediaType
[Fact]
public void DetermineMediaType_Null_Null()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Null(actual);
}
[Fact]
public void DetermineMediaType_Invalid_Null()
{
string? outputDirectory = null;
string outputFilename = "INVALID";
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Null(actual);
}
[Fact]
public void DetermineMediaType_BD_Filled()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "DiscImageCreator", "BluRay");
string outputFilename = "test";
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.BluRay, actual);
}
[Fact]
public void DetermineMediaType_CD_Filled()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "DiscImageCreator", "CDROM");
string outputFilename = "test";
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.CDROM, actual);
}
[Fact]
public void DetermineMediaType_DVD_Filled()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "DiscImageCreator", "DVD");
string outputFilename = "test";
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.DVD, actual);
}
[Fact]
public void DetermineMediaType_HDDVD_Filled()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "DiscImageCreator", "HDDVD");
string outputFilename = "test";
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.HDDVD, actual);
}
#endregion
#region GetOutputFiles
[Fact]
@@ -17,9 +81,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible, null);
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(null, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -28,9 +92,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Equal(26, actual.Count);
}
@@ -39,9 +103,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible, MediaType.GDROM);
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.GDROM, outputDirectory, outputFilename);
Assert.Equal(10, actual.Count);
}
@@ -50,9 +114,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible, MediaType.DVD);
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.DVD, outputDirectory, outputFilename);
Assert.Equal(16, actual.Count);
}
@@ -61,9 +125,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible, MediaType.NintendoGameCubeGameDisc);
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.NintendoGameCubeGameDisc, outputDirectory, outputFilename);
Assert.Equal(16, actual.Count);
}
@@ -72,9 +136,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible, MediaType.NintendoWiiOpticalDisc);
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.NintendoWiiOpticalDisc, outputDirectory, outputFilename);
Assert.Equal(16, actual.Count);
}
@@ -83,9 +147,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible, MediaType.HDDVD);
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.HDDVD, outputDirectory, outputFilename);
Assert.Equal(15, actual.Count);
}
@@ -94,9 +158,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible, MediaType.BluRay);
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.BluRay, outputDirectory, outputFilename);
Assert.Equal(15, actual.Count);
}
@@ -105,9 +169,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible, MediaType.FloppyDisk);
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.FloppyDisk, outputDirectory, outputFilename);
Assert.Equal(4, actual.Count);
}
@@ -116,9 +180,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible, MediaType.HardDisk);
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.HardDisk, outputDirectory, outputFilename);
Assert.Equal(4, actual.Count);
}
@@ -127,9 +191,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible, MediaType.ApertureCard);
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.ApertureCard, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -142,9 +206,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
Assert.Equal(17, actual.Count);
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.FoundAllFiles(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Equal(15, actual.Count);
}
[Fact]
@@ -152,8 +216,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "DiscImageCreator", "CDROM");
string outputFilename = "test.cue";
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.FoundAllFiles(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -166,8 +230,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.FoundAnyFiles(MediaType.CDROM, outputDirectory, outputFilename);
Assert.False(actual);
}
@@ -176,8 +240,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "DiscImageCreator", "CDROM");
string outputFilename = "test.cue";
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.FoundAnyFiles(MediaType.CDROM, outputDirectory, outputFilename);
Assert.True(actual);
}
@@ -186,8 +250,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "DiscImageCreator", "CDROM-zip");
string outputFilename = "test.cue";
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.FoundAnyFiles(MediaType.CDROM, outputDirectory, outputFilename);
Assert.True(actual);
}
@@ -200,8 +264,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GenerateArtifacts(outputDirectory, outputFilename);
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.GenerateArtifacts(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -210,8 +274,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "DiscImageCreator", "CDROM");
string outputFilename = "test.cue";
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GenerateArtifacts(outputDirectory, outputFilename);
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.GenerateArtifacts(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Equal(21, actual.Count);
}
@@ -224,8 +288,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GetDeleteableFilePaths(outputDirectory, outputFilename);
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.GetDeleteableFilePaths(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -234,8 +298,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "DiscImageCreator", "CDROM");
string outputFilename = "test.cue";
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GetDeleteableFilePaths(outputDirectory, outputFilename);
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.GetDeleteableFilePaths(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Equal(2, actual.Count);
}
@@ -248,8 +312,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GetZippableFilePaths(outputDirectory, outputFilename);
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.GetZippableFilePaths(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -258,8 +322,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "DiscImageCreator", "CDROM");
string outputFilename = "test.cue";
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GetZippableFilePaths(outputDirectory, outputFilename);
var processor = new DiscImageCreator(RedumpSystem.IBMPCcompatible);
var actual = processor.GetZippableFilePaths(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Equal(23, actual.Count);
}
@@ -351,15 +415,45 @@ namespace MPF.Processors.Test
}
[Fact]
public void GetDiscType_Valid_Filled()
public void GetDiscType_BD_Filled()
{
string? expected = "CD-ROM, GD-ROM, DVD-ROM, BD-ROM";
string? expected = "BDO";
string disc = Path.Combine(Environment.CurrentDirectory, "TestData", "DiscImageCreator", "BluRay", "test_disc.txt");
bool actual = DiscImageCreator.GetDiscType(disc, out string? discTypeOrBookType);
Assert.True(actual);
Assert.Equal(expected, discTypeOrBookType);
}
[Fact]
public void GetDiscType_CD_Filled()
{
string? expected = "CD-ROM";
string disc = Path.Combine(Environment.CurrentDirectory, "TestData", "DiscImageCreator", "CDROM", "test_disc.txt");
bool actual = DiscImageCreator.GetDiscType(disc, out string? discTypeOrBookType);
Assert.True(actual);
Assert.Equal(expected, discTypeOrBookType);
}
[Fact]
public void GetDiscType_DVD_Filled()
{
string? expected = "DVD-ROM";
string disc = Path.Combine(Environment.CurrentDirectory, "TestData", "DiscImageCreator", "DVD", "test_disc.txt");
bool actual = DiscImageCreator.GetDiscType(disc, out string? discTypeOrBookType);
Assert.True(actual);
Assert.Equal(expected, discTypeOrBookType);
}
[Fact]
public void GetDiscType_HDDVD_Filled()
{
string? expected = "HD DVD-ROM";
string disc = Path.Combine(Environment.CurrentDirectory, "TestData", "DiscImageCreator", "HDDVD", "test_disc.txt");
bool actual = DiscImageCreator.GetDiscType(disc, out string? discTypeOrBookType);
Assert.True(actual);
Assert.Equal(expected, discTypeOrBookType);
}
#endregion
#region GetDVDProtection

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0;net8.0;net9.0</TargetFrameworks>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
@@ -24,13 +24,13 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeCoverage" Version="17.13.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.6.7" />
<PackageReference Include="Microsoft.CodeCoverage" Version="17.14.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
<PackageReference Include="SabreTools.RedumpLib" Version="[1.7.4]" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.abstractions" Version="2.0.3" />
<PackageReference Include="xunit.analyzers" Version="1.21.0" />
<PackageReference Include="xunit.analyzers" Version="1.24.0" />
<PackageReference Include="xunit.assert" Version="2.9.3" />
<PackageReference Include="xunit.core" Version="2.9.3" />
<PackageReference Include="xunit.extensibility.core" Version="2.9.3" />
@@ -39,7 +39,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.2">
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using SabreTools.Models.Logiqx;
using SabreTools.RedumpLib.Data;
using Xunit;
@@ -8,17 +7,51 @@ namespace MPF.Processors.Test
{
public class PS3CFWTests
{
#region DetermineMediaType
[Fact]
public void DetermineMediaType_Null_BluRay()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.BluRay, actual);
}
[Fact]
public void DetermineMediaType_Invalid_BluRay()
{
string? outputDirectory = null;
string outputFilename = "INVALID";
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.BluRay, actual);
}
[Fact]
public void DetermineMediaType_Valid_BluRay()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "PS3CFW", "BluRay");
string outputFilename = "test";
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.BluRay, actual);
}
#endregion
#region GetOutputFiles
[Fact]
public void GetOutputFiles_Null_Empty()
public void GetOutputFiles_Null_Populated()
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, null);
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Empty(actual);
var actual = processor.GetOutputFiles(null, outputDirectory, outputFilename);
Assert.Equal(4, actual.Count);
}
[Fact]
@@ -26,21 +59,21 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.BluRay, outputDirectory, outputFilename);
Assert.Equal(4, actual.Count);
}
[Fact]
public void GetOutputFiles_Other_Empty()
public void GetOutputFiles_Other_Populated()
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.ApertureCard);
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Empty(actual);
var actual = processor.GetOutputFiles(MediaType.ApertureCard, outputDirectory, outputFilename);
Assert.Equal(4, actual.Count);
}
#endregion
@@ -52,8 +85,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3);
var actual = processor.FoundAllFiles(MediaType.BluRay, outputDirectory, outputFilename);
Assert.Equal(3, actual.Count);
}
@@ -62,8 +95,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "PS3CFW", "BluRay");
string outputFilename = "test.iso";
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3);
var actual = processor.FoundAllFiles(MediaType.BluRay, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -76,8 +109,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3);
var actual = processor.FoundAnyFiles(MediaType.BluRay, outputDirectory, outputFilename);
Assert.False(actual);
}
@@ -86,8 +119,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "PS3CFW", "BluRay");
string outputFilename = "test.iso";
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3);
var actual = processor.FoundAnyFiles(MediaType.BluRay, outputDirectory, outputFilename);
Assert.True(actual);
}
@@ -96,8 +129,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "PS3CFW", "BluRay-zip");
string outputFilename = "test.iso";
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3);
var actual = processor.FoundAnyFiles(MediaType.BluRay, outputDirectory, outputFilename);
Assert.True(actual);
}
@@ -110,8 +143,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var actual = processor.GenerateArtifacts(outputDirectory, outputFilename);
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3);
var actual = processor.GenerateArtifacts(MediaType.BluRay, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -120,8 +153,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "PS3CFW", "BluRay");
string outputFilename = "test.iso";
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var actual = processor.GenerateArtifacts(outputDirectory, outputFilename);
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3);
var actual = processor.GenerateArtifacts(MediaType.BluRay, outputDirectory, outputFilename);
Assert.Equal(2, actual.Count);
}
@@ -134,8 +167,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var actual = processor.GetDeleteableFilePaths(outputDirectory, outputFilename);
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3);
var actual = processor.GetDeleteableFilePaths(MediaType.BluRay, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -144,8 +177,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "PS3CFW", "BluRay");
string outputFilename = "test.iso";
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var actual = processor.GetDeleteableFilePaths(outputDirectory, outputFilename);
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3);
var actual = processor.GetDeleteableFilePaths(MediaType.BluRay, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -158,8 +191,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var actual = processor.GetZippableFilePaths(outputDirectory, outputFilename);
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3);
var actual = processor.GetZippableFilePaths(MediaType.BluRay, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -168,48 +201,11 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "PS3CFW", "BluRay");
string outputFilename = "test.iso";
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3, MediaType.BluRay);
var actual = processor.GetZippableFilePaths(outputDirectory, outputFilename);
var processor = new PS3CFW(RedumpSystem.SonyPlayStation3);
var actual = processor.GetZippableFilePaths(MediaType.BluRay, outputDirectory, outputFilename);
Assert.Equal(2, actual.Count);
}
#endregion
#region GeneratePS3CFWDatafile
[Fact]
public void GeneratePS3CFWDatafile_Empty_Null()
{
string iso = string.Empty;
Datafile? actual = PS3CFW.GeneratePS3CFWDatafile(iso);
Assert.Null(actual);
}
[Fact]
public void GeneratePS3CFWDatafile_Invalid_Null()
{
string iso = "INVALID";
Datafile? actual = PS3CFW.GeneratePS3CFWDatafile(iso);
Assert.Null(actual);
}
[Fact]
public void GeneratePS3CFWDatafile_Valid_Filled()
{
string iso = Path.Combine(Environment.CurrentDirectory, "TestData", "PS3CFW", "BluRay", "test.iso");
var actual = PS3CFW.GeneratePS3CFWDatafile(iso);
Assert.NotNull(actual);
Assert.NotNull(actual.Game);
var game = Assert.Single(actual.Game);
Assert.NotNull(game.Rom);
var rom = Assert.Single(game.Rom);
Assert.Equal("9", rom.Size);
Assert.Equal("560b9f59", rom.CRC);
Assert.Equal("edbb6676247e65c2245dd4883ed9fc24", rom.MD5);
Assert.Equal("1b33ad54d78085be5ecb1cf1b3e9da821e708075", rom.SHA1);
}
#endregion
}
}

View File

@@ -1,7 +1,7 @@
using System;
using System.IO;
using SabreTools.Models.Logiqx;
using SabreTools.Models.PIC;
using SabreTools.Data.Models.Logiqx;
using SabreTools.Data.Models.PIC;
using SabreTools.RedumpLib.Data;
using Xunit;
@@ -471,12 +471,9 @@ namespace MPF.Processors.Test
[Theory]
[InlineData(null, null)]
[InlineData("", null)]
[InlineData("GAME", DiscCategory.Games)]
[InlineData("game", DiscCategory.Games)]
[InlineData("VIDEO", DiscCategory.Video)]
[InlineData("video", DiscCategory.Video)]
[InlineData("AUDIO", DiscCategory.Audio)]
[InlineData("audio", DiscCategory.Audio)]
[InlineData("(GAME)", DiscCategory.Games)]
[InlineData("(VIDEO)", DiscCategory.Video)]
[InlineData("(AUDIO)", DiscCategory.Audio)]
[InlineData("INVALID", null)]
public void GetUMDCategoryTest(string? category, DiscCategory? expected)
{

View File

@@ -8,6 +8,80 @@ namespace MPF.Processors.Test
{
public class RedumperTests
{
#region DetermineMediaType
[Fact]
public void DetermineMediaType_Null_Null()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Null(actual);
}
[Fact]
public void DetermineMediaType_Invalid_Null()
{
string? outputDirectory = null;
string outputFilename = "INVALID";
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Null(actual);
}
[Fact]
public void DetermineMediaType_BD_Filled()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Redumper", "BluRay");
string outputFilename = "test";
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.BluRay, actual);
}
[Fact]
public void DetermineMediaType_BDR_Filled()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Redumper", "BDR");
string outputFilename = "test";
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.BluRay, actual);
}
[Fact]
public void DetermineMediaType_CD_Filled()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Redumper", "CDROM");
string outputFilename = "test";
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.CDROM, actual);
}
[Fact]
public void DetermineMediaType_DVD_Filled()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Redumper", "DVD");
string outputFilename = "test";
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.DVD, actual);
}
[Fact]
public void DetermineMediaType_HDDVD_Filled()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Redumper", "HDDVD");
string outputFilename = "test";
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.HDDVD, actual);
}
#endregion
#region GetOutputFiles
[Fact]
@@ -15,9 +89,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new Redumper(RedumpSystem.IBMPCcompatible, null);
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(null, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -26,10 +100,10 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new Redumper(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Equal(16, actual.Count);
var actual = processor.GetOutputFiles(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Equal(19, actual.Count);
}
[Fact]
@@ -37,9 +111,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new Redumper(RedumpSystem.IBMPCcompatible, MediaType.DVD);
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.DVD, outputDirectory, outputFilename);
Assert.Equal(17, actual.Count);
}
@@ -48,10 +122,10 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new Redumper(RedumpSystem.IBMPCcompatible, MediaType.HDDVD);
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Equal(10, actual.Count);
var actual = processor.GetOutputFiles(MediaType.HDDVD, outputDirectory, outputFilename);
Assert.Equal(12, actual.Count);
}
[Fact]
@@ -59,10 +133,10 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new Redumper(RedumpSystem.IBMPCcompatible, MediaType.BluRay);
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Equal(10, actual.Count);
var actual = processor.GetOutputFiles(MediaType.BluRay, outputDirectory, outputFilename);
Assert.Equal(12, actual.Count);
}
[Fact]
@@ -70,9 +144,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new Redumper(RedumpSystem.IBMPCcompatible, MediaType.ApertureCard);
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.ApertureCard, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -85,9 +159,9 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new Redumper(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
Assert.Equal(8, actual.Count);
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.FoundAllFiles(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Equal(7, actual.Count);
}
[Fact]
@@ -95,8 +169,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Redumper", "CDROM");
string outputFilename = "test.cue";
var processor = new Redumper(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.FoundAllFiles(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -105,8 +179,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Redumper", "CDROM-zip");
string outputFilename = "test.cue";
var processor = new Redumper(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.FoundAllFiles(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -119,8 +193,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new Redumper(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.FoundAnyFiles(MediaType.CDROM, outputDirectory, outputFilename);
Assert.False(actual);
}
@@ -129,8 +203,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Redumper", "CDROM");
string outputFilename = "test.cue";
var processor = new Redumper(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.FoundAnyFiles(MediaType.CDROM, outputDirectory, outputFilename);
Assert.True(actual);
}
@@ -143,8 +217,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new Redumper(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GenerateArtifacts(outputDirectory, outputFilename);
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.GenerateArtifacts(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -153,8 +227,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Redumper", "CDROM");
string outputFilename = "test.cue";
var processor = new Redumper(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GenerateArtifacts(outputDirectory, outputFilename);
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.GenerateArtifacts(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Equal(10, actual.Count);
}
@@ -167,8 +241,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new Redumper(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GetDeleteableFilePaths(outputDirectory, outputFilename);
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.GetDeleteableFilePaths(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -177,8 +251,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Redumper", "CDROM");
string outputFilename = "test.cue";
var processor = new Redumper(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GetDeleteableFilePaths(outputDirectory, outputFilename);
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.GetDeleteableFilePaths(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Single(actual);
}
@@ -191,8 +265,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new Redumper(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GetZippableFilePaths(outputDirectory, outputFilename);
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.GetZippableFilePaths(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -201,8 +275,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "Redumper", "CDROM");
string outputFilename = "test.cue";
var processor = new Redumper(RedumpSystem.IBMPCcompatible, MediaType.CDROM);
var actual = processor.GetZippableFilePaths(outputDirectory, outputFilename);
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.GetZippableFilePaths(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Equal(10, actual.Count);
}
@@ -266,32 +340,154 @@ namespace MPF.Processors.Test
#endregion
#region GetDiscProfile
[Fact]
public void GetDiscProfile_Empty_Null()
{
string log = string.Empty;
bool actual = Redumper.GetDiscProfile(log, out string? discProfile);
Assert.False(actual);
Assert.Null(discProfile);
}
[Fact]
public void GetDiscProfile_Invalid_Null()
{
string log = "INVALID";
bool actual = Redumper.GetDiscProfile(log, out string? discProfile);
Assert.False(actual);
Assert.Null(discProfile);
}
[Fact]
public void GetDiscProfile_Valid_Filled()
{
string? expected = "CD-ROM";
string log = Path.Combine(Environment.CurrentDirectory, "TestData", "Redumper", "CDROM", "test.log");
bool actual = Redumper.GetDiscProfile(log, out string? discProfile);
Assert.True(actual);
Assert.Equal(expected, discProfile);
}
#endregion
#region GetDiscType
[Fact]
public void GetDiscType_Empty_Null()
{
string log = string.Empty;
bool actual = Redumper.GetDiscType(log, out string? discTypeOrBookType);
bool actual = Redumper.GetDiscType(log, out MediaType? discType);
Assert.False(actual);
Assert.Null(discType);
}
[Fact]
public void GetDiscType_Invalid_Null()
{
string log = "INVALID";
bool actual = Redumper.GetDiscType(log, out string? discTypeOrBookType);
bool actual = Redumper.GetDiscType(log, out MediaType? discType);
Assert.False(actual);
Assert.Null(discType);
}
[Fact]
public void GetDiscType_Valid_Filled()
public void GetDiscType_BD_Filled()
{
string? expected = "CD-ROM";
string log = Path.Combine(Environment.CurrentDirectory, "TestData", "Redumper", "CDROM", "test.log");
bool actual = Redumper.GetDiscType(log, out string? discTypeOrBookType);
MediaType? expected = MediaType.BluRay;
string log = Path.Combine(Environment.CurrentDirectory, "TestData", "Redumper", "BluRay", "test.log");
bool actual = Redumper.GetDiscType(log, out MediaType? discType);
Assert.True(actual);
Assert.Equal(expected, discTypeOrBookType);
Assert.Equal(expected, discType);
}
[Fact]
public void GetDiscType_BDR_Filled()
{
MediaType? expected = MediaType.BluRay;
string log = Path.Combine(Environment.CurrentDirectory, "TestData", "Redumper", "BDR", "test.log");
bool actual = Redumper.GetDiscType(log, out MediaType? discType);
Assert.True(actual);
Assert.Equal(expected, discType);
}
[Fact]
public void GetDiscType_CD_Filled()
{
MediaType? expected = MediaType.CDROM;
string log = Path.Combine(Environment.CurrentDirectory, "TestData", "Redumper", "CDROM", "test.log");
bool actual = Redumper.GetDiscType(log, out MediaType? discType);
Assert.True(actual);
Assert.Equal(expected, discType);
}
[Fact]
public void GetDiscType_DVD_Filled()
{
MediaType? expected = MediaType.DVD;
string log = Path.Combine(Environment.CurrentDirectory, "TestData", "Redumper", "DVD", "test.log");
bool actual = Redumper.GetDiscType(log, out MediaType? discType);
Assert.True(actual);
Assert.Equal(expected, discType);
}
[Fact]
public void GetDiscType_HDDVD_Filled()
{
MediaType? expected = MediaType.HDDVD;
string log = Path.Combine(Environment.CurrentDirectory, "TestData", "Redumper", "HDDVD", "test.log");
bool actual = Redumper.GetDiscType(log, out MediaType? discType);
Assert.True(actual);
Assert.Equal(expected, discType);
}
#endregion
#region GetDiscTypeFromProfile
[Theory]
[InlineData(null, null)]
[InlineData("", null)]
[InlineData("INVALID", null)]
[InlineData("reserved", null)]
[InlineData("non removable disk", null)]
[InlineData("removable disk", null)]
[InlineData("MO erasable", null)]
[InlineData("MO write once", null)]
[InlineData("AS MO", null)]
[InlineData("CD-ROM", MediaType.CDROM)]
[InlineData("CD-R", MediaType.CDROM)]
[InlineData("CD-RW", MediaType.CDROM)]
[InlineData("DVD-ROM", MediaType.DVD)]
[InlineData("DVD-R", MediaType.DVD)]
[InlineData("DVD-RAM", MediaType.DVD)]
[InlineData("DVD-RW RO", MediaType.DVD)]
[InlineData("DVD-RW", MediaType.DVD)]
[InlineData("DVD-R DL", MediaType.DVD)]
[InlineData("DVD-R DL LJR", MediaType.DVD)]
[InlineData("DVD+RW", MediaType.DVD)]
[InlineData("DVD+R", MediaType.DVD)]
[InlineData("DDCD-ROM", MediaType.CDROM)]
[InlineData("DDCD-R", MediaType.CDROM)]
[InlineData("DDCD-RW", MediaType.CDROM)]
[InlineData("DVD+RW DL", MediaType.DVD)]
[InlineData("DVD+R DL", MediaType.DVD)]
[InlineData("BD-ROM", MediaType.BluRay)]
[InlineData("BD-R", MediaType.BluRay)]
[InlineData("BD-R RRM", MediaType.BluRay)]
[InlineData("BD-RW", MediaType.BluRay)]
[InlineData("HD DVD-ROM", MediaType.HDDVD)]
[InlineData("HD DVD-R", MediaType.HDDVD)]
[InlineData("HD DVD-RAM", MediaType.HDDVD)]
[InlineData("HD DVD-RW", MediaType.HDDVD)]
[InlineData("HD DVD-R DL", MediaType.HDDVD)]
[InlineData("HD DVD-RW DL", MediaType.HDDVD)]
[InlineData("NON STANDARD", null)]
public void GetDiscTypeFromProfileTest(string? profile, MediaType? expected)
{
var actual = Redumper.GetDiscTypeFromProfile(profile);
Assert.Equal(expected, actual);
}
#endregion

View File

@@ -1 +1,6 @@
TEST DATA
<CICMMetadata>
<OpticalDisc>
<DiscType>Compact Disc</DiscType>
<DiscSubType>CD-ROM</DiscSubType>
</OpticalDisc>
</CICMMetadata>

View File

@@ -0,0 +1,2 @@
<< GetDiscType >>
DiscTypeIdentifier: BDO

View File

@@ -1,8 +1,5 @@
<< GetDiscType >>
DiscType: CD-ROM
DiscTypeIdentifier: GD-ROM
DiscTypeSpecific: DVD-ROM
BookType: BD-ROM
<< GetDVDProtection >>
========== CopyrightInformation ==========

View File

@@ -0,0 +1,2 @@
<< GetDiscType >>
BookType: DVD-ROM

View File

@@ -0,0 +1,2 @@
<< GetDiscType >>
BookType: HD DVD-ROM

View File

@@ -0,0 +1,3 @@
<< GetDiscType >>
disc type: INVALID
disc type: BLURAY-R

View File

@@ -0,0 +1,3 @@
<< GetDiscType >>
disc type: INVALID
disc type: BLURAY

View File

@@ -13,9 +13,13 @@ CUE [
dat:
<rom name="INVALID" size="12345" crc="00000000" md5="d41d8cd98f00b204e9800998ecf8427e" sha1="da39a3ee5e6b4b0d3255bfef95601890afd80709" />
<< GetDiscType >>
<< GetDiscProfile >>
current profile: CD-ROM
<< GetDiscType >>
disc type: INVALID
disc type: CD
<< GetDVDProtection >>
copyright:
protection system type: none

View File

@@ -0,0 +1,3 @@
<< GetDiscType >>
disc type: INVALID
disc type: DVD

View File

@@ -0,0 +1,3 @@
<< GetDiscType >>
disc type: INVALID
disc type: HD-DVD

View File

@@ -1,7 +1,21 @@
<< GetUMDAuxInfo >>
TITLE title
DISC_ID serial
DISC_VERSION version
pspUmdTypes GAME
L0 length 12345
FileSize: 12345
disc0:/PSP_GAME/PARAM.SFO
magic: PSF
version: 1.01
BOOTABLE: 1
CATEGORY: UG
DISC_ID: ABCD12345
DISC_NUMBER: 1
DISC_TOTAL: 1
DISC_VERSION: 1.01
PARENTAL_LEVEL: 1
PSP_SYSTEM_VER: 1.00
REGION: 32768
TITLE: title
pspUmdTypes: 0x10 (GAME)
L0 length: 442560 (0x6c0c0)
L1 length: 276096 (0x43680)
---------------------------
Total: 718656 (0xaf740)
FileSize: 1471807488 (0x57ba0000)

View File

@@ -8,17 +8,51 @@ namespace MPF.Processors.Test
{
public class UmdImageCreatorTests
{
#region DetermineMediaType
[Fact]
public void DetermineMediaType_Null_DVD()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.UMD, actual);
}
[Fact]
public void DetermineMediaType_Invalid_DVD()
{
string? outputDirectory = null;
string outputFilename = "INVALID";
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.UMD, actual);
}
[Fact]
public void DetermineMediaType_Valid_DVD()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "UmdImageCreator", "UMD");
string outputFilename = "test";
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.UMD, actual);
}
#endregion
#region GetOutputFiles
[Fact]
public void GetOutputFiles_Null_Empty()
public void GetOutputFiles_Null_Populated()
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable, null);
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Empty(actual);
var actual = processor.GetOutputFiles(null, outputDirectory, outputFilename);
Assert.Equal(7, actual.Count);
}
[Fact]
@@ -26,21 +60,21 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable, MediaType.UMD);
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.UMD, outputDirectory, outputFilename);
Assert.Equal(7, actual.Count);
}
[Fact]
public void GetOutputFiles_Other_Empty()
public void GetOutputFiles_Other_Populated()
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable, MediaType.ApertureCard);
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Empty(actual);
var actual = processor.GetOutputFiles(MediaType.ApertureCard, outputDirectory, outputFilename);
Assert.Equal(7, actual.Count);
}
#endregion
@@ -52,8 +86,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable, MediaType.UMD);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable);
var actual = processor.FoundAllFiles(MediaType.UMD, outputDirectory, outputFilename);
Assert.Equal(5, actual.Count);
}
@@ -62,8 +96,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "UmdImageCreator", "UMD");
string outputFilename = "test.iso";
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable, MediaType.UMD);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable);
var actual = processor.FoundAllFiles(MediaType.UMD, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -72,8 +106,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "UmdImageCreator", "UMD-zip");
string outputFilename = "test.iso";
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable, MediaType.UMD);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable);
var actual = processor.FoundAllFiles(MediaType.UMD, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -86,8 +120,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable, MediaType.UMD);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable);
var actual = processor.FoundAnyFiles(MediaType.UMD, outputDirectory, outputFilename);
Assert.False(actual);
}
@@ -96,8 +130,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "UmdImageCreator", "UMD");
string outputFilename = "test.iso";
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable, MediaType.UMD);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable);
var actual = processor.FoundAnyFiles(MediaType.UMD, outputDirectory, outputFilename);
Assert.True(actual);
}
@@ -110,8 +144,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable, MediaType.UMD);
var actual = processor.GenerateArtifacts(outputDirectory, outputFilename);
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable);
var actual = processor.GenerateArtifacts(MediaType.UMD, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -120,8 +154,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "UmdImageCreator", "UMD");
string outputFilename = "test.iso";
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable, MediaType.UMD);
var actual = processor.GenerateArtifacts(outputDirectory, outputFilename);
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable);
var actual = processor.GenerateArtifacts(MediaType.UMD, outputDirectory, outputFilename);
Assert.Equal(6, actual.Count);
}
@@ -134,8 +168,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable, MediaType.UMD);
var actual = processor.GetDeleteableFilePaths(outputDirectory, outputFilename);
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable);
var actual = processor.GetDeleteableFilePaths(MediaType.UMD, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -144,8 +178,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "UmdImageCreator", "UMD");
string outputFilename = "test.iso";
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable, MediaType.UMD);
var actual = processor.GetDeleteableFilePaths(outputDirectory, outputFilename);
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable);
var actual = processor.GetDeleteableFilePaths(MediaType.UMD, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -158,8 +192,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable, MediaType.UMD);
var actual = processor.GetZippableFilePaths(outputDirectory, outputFilename);
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable);
var actual = processor.GetZippableFilePaths(MediaType.UMD, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -168,8 +202,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "UmdImageCreator", "UMD");
string outputFilename = "test.iso";
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable, MediaType.UMD);
var actual = processor.GetZippableFilePaths(outputDirectory, outputFilename);
var processor = new UmdImageCreator(RedumpSystem.SonyPlayStationPortable);
var actual = processor.GetZippableFilePaths(MediaType.UMD, outputDirectory, outputFilename);
Assert.Equal(6, actual.Count);
}
@@ -257,10 +291,10 @@ namespace MPF.Processors.Test
{
string? expectedTitle = "title";
DiscCategory? expectedCategory = DiscCategory.Games;
string? expectedSerial = "seri-al";
string? expectedVersion = "version";
string? expectedLayer = "12345";
long expectedSize = 12345;
string? expectedSerial = "ABCD-12345";
string? expectedVersion = "1.01";
string? expectedLayer = "442560";
long expectedSize = 1471807488;
string disc = Path.Combine(Environment.CurrentDirectory, "TestData", "UmdImageCreator", "UMD", "test_disc.txt");
bool actual = UmdImageCreator.GetUMDAuxInfo(disc,
@@ -289,7 +323,7 @@ namespace MPF.Processors.Test
{
string volDesc = string.Empty;
bool actual = UmdImageCreator.GetVolumeLabels(volDesc, out Dictionary<string, List<string>> volLabels);
Assert.False(actual);
Assert.Empty(volLabels);
}
@@ -299,7 +333,7 @@ namespace MPF.Processors.Test
{
string volDesc = "INVALID";
bool actual = UmdImageCreator.GetVolumeLabels(volDesc, out Dictionary<string, List<string>> volLabels);
Assert.False(actual);
Assert.Empty(volLabels);
}

View File

@@ -8,17 +8,51 @@ namespace MPF.Processors.Test
// TODO: Add tests for RecreateSS
public class XboxBackupCreatorTests
{
#region DetermineMediaType
[Fact]
public void DetermineMediaType_Empty_DVD()
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.DVD, actual);
}
[Fact]
public void DetermineMediaType_Invalid_DVD()
{
string? outputDirectory = null;
string outputFilename = "INVALID";
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.DVD, actual);
}
[Fact]
public void DetermineMediaType_Valid_DVD()
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "XboxBackupCreator", "DVD");
string outputFilename = "test";
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox);
var actual = processor.DetermineMediaType(outputDirectory, outputFilename);
Assert.Equal(MediaType.DVD, actual);
}
#endregion
#region GetOutputFiles
[Fact]
public void GetOutputFiles_Null_Empty()
public void GetOutputFiles_Null_Populated()
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox, null);
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Empty(actual);
var actual = processor.GetOutputFiles(null, outputDirectory, outputFilename);
Assert.Equal(7, actual.Count);
}
[Fact]
@@ -26,21 +60,21 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox, MediaType.DVD);
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
var actual = processor.GetOutputFiles(MediaType.DVD, outputDirectory, outputFilename);
Assert.Equal(7, actual.Count);
}
[Fact]
public void GetOutputFiles_Other_Empty()
public void GetOutputFiles_Other_Populated()
{
string? outputDirectory = null;
string outputFilename = "test";
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox, MediaType.ApertureCard);
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox);
var actual = processor.GetOutputFiles(outputDirectory, outputFilename);
Assert.Empty(actual);
var actual = processor.GetOutputFiles(MediaType.ApertureCard, outputDirectory, outputFilename);
Assert.Equal(7, actual.Count);
}
#endregion
@@ -52,8 +86,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox, MediaType.DVD);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox);
var actual = processor.FoundAllFiles(MediaType.DVD, outputDirectory, outputFilename);
Assert.Equal(5, actual.Count);
}
@@ -62,8 +96,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "XboxBackupCreator", "DVD");
string outputFilename = "test.iso";
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox, MediaType.DVD);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox);
var actual = processor.FoundAllFiles(MediaType.DVD, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -72,8 +106,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "XboxBackupCreator", "DVD-zip");
string outputFilename = "test.iso";
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox, MediaType.DVD);
var actual = processor.FoundAllFiles(outputDirectory, outputFilename);
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox);
var actual = processor.FoundAllFiles(MediaType.DVD, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -86,8 +120,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox, MediaType.DVD);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox);
var actual = processor.FoundAnyFiles(MediaType.DVD, outputDirectory, outputFilename);
Assert.False(actual);
}
@@ -96,8 +130,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "XboxBackupCreator", "DVD");
string outputFilename = "test.iso";
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox, MediaType.DVD);
var actual = processor.FoundAnyFiles(outputDirectory, outputFilename);
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox);
var actual = processor.FoundAnyFiles(MediaType.DVD, outputDirectory, outputFilename);
Assert.True(actual);
}
@@ -110,8 +144,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox, MediaType.DVD);
var actual = processor.GenerateArtifacts(outputDirectory, outputFilename);
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox);
var actual = processor.GenerateArtifacts(MediaType.DVD, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -120,8 +154,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "XboxBackupCreator", "DVD");
string outputFilename = "test.iso";
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox, MediaType.DVD);
var actual = processor.GenerateArtifacts(outputDirectory, outputFilename);
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox);
var actual = processor.GenerateArtifacts(MediaType.DVD, outputDirectory, outputFilename);
Assert.Equal(6, actual.Count);
}
@@ -134,8 +168,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox, MediaType.DVD);
var actual = processor.GetDeleteableFilePaths(outputDirectory, outputFilename);
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox);
var actual = processor.GetDeleteableFilePaths(MediaType.DVD, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -144,8 +178,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "XboxBackupCreator", "DVD");
string outputFilename = "test.iso";
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox, MediaType.DVD);
var actual = processor.GetDeleteableFilePaths(outputDirectory, outputFilename);
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox);
var actual = processor.GetDeleteableFilePaths(MediaType.DVD, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -158,8 +192,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = null;
string outputFilename = string.Empty;
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox, MediaType.DVD);
var actual = processor.GetZippableFilePaths(outputDirectory, outputFilename);
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox);
var actual = processor.GetZippableFilePaths(MediaType.DVD, outputDirectory, outputFilename);
Assert.Empty(actual);
}
@@ -168,8 +202,8 @@ namespace MPF.Processors.Test
{
string? outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestData", "XboxBackupCreator", "DVD");
string outputFilename = "test.iso";
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox, MediaType.DVD);
var actual = processor.GetZippableFilePaths(outputDirectory, outputFilename);
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox);
var actual = processor.GetZippableFilePaths(MediaType.DVD, outputDirectory, outputFilename);
Assert.Equal(6, actual.Count);
}
@@ -340,7 +374,7 @@ namespace MPF.Processors.Test
{
long expected = -1;
string? log = null;
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox, MediaType.DVD);
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox);
bool actual = processor.GetReadErrors(log, out long readErrors);
Assert.False(actual);
@@ -352,7 +386,7 @@ namespace MPF.Processors.Test
{
long expected = -1;
string? log = string.Empty;
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox, MediaType.DVD);
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox);
bool actual = processor.GetReadErrors(log, out long readErrors);
Assert.False(actual);
@@ -364,7 +398,7 @@ namespace MPF.Processors.Test
{
long expected = -1;
string? log = "INVALID";
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox, MediaType.DVD);
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox);
bool actual = processor.GetReadErrors(log, out long readErrors);
Assert.False(actual);
@@ -376,7 +410,7 @@ namespace MPF.Processors.Test
{
long expected = 0;
string? log = Path.Combine(Environment.CurrentDirectory, "TestData", "XboxBackupCreator", "DVD", "log.txt");
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox, MediaType.DVD);
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox);
bool actual = processor.GetReadErrors(log, out long readErrors);
Assert.True(actual);
@@ -391,7 +425,7 @@ namespace MPF.Processors.Test
public void GetMediaID_Null_Null()
{
string? log = null;
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox360, MediaType.DVD);
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox360);
string? actual = processor.GetMediaID(log);
Assert.Null(actual);
}
@@ -400,7 +434,7 @@ namespace MPF.Processors.Test
public void GetMediaID_Empty_Null()
{
string? log = string.Empty;
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox360, MediaType.DVD);
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox360);
string? actual = processor.GetMediaID(log);
Assert.Null(actual);
}
@@ -409,7 +443,7 @@ namespace MPF.Processors.Test
public void GetMediaID_Invalid_Null()
{
string? log = "INVALID";
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox360, MediaType.DVD);
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox360);
string? actual = processor.GetMediaID(log);
Assert.Null(actual);
}
@@ -419,7 +453,7 @@ namespace MPF.Processors.Test
{
string? expected = "8B62A812";
string? log = Path.Combine(Environment.CurrentDirectory, "TestData", "XboxBackupCreator", "DVD", "log.txt");
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox360, MediaType.DVD);
var processor = new XboxBackupCreator(RedumpSystem.MicrosoftXbox360);
string? actual = processor.GetMediaID(log);
Assert.Equal(expected, actual);
}

View File

@@ -5,8 +5,8 @@ using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using SabreTools.Models.CueSheets;
using SabreTools.Models.Logiqx;
using SabreTools.Data.Models.CueSheets;
using SabreTools.Data.Models.Logiqx;
using SabreTools.RedumpLib;
using SabreTools.RedumpLib.Data;
using Schemas;
@@ -22,12 +22,35 @@ namespace MPF.Processors
public sealed class Aaru : BaseProcessor
{
/// <inheritdoc/>
public Aaru(RedumpSystem? system, MediaType? type) : base(system, type) { }
public Aaru(RedumpSystem? system) : base(system) { }
#region BaseProcessor Implementations
/// <inheritdoc/>
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, bool redumpCompat)
public override MediaType? DetermineMediaType(string? outputDirectory, string outputFilename)
{
// If the filename is invalid
if (string.IsNullOrEmpty(outputFilename))
return null;
// Reassemble the base path
string basePath = Path.GetFileNameWithoutExtension(outputFilename);
if (!string.IsNullOrEmpty(outputDirectory))
basePath = Path.Combine(outputDirectory, basePath);
// Deserialize the sidecar, if possible
var sidecar = GenerateSidecar($"{basePath}.cicm.xml");
// Extract the disc type strings, if possible
if (GetDiscType(sidecar, out string? discType, out string? discSubType))
return GetDiscTypeFromStrings(discType, discSubType);
// The type could not be determined
return null;
}
/// <inheritdoc/>
public override void GenerateSubmissionInfo(SubmissionInfo info, MediaType? mediaType, string basePath, bool redumpCompat)
{
// TODO: Fill in submission info specifics for Aaru
var outputDirectory = Path.GetDirectoryName(basePath);
@@ -36,10 +59,10 @@ namespace MPF.Processors
info = Builder.EnsureAllSections(info);
// TODO: Determine if there's an Aaru version anywhere
info.DumpingInfo!.DumpingDate = ProcessingTool.GetFileModifiedDate(basePath + ".cicm.xml")?.ToString("yyyy-MM-dd HH:mm:ss");
info.DumpingInfo!.DumpingDate = ProcessingTool.GetFileModifiedDate($"{basePath}.cicm.xml")?.ToString("yyyy-MM-dd HH:mm:ss");
// Deserialize the sidecar, if possible
var sidecar = GenerateSidecar(basePath + ".cicm.xml");
var sidecar = GenerateSidecar($"{basePath}.cicm.xml");
// Fill in the hardware data
if (GetHardwareInfo(sidecar, out var manufacturer, out var model, out var firmware))
@@ -63,31 +86,29 @@ namespace MPF.Processors
info.DumpingInfo.ReportedDiscType = fullDiscType;
}
// TODO: Re-enable once PVD generation / finding is fixed
// Generate / obtain the PVD
//info.Extras.PVD = GeneratePVD(sidecar) ?? "Disc has no PVD";
// Get the Datafile information
var datafile = GenerateDatafile(sidecar, basePath);
// Fill in the hash data
info.TracksAndWriteOffsets!.ClrMameProData = ProcessingTool.GenerateDatfile(datafile);
switch (Type)
// Get the error count
long errorCount = GetErrorCount($"{basePath}.resume.xml");
info.CommonDiscInfo!.ErrorsCount = (errorCount == -1 ? "Error retrieving error count" : errorCount.ToString());
// Get the write offset, if it exists
string? writeOffset = GetWriteOffset(sidecar);
info.CommonDiscInfo.RingWriteOffset = writeOffset;
info.TracksAndWriteOffsets.OtherWriteOffsets = writeOffset;
// Extract info based generically on MediaType
switch (mediaType)
{
// TODO: Can this do GD-ROM?
case MediaType.CDROM:
// TODO: Re-enable once PVD generation / finding is fixed
// Generate / obtain the PVD
//info.Extras.PVD = GeneratePVD(sidecar) ?? "Disc has no PVD";
long errorCount = -1;
if (File.Exists(basePath + ".resume.xml"))
errorCount = GetErrorCount(basePath + ".resume.xml");
info.CommonDiscInfo!.ErrorsCount = (errorCount == -1 ? "Error retrieving error count" : errorCount.ToString());
info.TracksAndWriteOffsets.Cuesheet = GenerateCuesheet(sidecar, basePath) ?? string.Empty;
string cdWriteOffset = GetWriteOffset(sidecar) ?? string.Empty;
info.CommonDiscInfo.RingWriteOffset = cdWriteOffset;
info.TracksAndWriteOffsets.OtherWriteOffsets = cdWriteOffset;
break;
case MediaType.DVD:
@@ -103,15 +124,12 @@ namespace MPF.Processors
info.SizeAndChecksums.SHA1 = sha1;
}
// TODO: Re-enable once PVD generation / finding is fixed
// Generate / obtain the PVD
//info.Extras.PVD = GeneratePVD(sidecar) ?? "Disc has no PVD";
// TODO: Sync layerbreak finding with other processors
// Deal with the layerbreak
string? layerbreak = null;
if (Type == MediaType.DVD)
if (mediaType == MediaType.DVD)
layerbreak = GetLayerbreak(sidecar) ?? string.Empty;
else if (Type == MediaType.BluRay)
else if (mediaType == MediaType.BluRay)
layerbreak = info.SizeAndChecksums!.Size > 25_025_314_816 ? "25025314816" : null;
// If we have a single-layer disc
@@ -185,12 +203,12 @@ namespace MPF.Processors
}
/// <inheritdoc/>
internal override List<OutputFile> GetOutputFiles(string? outputDirectory, string outputFilename)
internal override List<OutputFile> GetOutputFiles(MediaType? mediaType, string? outputDirectory, string outputFilename)
{
// Remove the extension by default
outputFilename = Path.GetFileNameWithoutExtension(outputFilename);
switch (Type)
switch (mediaType)
{
case MediaType.CDROM:
return [
@@ -391,7 +409,7 @@ namespace MPF.Processors
cueSheet.Files = [.. cueFiles];
if (cueSheet != null && cueSheet != default)
{
var ms = SabreTools.Serialization.Serializers.CueSheet.SerializeStream(cueSheet);
var ms = new SabreTools.Serialization.Writers.CueSheet().SerializeStream(cueSheet);
if (ms == null)
return null;
@@ -889,6 +907,156 @@ namespace MPF.Processors
return !string.IsNullOrEmpty(discType) || !string.IsNullOrEmpty(discSubType);
}
/// <summary>
/// Convert the type and subtype to a media type, if possible
/// </summary>
/// <param name="discType">Disc type string to check</param>
/// <param name="discSubType">Disc subtype string to check</param>
/// <returns>Media type on success, null otherwise</returns>
internal static MediaType? GetDiscTypeFromStrings(string? discType, string? discSubType)
{
return discType switch
{
"3\" floppy" => MediaType.FloppyDisk,
"3.5\" floppy" => MediaType.FloppyDisk,
"3.5\" magneto-optical" => MediaType.Floptical,
"3.5\" SyQuest cartridge" => null,
"3.9\" SyQuest cartridge" => null,
"5.25\" floppy" => MediaType.FloppyDisk,
"5.25\" magneto-optical" => MediaType.Floptical,
"5.25\" SyQuest cartridge" => null,
"8\" floppy" => MediaType.FloppyDisk,
"300mm magneto optical" => MediaType.Floptical,
"356mm magneto-optical" => MediaType.Floptical,
"Advanced Digital Recording" => null,
"Advanced Intelligent Tape" => null,
"Archival Disc" => null,
"BeeCard" => null,
"Blu-ray" => discSubType switch
{
"Wii U Optical Disc" => MediaType.NintendoWiiUOpticalDisc,
_ => MediaType.BluRay,
},
"Borsu" => null,
"Compact Cassette" => MediaType.Cassette,
"Compact Disc" => MediaType.CDROM,
"Compact Flash" => MediaType.CompactFlash,
"CompacTape" => null,
"CRVdisc" => null,
"Data8" => null,
"DataPlay" => null,
"DataStore" => null,
"DDCD" => MediaType.CDROM,
"DECtape" => null,
"DemiDiskette" => null,
"Digital Audio Tape" => null,
"Digital Data Storage" => MediaType.DataCartridge,
"Digital Linear Tape" => null,
"DIR" => null,
"DST" => null,
"DTF" => null,
"DTF2" => null,
"DV tape" => null,
"DVD" => discSubType switch
{
"GameCube Game Disc" => MediaType.NintendoGameCubeGameDisc,
"Wii Optical Disc" => MediaType.NintendoWiiOpticalDisc,
_ => MediaType.DVD,
},
"EVD" => null,
"Exatape" => null,
"Express Card" => null,
"FDDVD" => null,
"Flextra" => null,
"Floptical" => MediaType.Floptical,
"FVD" => null,
"GD" => MediaType.GDROM,
"Hard Disk Drive" => MediaType.HardDisk,
"HD DVD" => MediaType.HDDVD,
"HD VMD" => null,
"HiFD" => MediaType.FloppyDisk,
"HiTC" => null,
"HuCard" => MediaType.Cartridge,
"HVD" => null,
"HyperFlex" => null,
"IBM 3470" => null,
"IBM 3480" => null,
"IBM 3490" => null,
"IBM 3490E" => null,
"IBM 3592" => null,
"Iomega Bernoulli Box" => MediaType.IomegaBernoulliDisk,
"Iomega Bernoulli Box II" => MediaType.IomegaBernoulliDisk,
"Iomega Ditto" => null,
"Iomega Jaz" => MediaType.IomegaJaz,
"Iomega PocketZip" => MediaType.IomegaZip,
"Iomega REV" => null,
"Iomega ZIP" => MediaType.IomegaZip,
"Kodak Verbatim" => null,
"LaserDisc" => MediaType.LaserDisc,
"Linear Tape-Open" => null,
"LT1" => null,
"Magneto-optical" => MediaType.Floptical,
"Memory Stick" => MediaType.SDCard,
"MiniCard" => null,
"MiniDisc" => null,
"MultiMediaCard" => MediaType.SDCard,
"Nintendo 3DS Game Card" => MediaType.Cartridge,
"Nintendo 64 Disk" => MediaType.Nintendo64DD,
"Nintendo 64 Game Pak" => MediaType.Cartridge,
"Nintendo Disk Card" => MediaType.NintendoFamicomDiskSystem,
"Nintendo DS Game Card" => MediaType.Cartridge,
"Nintendo DSi Game Card" => MediaType.Cartridge,
"Nintendo Entertainment System Game Pak" => MediaType.Cartridge,
"Nintendo Famicom Game Pak" => MediaType.Cartridge,
"Nintendo Game Boy Advance Game Pak" => MediaType.Cartridge,
"Nintendo Game Boy Game Pak" => MediaType.Cartridge,
"Nintendo Switch Game Card" => MediaType.Cartridge,
"Optical Disc Archive" => null,
"Orb" => null,
"PCMCIA Card" => null,
"PD650" => null,
"PlayStation Memory Card" => null,
"Quarter-inch cartridge" => MediaType.DataCartridge,
"Quarter-inch mini cartridge" => MediaType.DataCartridge,
"QuickDisk" => null,
"RDX" => null,
"SACD" => MediaType.DVD,
"Scalable Linear Recording" => null,
"Secure Digital" => MediaType.SDCard,
"SmartMedia" => MediaType.SDCard,
"Sony Professional Disc" => null,
"Sony Professional Disc for DATA" => null,
"STK 4480" => null,
"STK 4490" => null,
"STK 9490" => null,
"STK T-9840" => null,
"STK T-9940" => null,
"STK T-10000" => null,
"Super Advanced Intelligent Tape" => null,
"Super Digital Linear Tape" => null,
"Super Nintendo Game Pak" => MediaType.Cartridge,
"Super Nintendo Game Pak (US)" => MediaType.Cartridge,
"SuperDisk" => MediaType.FloppyDisk,
"SVOD" => null,
"Travan" => null,
"UDO" => null,
"UHD144" => null,
"UMD" => MediaType.UMD,
"Unknown" => null,
"USB flash drive" => MediaType.FlashDrive,
"VCDHD" => null,
"VideoFloppy" => null,
"VideoNow" => MediaType.CDROM,
"VXA" => MediaType.FlashDrive,
"Wafer" => null,
"xD" => null,
"XQD" => null,
"Zoned Hard Disk Drive" => MediaType.HardDisk,
"ZX Microdrive" => null,
_ => null,
};
}
/// <summary>
/// Get the DVD protection information, if possible
/// </summary>

View File

@@ -1,11 +1,17 @@
using System;
using System.Collections.Generic;
using System.IO;
#if NET452_OR_GREATER || NETCOREAPP
using System.IO.Compression;
#endif
using System.Text;
using SabreTools.Hashing;
using SabreTools.Data.Models.Logiqx;
using SabreTools.RedumpLib.Data;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Archives;
using SharpCompress.Archives.Zip;
using SharpCompress.Common;
using SharpCompress.Compressors.Deflate;
using SharpCompress.Writers.Zip;
#endif
namespace MPF.Processors
{
@@ -23,42 +29,45 @@ namespace MPF.Processors
/// </summary>
public RedumpSystem? System { get; private set; }
/// <summary>
/// Currently represented media type
/// </summary>
public MediaType? Type { get; private set; }
#endregion
/// <summary>
/// Generate processor for a system and media type combination
/// </summary>
/// <param name="system">RedumpSystem value to use</param>
/// <param name="type">MediaType value to use</param>
public BaseProcessor(RedumpSystem? system, MediaType? type)
public BaseProcessor(RedumpSystem? system)
{
System = system;
Type = type;
}
#region Abstract Methods
/// <summary>
/// Determine the media type based on the provided files
/// </summary>
/// <param name="outputDirectory">Output folder to use as the base path</param>
/// <param name="outputFilename">Output filename to use as the base path</param>
/// <returns>MediaType that was determined, if possible</returns>
public abstract MediaType? DetermineMediaType(string? outputDirectory, string outputFilename);
/// <summary>
/// Generate a SubmissionInfo for the output files
/// </summary>
/// <param name="submissionInfo">Base submission info to fill in specifics for</param>
/// <param name="mediaType">Media type for specific information gathering</param>
/// <param name="basePath">Base filename and path to use for checking</param>
/// <param name="redumpCompat">Determines if outputs are processed according to Redump specifications</param>
public abstract void GenerateSubmissionInfo(SubmissionInfo submissionInfo, string basePath, bool redumpCompat);
public abstract void GenerateSubmissionInfo(SubmissionInfo submissionInfo, MediaType? mediaType, string basePath, bool redumpCompat);
// <summary>
/// Generate a list of all output files generated
/// </summary>
/// <param name="mediaType">Media type for controlling expected file sets</param>
/// <param name="outputDirectory">Output folder to use as the base path</param>
/// <param name="outputFilename">Output filename to use as the base path</param>
/// <returns>List of all output files, empty otherwise</returns>
/// <remarks>Assumes filename has an extension</remarks>
internal abstract List<OutputFile> GetOutputFiles(string? outputDirectory, string outputFilename);
internal abstract List<OutputFile> GetOutputFiles(MediaType? mediaType, string? outputDirectory, string outputFilename);
#endregion
@@ -67,15 +76,22 @@ namespace MPF.Processors
/// <summary>
/// Compress log files to save space
/// </summary>
/// <param name="mediaType">Media type for controlling expected file sets</param>
/// <param name="logCompression">Compression type to use for logs</param>
/// <param name="outputDirectory">Output folder to use as the base path</param>
/// <param name="outputFilename">Output filename to use as the base path</param>
/// <param name="filenameSuffix">Output filename to use as the base path</param>
/// <param name="processor">Processor object representing how to process the outputs</param>
/// <returns>True if the process succeeded, false otherwise</returns>
/// <remarks>Assumes filename has an extension</remarks>
public bool CompressLogFiles(string? outputDirectory, string outputFilename, string? filenameSuffix, out string status)
public bool CompressLogFiles(MediaType? mediaType,
LogCompression logCompression,
string? outputDirectory,
string outputFilename,
string? filenameSuffix,
out string status)
{
#if NET20 || NET35 || NET40
#if NET20 || NET35 || NET40 || NET452
status = "Log compression is not available for this framework version";
return false;
#else
@@ -88,7 +104,7 @@ namespace MPF.Processors
string archiveName = $"{basePath}_logs.zip";
// Get the lists of zippable files
var zippableFiles = GetZippableFilePaths(outputDirectory, outputFilename);
var zippableFiles = GetZippableFilePaths(mediaType, outputDirectory, outputFilename);
var generatedFiles = GetGeneratedFilePaths(outputDirectory, filenameSuffix);
// Don't create an archive if there are no paths
@@ -98,26 +114,46 @@ namespace MPF.Processors
return true;
}
// If the file already exists, we want to delete the old one
try
// If the file already exists, change the archive name
if (File.Exists(archiveName))
{
if (File.Exists(archiveName))
File.Delete(archiveName);
}
catch
{
status = "Could not delete old archive!";
return false;
string now = DateTime.Now.ToString("yyyyMMdd-HHmmss");
archiveName = $"{basePath}_logs_{now}.zip";
}
// Add the log files to the archive and delete the uncompressed file after
ZipArchive? zf = null;
bool disposed = false;
try
{
zf = ZipFile.Open(archiveName, ZipArchiveMode.Create);
zf = ZipArchive.Create();
_ = AddToArchive(zf, zippableFiles, outputDirectory, true);
_ = AddToArchive(zf, generatedFiles, outputDirectory, false);
List<string> successful = AddToArchive(zf, zippableFiles, outputDirectory);
_ = AddToArchive(zf, generatedFiles, outputDirectory);
switch (logCompression)
{
case LogCompression.DeflateMaximum:
zf.SaveTo(archiveName, new ZipWriterOptions(CompressionType.Deflate, CompressionLevel.BestCompression) { UseZip64 = true });
break;
case LogCompression.Zstd19:
zf.SaveTo(archiveName, new ZipWriterOptions(CompressionType.ZStandard, (CompressionLevel)19) { UseZip64 = true });
break;
case LogCompression.DeflateDefault:
default:
zf.SaveTo(archiveName, new ZipWriterOptions(CompressionType.Deflate, CompressionLevel.Default) { UseZip64 = true });
break;
}
// Dispose the archive
zf?.Dispose();
disposed = true;
// Delete all successful files
foreach (string file in successful)
{
try { File.Delete(file); } catch { }
}
status = "Compression complete!";
return true;
@@ -129,7 +165,8 @@ namespace MPF.Processors
}
finally
{
zf?.Dispose();
if (!disposed)
zf?.Dispose();
}
#endif
}
@@ -137,15 +174,19 @@ namespace MPF.Processors
/// <summary>
/// Compress log files to save space
/// </summary>
/// <param name="mediaType">Media type for controlling expected file sets</param>
/// <param name="outputDirectory">Output folder to use as the base path</param>
/// <param name="outputFilename">Output filename to use as the base path</param>
/// <param name="processor">Processor object representing how to process the outputs</param>
/// <returns>True if the process succeeded, false otherwise</returns>
/// <remarks>Assumes filename has an extension</remarks>
public bool DeleteUnnecessaryFiles(string? outputDirectory, string outputFilename, out string status)
public bool DeleteUnnecessaryFiles(MediaType? mediaType,
string? outputDirectory,
string outputFilename,
out string status)
{
// Get the list of deleteable files from the parameters object
var files = GetDeleteableFilePaths(outputDirectory, outputFilename);
var files = GetDeleteableFilePaths(mediaType, outputDirectory, outputFilename);
if (files.Count == 0)
{
@@ -170,11 +211,12 @@ namespace MPF.Processors
/// <summary>
/// Ensures that all required output files have been created
/// </summary>
/// <param name="mediaType">Media type for controlling expected file sets</param>
/// <param name="outputDirectory">Output folder to use as the base path</param>
/// <param name="outputFilename">Output filename to use as the base path</param>
/// <returns>A list representing missing files, empty if none</returns>
/// <remarks>Assumes filename has an extension</remarks>
public List<string> FoundAllFiles(string? outputDirectory, string outputFilename)
public List<string> FoundAllFiles(MediaType? mediaType, string? outputDirectory, string outputFilename)
{
// Assemble a base path
string basePath = Path.GetFileNameWithoutExtension(outputFilename);
@@ -182,23 +224,23 @@ namespace MPF.Processors
basePath = Path.Combine(outputDirectory, basePath);
// Get the list of output files
var outputFiles = GetOutputFiles(outputDirectory, outputFilename);
var outputFiles = GetOutputFiles(mediaType, outputDirectory, outputFilename);
if (outputFiles.Count == 0)
return ["Media and system combination not supported"];
// Check for the log file
bool logArchiveExists = false;
#if NET452_OR_GREATER || NETCOREAPP
#if NET462_OR_GREATER || NETCOREAPP
ZipArchive? logArchive = null;
#endif
if (File.Exists($"{basePath}_logs.zip"))
{
logArchiveExists = true;
#if NET452_OR_GREATER || NETCOREAPP
#if NET462_OR_GREATER || NETCOREAPP
try
{
// Try to open the archive
logArchive = ZipFile.OpenRead($"{basePath}_logs.zip");
logArchive = ZipArchive.Open($"{basePath}_logs.zip");
}
catch
{
@@ -226,7 +268,7 @@ namespace MPF.Processors
continue;
}
#if NET20 || NET35 || NET40
#if NET20 || NET35 || NET40 || NET452
// Assume the zipfile has the file in it
continue;
#else
@@ -239,7 +281,7 @@ namespace MPF.Processors
#endif
}
#if NET452_OR_GREATER || NETCOREAPP
#if NET462_OR_GREATER || NETCOREAPP
// Close the log archive, if it exists
logArchive?.Dispose();
#endif
@@ -250,11 +292,12 @@ namespace MPF.Processors
/// <summary>
/// Ensures that no potential output files have been created
/// </summary>
/// <param name="mediaType">Media type for controlling expected file sets</param>
/// <param name="outputDirectory">Output folder to use as the base path</param>
/// <param name="outputFilename">Output filename to use as the base path</param>
/// <returns>True if any dumping files exist, False if none</returns>
/// <remarks>Assumes filename has an extension</remarks>
public bool FoundAnyFiles(string? outputDirectory, string outputFilename)
public bool FoundAnyFiles(MediaType? mediaType, string? outputDirectory, string outputFilename)
{
// Assemble a base path
string basePath = Path.GetFileNameWithoutExtension(outputFilename);
@@ -262,7 +305,7 @@ namespace MPF.Processors
basePath = Path.Combine(outputDirectory, basePath);
// Get the list of output files
var outputFiles = GetOutputFiles(outputDirectory, outputFilename);
var outputFiles = GetOutputFiles(mediaType, outputDirectory, outputFilename);
if (outputFiles.Count == 0)
return false;
@@ -284,78 +327,87 @@ namespace MPF.Processors
/// <summary>
/// Generate artifacts and return them as a dictionary
/// </summary>
/// <param name="mediaType">Media type for controlling expected file sets</param>
/// <param name="outputDirectory">Output folder to use as the base path</param>
/// <param name="outputFilename">Output filename to use as the base path</param>
/// <returns>Dictiionary of artifact keys to Base64-encoded values, if possible</param>
/// <remarks>Assumes filename has an extension</remarks>
public Dictionary<string, string> GenerateArtifacts(string? outputDirectory, string outputFilename)
public Dictionary<string, string> GenerateArtifacts(MediaType? mediaType, string? outputDirectory, string outputFilename)
{
// Get the list of output files
var outputFiles = GetOutputFiles(outputDirectory, outputFilename);
var outputFiles = GetOutputFiles(mediaType, outputDirectory, outputFilename);
if (outputFiles.Count == 0)
return [];
// Create the artifacts dictionary
var artifacts = new Dictionary<string, string>();
// Only try to create artifacts for files that exist
foreach (var outputFile in outputFiles)
try
{
// Skip non-artifact files
if (!outputFile.IsArtifact || outputFile.ArtifactKey == null)
continue;
// Create the artifacts dictionary
var artifacts = new Dictionary<string, string>();
// Skip non-existent files
if (!outputFile.Exists(outputDirectory ?? string.Empty))
continue;
// Skip non-existent files
foreach (var filePath in outputFile.GetPaths(outputDirectory ?? string.Empty))
// Only try to create artifacts for files that exist
foreach (var outputFile in outputFiles)
{
// Get binary artifacts as a byte array
if (outputFile.IsBinaryArtifact)
{
byte[] data = File.ReadAllBytes(filePath);
string str = Convert.ToBase64String(data);
artifacts[outputFile.ArtifactKey] = str;
}
else
{
string? data = ProcessingTool.GetFullFile(filePath);
string str = ProcessingTool.GetBase64(data) ?? string.Empty;
artifacts[outputFile.ArtifactKey] = str;
}
// Skip non-artifact files
if (!outputFile.IsArtifact || outputFile.ArtifactKey == null)
continue;
break;
// Skip non-existent files
if (!outputFile.Exists(outputDirectory ?? string.Empty))
continue;
// Skip non-existent files
foreach (var filePath in outputFile.GetPaths(outputDirectory ?? string.Empty))
{
// Get binary artifacts as a byte array
if (outputFile.IsBinaryArtifact)
{
byte[] data = File.ReadAllBytes(filePath);
string str = Convert.ToBase64String(data);
artifacts[outputFile.ArtifactKey] = str;
}
else
{
string? data = ProcessingTool.GetFullFile(filePath);
string str = ProcessingTool.GetBase64(data) ?? string.Empty;
artifacts[outputFile.ArtifactKey] = str;
}
break;
}
}
}
return artifacts;
return artifacts;
}
catch
{
// Any issues shouldn't stop processing
return [];
}
}
#if NET452_OR_GREATER || NETCOREAPP
#if NET462_OR_GREATER || NETCOREAPP
/// <summary>
/// Try to add a set of files to an existing archive
/// </summary>
/// <param name="archive">Archive to add the file to</param>
/// <param name="files">Full path to a set of existing files</param>
/// <param name="outputDirectory">Directory that the existing files live in</param>
/// <param name="delete">Indicates if the files should be deleted after adding</param>
/// <returns>True if all files were added successfully, false otherwise</returns>
private static bool AddToArchive(ZipArchive archive, List<string> files, string? outputDirectory, bool delete)
/// <returns>List of all files that were successfully added</returns>
private static List<string> AddToArchive(ZipArchive archive, List<string> files, string? outputDirectory)
{
// An empty list means success
if (files.Count == 0)
return true;
return [];
// Loop through and add all files
bool allAdded = true;
List<string> added = [];
foreach (string file in files)
{
allAdded &= AddToArchive(archive, file, outputDirectory, delete);
if (AddToArchive(archive, file, outputDirectory))
added.Add(file);
}
return allAdded;
return added;
}
/// <summary>
@@ -364,9 +416,8 @@ namespace MPF.Processors
/// <param name="archive">Archive to add the file to</param>
/// <param name="file">Full path to an existing file</param>
/// <param name="outputDirectory">Directory that the existing file lives in</param>
/// <param name="delete">Indicates if the file should be deleted after adding</param>
/// <returns>True if the file was added successfully, false otherwise</returns>
private static bool AddToArchive(ZipArchive archive, string file, string? outputDirectory, bool delete)
private static bool AddToArchive(ZipArchive archive, string file, string? outputDirectory)
{
// Check if the file exists
if (!File.Exists(file))
@@ -383,23 +434,13 @@ namespace MPF.Processors
// Create and add the entry
try
{
#if NETFRAMEWORK || NETCOREAPP3_1 || NET5_0
archive.CreateEntryFromFile(file, entryName, CompressionLevel.Optimal);
#else
archive.CreateEntryFromFile(file, entryName, CompressionLevel.SmallestSize);
#endif
archive.AddEntry(entryName, file);
}
catch
{
return false;
}
// Try to delete the file if requested
if (delete)
{
try { File.Delete(file); } catch { }
}
return true;
}
#endif
@@ -407,14 +448,15 @@ namespace MPF.Processors
/// <summary>
/// Generate a list of all deleteable file paths
/// </summary>
/// <param name="mediaType">Media type for controlling expected file sets</param>
/// <param name="outputDirectory">Output folder to use as the base path</param>
/// <param name="outputFilename">Output filename to use as the base path</param>
/// <returns>List of all deleteable file paths, empty otherwise</returns>
/// <remarks>Assumes filename has an extension</remarks>
internal List<string> GetDeleteableFilePaths(string? outputDirectory, string outputFilename)
internal List<string> GetDeleteableFilePaths(MediaType? mediaType, string? outputDirectory, string outputFilename)
{
// Get the list of output files
var outputFiles = GetOutputFiles(outputDirectory, outputFilename);
var outputFiles = GetOutputFiles(mediaType, outputDirectory, outputFilename);
if (outputFiles.Count == 0)
return [];
@@ -490,14 +532,15 @@ namespace MPF.Processors
/// <summary>
/// Generate a list of all zippable file paths
/// </summary>
/// <param name="mediaType">Media type for controlling expected file sets</param>
/// <param name="outputDirectory">Output folder to use as the base path</param>
/// <param name="outputFilename">Output filename to use as the base path</param>
/// <returns>List of all zippable file paths, empty otherwise</returns>
/// <remarks>Assumes filename has an extension</remarks>
internal List<string> GetZippableFilePaths(string? outputDirectory, string outputFilename)
internal List<string> GetZippableFilePaths(MediaType? mediaType, string? outputDirectory, string outputFilename)
{
// Get the list of output files
var outputFiles = GetOutputFiles(outputDirectory, outputFilename);
var outputFiles = GetOutputFiles(mediaType, outputDirectory, outputFilename);
if (outputFiles.Count == 0)
return [];
@@ -520,6 +563,38 @@ namespace MPF.Processors
#region Shared Methods
/// <summary>
/// Generate a CMP XML datfile string based on a single input file
/// </summary>
/// <param name="file">File to generate a datfile for</param>
/// <returns>Datafile containing the hash information, null on error</returns>
internal static Datafile? GenerateDatafile(string file)
{
// If the file is invalid
if (string.IsNullOrEmpty(file))
return null;
if (!File.Exists(file))
return null;
// Attempt to get the hashes
if (!HashTool.GetStandardHashes(file, out long size, out var crc32, out var md5, out var sha1))
return null;
// Generate and return the Datafile
var rom = new Rom
{
Name = string.Empty,
Size = size.ToString(),
CRC = crc32,
MD5 = md5,
SHA1 = sha1,
};
var game = new Game { Rom = [rom] };
var datafile = new Datafile { Game = [game] };
return datafile;
}
/// <summary>
/// Get the hex contents of the PIC file
/// </summary>
@@ -527,8 +602,12 @@ namespace MPF.Processors
/// <param name="trimLength">Number of characters to trim the PIC to, if -1, ignored</param>
/// <returns>PIC data as a hex string if possible, null on error</returns>
/// <remarks>https://stackoverflow.com/questions/9932096/add-separator-to-string-at-every-n-characters</remarks>
internal static string? GetPIC(string picPath, int trimLength = -1)
internal static string? GetPIC(string? picPath, int trimLength = -1)
{
// If the file is invalid
if (picPath == null)
return null;
// If the file doesn't exist, we can't get the info
if (!File.Exists(picPath))
return null;

View File

@@ -1,8 +1,8 @@
using System.Collections.Generic;
using System.IO;
using System.Text;
using SabreTools.Data.Models.Logiqx;
using SabreTools.Hashing;
using SabreTools.Models.Logiqx;
using SabreTools.RedumpLib;
using SabreTools.RedumpLib.Data;
@@ -14,21 +14,32 @@ namespace MPF.Processors
public sealed class CleanRip : BaseProcessor
{
/// <inheritdoc/>
public CleanRip(RedumpSystem? system, MediaType? type) : base(system, type) { }
public CleanRip(RedumpSystem? system) : base(system) { }
#region BaseProcessor Implementations
/// <inheritdoc/>
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, bool redumpCompat)
public override MediaType? DetermineMediaType(string? outputDirectory, string outputFilename)
{
return System switch
{
RedumpSystem.NintendoGameCube => MediaType.NintendoGameCubeGameDisc,
RedumpSystem.NintendoWii => MediaType.NintendoWiiOpticalDisc,
_ => null,
};
}
/// <inheritdoc/>
public override void GenerateSubmissionInfo(SubmissionInfo info, MediaType? mediaType, string basePath, bool redumpCompat)
{
// Ensure that required sections exist
info = Builder.EnsureAllSections(info);
// TODO: Determine if there's a CleanRip version anywhere
info.DumpingInfo!.DumpingDate = ProcessingTool.GetFileModifiedDate(basePath + "-dumpinfo.txt")?.ToString("yyyy-MM-dd HH:mm:ss");
info.DumpingInfo!.DumpingDate = ProcessingTool.GetFileModifiedDate($"{basePath}-dumpinfo.txt")?.ToString("yyyy-MM-dd HH:mm:ss");
// Get the Datafile information
var datafile = GenerateCleanripDatafile(basePath + ".iso", basePath + "-dumpinfo.txt");
var datafile = GenerateCleanripDatafile($"{basePath}.iso", $"{basePath}-dumpinfo.txt");
info.TracksAndWriteOffsets!.ClrMameProData = ProcessingTool.GenerateDatfile(datafile);
// Get the individual hash data, as per internal
@@ -44,56 +55,40 @@ namespace MPF.Processors
info.SizeAndChecksums.Layerbreak = 2084960;
}
// Extract info based generically on MediaType
switch (Type)
// Get BCA information, if available
info.Extras!.BCA = GetBCA(basePath + $"{basePath}.bca");
// Get internal information
if (GetGameCubeWiiInformation(basePath + $"{basePath}-dumpinfo.txt", out Region? region, out var version, out var internalName, out var serial))
{
case MediaType.DVD: // Only added here to help users; not strictly correct
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
if (File.Exists(basePath + ".bca"))
info.Extras!.BCA = GetBCA(basePath + ".bca");
if (GetGameCubeWiiInformation(basePath + "-dumpinfo.txt", out Region? gcRegion, out var gcVersion, out var gcName, out var gcSerial))
{
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalName] = gcName ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = gcSerial ?? string.Empty;
if (!redumpCompat)
{
info.VersionAndEditions!.Version = gcVersion ?? info.VersionAndEditions.Version;
info.CommonDiscInfo.Region = gcRegion ?? info.CommonDiscInfo.Region;
}
}
break;
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalName] = internalName ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = serial ?? string.Empty;
if (!redumpCompat)
{
info.VersionAndEditions!.Version = version ?? info.VersionAndEditions.Version;
info.CommonDiscInfo.Region = region ?? info.CommonDiscInfo.Region;
}
}
}
/// <inheritdoc/>
internal override List<OutputFile> GetOutputFiles(string? outputDirectory, string outputFilename)
internal override List<OutputFile> GetOutputFiles(MediaType? mediaType, string? outputDirectory, string outputFilename)
{
// Remove the extension by default
outputFilename = Path.GetFileNameWithoutExtension(outputFilename);
switch (Type)
{
case MediaType.DVD: // Only added here to help users; not strictly correct
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
return [
new($"{outputFilename}.bca", OutputFileFlags.Required
| OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"bca"),
new($"{outputFilename}.iso", OutputFileFlags.Required),
return [
new($"{outputFilename}.bca", OutputFileFlags.Required
| OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"bca"),
new([$"{outputFilename}.iso", $"{outputFilename}.part0.iso"], OutputFileFlags.Required),
new($"{outputFilename}-dumpinfo.txt", OutputFileFlags.Required
| OutputFileFlags.Artifact
| OutputFileFlags.Zippable,
"dumpinfo"),
];
}
return [];
new($"{outputFilename}-dumpinfo.txt", OutputFileFlags.Required
| OutputFileFlags.Artifact
| OutputFileFlags.Zippable,
"dumpinfo"),
];
}
#endregion

View File

@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
#if NET452_OR_GREATER || NETCOREAPP
using System.IO.Compression;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Archives.Zip;
#endif
namespace MPF.Processors
@@ -78,7 +78,7 @@ namespace MPF.Processors
return false;
}
#if NET452_OR_GREATER || NETCOREAPP
#if NET462_OR_GREATER || NETCOREAPP
/// <inheritdoc/>
public override bool Exists(ZipArchive? archive)
{

View File

@@ -5,7 +5,7 @@ using System.IO;
using System.Linq;
#endif
using System.Text.RegularExpressions;
using SabreTools.Models.Logiqx;
using SabreTools.Data.Models.Logiqx;
using SabreTools.RedumpLib;
using SabreTools.RedumpLib.Data;
@@ -63,15 +63,92 @@ namespace MPF.Processors
public sealed class DiscImageCreator : BaseProcessor
{
/// <inheritdoc/>
public DiscImageCreator(RedumpSystem? system, MediaType? type) : base(system, type) { }
public DiscImageCreator(RedumpSystem? system) : base(system) { }
#region BaseProcessor Implementations
/// <inheritdoc/>
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, bool redumpCompat)
public override MediaType? DetermineMediaType(string? outputDirectory, string outputFilename)
{
var outputDirectory = Path.GetDirectoryName(basePath);
// If the filename is invalid
if (string.IsNullOrEmpty(outputFilename))
return null;
// Reassemble the base path
string basePath = Path.GetFileNameWithoutExtension(outputFilename);
if (!string.IsNullOrEmpty(outputDirectory))
basePath = Path.Combine(outputDirectory, basePath);
// Get the comma-separated list of values
if (GetDiscType($"{basePath}_disc.txt", out var discType) && discType != null)
{
// CD-ROM
if (discType.Contains("CD-DA or CD-ROM Disc"))
return MediaType.CDROM;
else if (discType.Contains("CD-I Disc"))
return MediaType.CDROM;
else if (discType.Contains("CD-ROM XA Disc"))
return MediaType.CDROM;
// HD-DVD
if (discType.Contains("HD DVD-ROM"))
return MediaType.HDDVD;
else if (discType.Contains("HD DVD-RAM"))
return MediaType.HDDVD;
else if (discType.Contains("HD DVD-R"))
return MediaType.HDDVD;
// DVD
if (discType.Contains("DVD-ROM"))
return MediaType.DVD;
else if (discType.Contains("DVD-RAM"))
return MediaType.DVD;
else if (discType.Contains("DVD-R"))
return MediaType.DVD;
else if (discType.Contains("DVD-RW"))
return MediaType.DVD;
else if (discType.Contains("Reserved1"))
return MediaType.DVD;
else if (discType.Contains("Reserved2"))
return MediaType.DVD;
else if (discType.Contains("DVD+RW"))
return MediaType.DVD;
else if (discType.Contains("DVD+R"))
return MediaType.DVD;
else if (discType.Contains("Reserved3"))
return MediaType.DVD;
else if (discType.Contains("Reserved4"))
return MediaType.DVD;
else if (discType.Contains("DVD+RW DL"))
return MediaType.DVD;
else if (discType.Contains("DVD+R DL"))
return MediaType.DVD;
else if (discType.Contains("Reserved5"))
return MediaType.NintendoWiiOpticalDisc;
// Blu-ray
if (discType.Contains("BDO"))
return MediaType.BluRay;
else if (discType.Contains("BDU"))
return MediaType.BluRay;
else if (discType.Contains("BDW"))
return MediaType.BluRay;
else if (discType.Contains("BDR"))
return MediaType.BluRay;
else if (discType.Contains("XG4"))
return MediaType.BluRay;
// Assume CD-ROM for everything else
return MediaType.CDROM;
}
// The type could not be determined
return null;
}
/// <inheritdoc/>
public override void GenerateSubmissionInfo(SubmissionInfo info, MediaType? mediaType, string basePath, bool redumpCompat)
{
// Ensure that required sections exist
info = Builder.EnsureAllSections(info);
@@ -94,25 +171,36 @@ namespace MPF.Processors
if (GetDiscType($"{basePath}_disc.txt", out var discTypeOrBookType))
info.DumpingInfo.ReportedDiscType = discTypeOrBookType;
// Get the PVD, if it exists
info.Extras!.PVD = GetPVD($"{basePath}_mainInfo.txt") ?? "Disc has no PVD";
// Get the Datafile information
var datafile = ProcessingTool.GetDatafile($"{basePath}.dat");
// Fill in the hash data
info.TracksAndWriteOffsets!.ClrMameProData = ProcessingTool.GenerateDatfile(datafile);
// Get the write offset, if it exists
string? writeOffset = GetWriteOffset($"{basePath}_disc.txt");
info.CommonDiscInfo!.RingWriteOffset = writeOffset;
info.TracksAndWriteOffsets.OtherWriteOffsets = writeOffset;
// Attempt to get multisession data
string? multiSessionInfo = GetMultisessionInformation($"{basePath}_disc.txt");
if (!string.IsNullOrEmpty(multiSessionInfo))
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.Multisession] = multiSessionInfo!;
// Fill in the volume labels
if (GetVolumeLabels($"{basePath}_volDesc.txt", out var volLabels))
VolumeLabels = volLabels;
// Extract info based generically on MediaType
switch (Type)
switch (mediaType)
{
case MediaType.CDROM:
case MediaType.GDROM: // TODO: Verify GD-ROM outputs this
info.Extras!.PVD = GetPVD($"{basePath}_mainInfo.txt") ?? "Disc has no PVD";
info.TracksAndWriteOffsets.Cuesheet = ProcessingTool.GetFullFile($"{basePath}.cue") ?? string.Empty;
// Audio-only discs will fail if there are any C2 errors, so they would never get here
if (System.IsAudio())
if (IsAudio(info.TracksAndWriteOffsets.Cuesheet))
{
info.CommonDiscInfo!.ErrorsCount = "0";
}
@@ -127,19 +215,6 @@ namespace MPF.Processors
info.CommonDiscInfo!.ErrorsCount = (errorCount == -1 ? "Error retrieving error count" : errorCount.ToString());
}
info.TracksAndWriteOffsets.Cuesheet = ProcessingTool.GetFullFile($"{basePath}.cue") ?? string.Empty;
//var cueSheet = new CueSheet($"{basePath}.cue"); // TODO: Do something with this
// Attempt to get the write offset
string cdWriteOffset = GetWriteOffset($"{basePath}_disc.txt") ?? string.Empty;
info.CommonDiscInfo.RingWriteOffset = cdWriteOffset;
info.TracksAndWriteOffsets.OtherWriteOffsets = cdWriteOffset;
// Attempt to get multisession data
string cdMultiSessionInfo = GetMultisessionInformation($"{basePath}_disc.txt") ?? string.Empty;
if (!string.IsNullOrEmpty(cdMultiSessionInfo))
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.Multisession] = cdMultiSessionInfo;
break;
case MediaType.DVD:
@@ -156,12 +231,12 @@ namespace MPF.Processors
}
// Deal with the layerbreaks
if (Type == MediaType.DVD)
if (mediaType == MediaType.DVD)
{
string layerbreak = GetLayerbreak($"{basePath}_disc.txt", System.IsXGD()) ?? string.Empty;
info.SizeAndChecksums!.Layerbreak = !string.IsNullOrEmpty(layerbreak) ? long.Parse(layerbreak) : default;
}
else if (Type == MediaType.BluRay)
else if (mediaType == MediaType.BluRay)
{
var di = ProcessingTool.GetDiscInformation($"{basePath}_PIC.bin");
info.SizeAndChecksums!.PICIdentifier = ProcessingTool.GetPICIdentifier(di);
@@ -178,11 +253,8 @@ namespace MPF.Processors
}
}
// Read the PVD
info.Extras!.PVD = GetPVD($"{basePath}_mainInfo.txt") ?? string.Empty;
// Bluray-specific options
if (Type == MediaType.BluRay)
if (mediaType == MediaType.BluRay)
{
int trimLength = -1;
switch (System)
@@ -217,7 +289,7 @@ namespace MPF.Processors
case RedumpSystem.SonyElectronicBook:
info.CopyProtection!.SecuROMData = GetSecuROMData($"{basePath}_subIntention.txt", out SecuROMScheme secuROMScheme) ?? string.Empty;
if (secuROMScheme == SecuROMScheme.Unknown)
info.CommonDiscInfo!.Comments = "Warning: Incorrect SecuROM sector count" + Environment.NewLine;
info.CommonDiscInfo!.Comments = $"Warning: Incorrect SecuROM sector count{Environment.NewLine}";
// Needed for some odd copy protections
info.CopyProtection!.Protection = GetDVDProtection($"{basePath}_CSSKey.txt", $"{basePath}_disc.txt", false) ?? string.Empty;
@@ -322,7 +394,7 @@ namespace MPF.Processors
break;
case RedumpSystem.NamcoSegaNintendoTriforce:
if (Type == MediaType.CDROM)
if (mediaType == MediaType.CDROM)
{
info.Extras!.Header = GetSegaHeader($"{basePath}_mainInfo.txt") ?? string.Empty;
@@ -361,7 +433,7 @@ namespace MPF.Processors
break;
case RedumpSystem.SegaChihiro:
if (Type == MediaType.CDROM)
if (mediaType == MediaType.CDROM)
{
info.Extras!.Header = GetSegaHeader($"{basePath}_mainInfo.txt") ?? string.Empty;
@@ -384,7 +456,7 @@ namespace MPF.Processors
break;
case RedumpSystem.SegaDreamcast:
if (Type == MediaType.CDROM)
if (mediaType == MediaType.CDROM)
{
info.Extras!.Header = GetSegaHeader($"{basePath}_mainInfo.txt") ?? string.Empty;
@@ -407,7 +479,7 @@ namespace MPF.Processors
break;
case RedumpSystem.SegaNaomi:
if (Type == MediaType.CDROM)
if (mediaType == MediaType.CDROM)
{
info.Extras!.Header = GetSegaHeader($"{basePath}_mainInfo.txt") ?? string.Empty;
@@ -430,7 +502,7 @@ namespace MPF.Processors
break;
case RedumpSystem.SegaNaomi2:
if (Type == MediaType.CDROM)
if (mediaType == MediaType.CDROM)
{
info.Extras!.Header = GetSegaHeader($"{basePath}_mainInfo.txt") ?? string.Empty;
@@ -497,12 +569,12 @@ namespace MPF.Processors
}
/// <inheritdoc/>
internal override List<OutputFile> GetOutputFiles(string? outputDirectory, string outputFilename)
internal override List<OutputFile> GetOutputFiles(MediaType? mediaType, string? outputDirectory, string outputFilename)
{
// Remove the extension by default
outputFilename = Path.GetFileNameWithoutExtension(outputFilename);
switch (Type)
switch (mediaType)
{
case MediaType.CDROM:
return [
@@ -518,13 +590,10 @@ namespace MPF.Processors
| OutputFileFlags.Zippable),
new($"{outputFilename}.img", OutputFileFlags.Required
| OutputFileFlags.Deleteable),
new([$"{outputFilename}.img_EdcEcc.txt", $"{outputFilename}.img_EccEdc.txt"], System.IsAudio()
? OutputFileFlags.Artifact | OutputFileFlags.Zippable
: OutputFileFlags.Required | OutputFileFlags.Artifact | OutputFileFlags.Zippable,
new([$"{outputFilename}.img_EdcEcc.txt", $"{outputFilename}.img_EccEdc.txt"], OutputFileFlags.Artifact
| OutputFileFlags.Zippable,
"img_edcecc"),
new([$"{outputFilename}.scm", $"{outputFilename}.scmtmp"], System.IsAudio()
? OutputFileFlags.Deleteable
: OutputFileFlags.Required | OutputFileFlags.Deleteable),
new([$"{outputFilename}.scm", $"{outputFilename}.scmtmp"], OutputFileFlags.Deleteable),
new([$"{outputFilename}.sub", $"{outputFilename}.subtmp"], OutputFileFlags.Required
| OutputFileFlags.Binary
| OutputFileFlags.Zippable,
@@ -2107,7 +2176,7 @@ namespace MPF.Processors
#endif
// Now that we're at the offsets, attempt to get the sample offset
return string.Join("; ", [.. offsets]);
return offsets.Count == 0 ? null : string.Join("; ", [.. offsets]);
}
catch
{

View File

@@ -1,5 +1,26 @@
namespace MPF.Processors
{
/// <summary>
/// Indicates the type of compression used for logs
/// </summary>
public enum LogCompression
{
/// <summary>
/// PKZIP using DEFLATE level 5
/// </summary>
DeflateDefault,
/// <summary>
/// PKZIP using DEFLATE level 9
/// </summary>
DeflateMaximum,
/// <summary>
/// PKZIP using Zstd level 19
/// </summary>
Zstd19,
}
/// <summary>
/// Enum for SecuROM scheme type
/// </summary>

View File

@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using SabreTools.Data.Models.Logiqx;
using SabreTools.Hashing;
using SabreTools.Models.Logiqx;
using SabreTools.RedumpLib;
using SabreTools.RedumpLib.Data;
@@ -14,12 +14,18 @@ namespace MPF.Processors
public sealed class Generic : BaseProcessor
{
/// <inheritdoc/>
public Generic(RedumpSystem? system, MediaType? type) : base(system, type) { }
public Generic(RedumpSystem? system) : base(system) { }
#region BaseProcessor Implementations
/// <inheritdoc/>
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, bool redumpCompat)
public override MediaType? DetermineMediaType(string? outputDirectory, string outputFilename)
{
throw new NotImplementedException();
}
/// <inheritdoc/>
public override void GenerateSubmissionInfo(SubmissionInfo info, MediaType? mediaType, string basePath, bool redumpCompat)
{
// Ensure that required sections exist
info = Builder.EnsureAllSections(info);
@@ -34,7 +40,7 @@ namespace MPF.Processors
info.TracksAndWriteOffsets!.ClrMameProData = ProcessingTool.GenerateDatfile(datafile);
// Extract info based generically on MediaType
switch (Type)
switch (mediaType)
{
case MediaType.CDROM:
case MediaType.GDROM:
@@ -62,7 +68,7 @@ namespace MPF.Processors
}
/// <inheritdoc/>
internal override List<OutputFile> GetOutputFiles(string? outputDirectory, string outputFilename)
internal override List<OutputFile> GetOutputFiles(MediaType? mediaType, string? outputDirectory, string outputFilename)
{
return [];
}

View File

@@ -12,7 +12,7 @@
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<VersionPrefix>3.3.2</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<WarningsNotAsErrors>NU5104</WarningsNotAsErrors>
<!-- Package Properties -->
@@ -33,13 +33,12 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.Hashing" Version="1.4.2" />
<PackageReference Include="SabreTools.Models" Version="1.5.8" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.6.7" />
<PackageReference Include="SabreTools.Serialization" Version="1.8.6" />
<PackageReference Include="System.IO.Compression" Version="4.3.0" Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`))" />
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net452`))" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.4" Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net452`))" />
<PackageReference Include="GrindCore.SharpCompress" Version="0.40.4-alpha" Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net452`))" />
<PackageReference Include="SabreTools.Hashing" Version="[1.5.1]" />
<PackageReference Include="SabreTools.IO" Version="[1.7.6]" />
<PackageReference Include="SabreTools.RedumpLib" Version="[1.7.4]" />
<PackageReference Include="SabreTools.Serialization" Version="[2.0.2]" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.9" Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net452`))" />
</ItemGroup>
</Project>

View File

@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using System.IO;
#if NET452_OR_GREATER || NETCOREAPP
using System.IO.Compression;
#if NET462_OR_GREATER || NETCOREAPP
using System.Linq;
using SharpCompress.Archives.Zip;
#endif
namespace MPF.Processors
@@ -218,7 +218,7 @@ namespace MPF.Processors
return false;
}
#if NET452_OR_GREATER || NETCOREAPP
#if NET462_OR_GREATER || NETCOREAPP
/// <summary>
/// Indicates if an output file exists in an archive
/// </summary>
@@ -238,7 +238,7 @@ namespace MPF.Processors
try
{
// Check all entries on filename alone
if (archive.Entries.Any(e => e.Name == filename))
if (archive.Entries.Any(e => e.Key == filename))
return true;
}
catch { }

View File

@@ -1,7 +1,6 @@
using System.Collections.Generic;
using System.IO;
using SabreTools.Hashing;
using SabreTools.Models.Logiqx;
using SabreTools.Data.Models.Logiqx;
using SabreTools.RedumpLib;
using SabreTools.RedumpLib.Data;
@@ -13,12 +12,16 @@ namespace MPF.Processors
public sealed class PS3CFW : BaseProcessor
{
/// <inheritdoc/>
public PS3CFW(RedumpSystem? system, MediaType? type) : base(system, type) { }
public PS3CFW(RedumpSystem? system) : base(system) { }
#region BaseProcessor Implementations
/// <inheritdoc/>
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, bool redumpCompat)
public override MediaType? DetermineMediaType(string? outputDirectory, string outputFilename)
=> MediaType.BluRay;
/// <inheritdoc/>
public override void GenerateSubmissionInfo(SubmissionInfo info, MediaType? mediaType, string basePath, bool redumpCompat)
{
// Ensure that required sections exist
info = Builder.EnsureAllSections(info);
@@ -34,9 +37,7 @@ namespace MPF.Processors
info.DumpingInfo!.DumpingDate = ProcessingTool.GetFileModifiedDate(isoPath)?.ToString("yyyy-MM-dd HH:mm:ss");
// Get the Datafile information
Datafile? datafile = GeneratePS3CFWDatafile(isoPath);
// Fill in the hash data
Datafile? datafile = GenerateDatafile(isoPath);
info.TracksAndWriteOffsets!.ClrMameProData = ProcessingTool.GenerateDatfile(datafile);
// Get the individual hash data, as per internal
@@ -76,22 +77,50 @@ namespace MPF.Processors
if (!string.IsNullOrEmpty(getKeyPath))
info.DumpingInfo.DumpingDate = ProcessingTool.GetFileModifiedDate(getKeyPath)?.ToString("yyyy-MM-dd HH:mm:ss");
// TODO: Put info about abnormal PIC info beyond 132 bytes in comments?
// Try to determine the name of the PIC
string? picPath = null;
if (File.Exists($"{basePath}.disc.pic"))
{
info.Extras!.PIC = GetPIC($"{basePath}.disc.pic", 264);
picPath = $"{basePath}.disc.pic";
}
else if (File.Exists(Path.Combine(baseDir, "disc.pic")))
{
info.Extras!.PIC = GetPIC(Path.Combine(baseDir, "disc.pic"), 264);
picPath = Path.Combine(baseDir, "disc.pic");
}
else
{
string[] discPicFiles = Directory.GetFiles(baseDir, "*.disc.pic");
if (discPicFiles.Length > 0)
info.Extras!.PIC = GetPIC(discPicFiles[0], 264);
picPath = discPicFiles[0];
}
// Get the layerbreak information from the PIC
var di = ProcessingTool.GetDiscInformation(picPath);
info.SizeAndChecksums!.PICIdentifier = ProcessingTool.GetPICIdentifier(di);
if (ProcessingTool.GetLayerbreaks(di, out long? layerbreak1, out long? layerbreak2, out long? layerbreak3))
{
if (layerbreak1 != null && layerbreak1 * 2048 < info.SizeAndChecksums.Size)
info.SizeAndChecksums.Layerbreak = layerbreak1.Value;
if (layerbreak2 != null && layerbreak2 * 2048 < info.SizeAndChecksums.Size)
info.SizeAndChecksums.Layerbreak2 = layerbreak2.Value;
if (layerbreak3 != null && layerbreak3 * 2048 < info.SizeAndChecksums.Size)
info.SizeAndChecksums.Layerbreak3 = layerbreak3.Value;
}
// Set the trim length based on the layer count
int trimLength;
if (info.SizeAndChecksums!.Layerbreak3 != default)
trimLength = 520;
else if (info.SizeAndChecksums!.Layerbreak2 != default)
trimLength = 392;
else
trimLength = 264;
// TODO: Put info about abnormal PIC info beyond 132 bytes in comments?
info.Extras!.PIC = GetPIC(picPath, trimLength);
// Parse Disc Key, Disc ID, and PIC from the getkey.log file
if (ProcessingTool.ParseGetKeyLog(getKeyPath, out string? key, out string? id, out string? pic))
{
@@ -105,64 +134,23 @@ namespace MPF.Processors
}
/// <inheritdoc/>
internal override List<OutputFile> GetOutputFiles(string? outputDirectory, string outputFilename)
internal override List<OutputFile> GetOutputFiles(MediaType? mediaType, string? outputDirectory, string outputFilename)
{
// Remove the extension by default
outputFilename = Path.GetFileNameWithoutExtension(outputFilename);
switch (Type)
{
case MediaType.BluRay:
return [
new([$"{outputFilename}.iso", $"{outputFilename}.ISO"], OutputFileFlags.Required),
new([$"{outputFilename}.cue", $"{outputFilename}.CUE"], OutputFileFlags.Zippable),
new RegexOutputFile($"getkey\\.log$", OutputFileFlags.Required
| OutputFileFlags.Artifact
| OutputFileFlags.Zippable,
"getkey_log"),
new RegexOutputFile($"disc\\.pic$", OutputFileFlags.Required
| OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"disc_pic"),
];
}
return [];
}
#endregion
#region Information Extraction Methods
/// <summary>
/// Get a formatted datfile from the PS3 CFW output, if possible
/// </summary>
/// <param name="iso">Path to ISO file</param>
/// <returns></returns>
internal static Datafile? GeneratePS3CFWDatafile(string iso)
{
// If the ISO file doesn't exist
if (string.IsNullOrEmpty(iso))
return null;
if (!File.Exists(iso))
return null;
try
{
if (HashTool.GetStandardHashes(iso, out long size, out string? crc, out string? md5, out string? sha1))
{
return new Datafile
{
Game = [new Game { Rom = [new Rom { Name = Path.GetFileName(iso), Size = size.ToString(), CRC = crc, MD5 = md5, SHA1 = sha1 }] }]
};
}
return null;
}
catch
{
// We don't care what the exception is right now
return null;
}
return [
new([$"{outputFilename}.iso", $"{outputFilename}.ISO"], OutputFileFlags.Required),
new([$"{outputFilename}.cue", $"{outputFilename}.CUE"], OutputFileFlags.Zippable),
new RegexOutputFile($"getkey\\.log$", OutputFileFlags.Required
| OutputFileFlags.Artifact
| OutputFileFlags.Zippable,
"getkey_log"),
new RegexOutputFile($"disc\\.pic$", OutputFileFlags.Required
| OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"disc_pic"),
];
}
#endregion

View File

@@ -10,9 +10,8 @@ using System.Xml.Schema;
using System.Xml.Serialization;
using SabreTools.Hashing;
using SabreTools.IO.Extensions;
using SabreTools.Matching;
using SabreTools.Models.Logiqx;
using SabreTools.Models.PIC;
using SabreTools.Data.Models.Logiqx;
using SabreTools.Data.Models.PIC;
using SabreTools.RedumpLib.Data;
namespace MPF.Processors
@@ -129,11 +128,11 @@ namespace MPF.Processors
/// <param name="pic">Path to a PIC.bin file</param>
/// <returns>Filled DiscInformation on success, null on error</returns>
/// <remarks>This omits the emergency brake information, if it exists</remarks>
public static DiscInformation? GetDiscInformation(string pic)
public static DiscInformation? GetDiscInformation(string? pic)
{
try
{
return SabreTools.Serialization.Deserializers.PIC.DeserializeFile(pic);
return new SabreTools.Serialization.Readers.PIC().Deserialize(pic);
}
catch
{
@@ -375,9 +374,9 @@ namespace MPF.Processors
{
return category?.ToLowerInvariant() switch
{
"game" => DiscCategory.Games,
"video" => DiscCategory.Video,
"audio" => DiscCategory.Audio,
"(game)" => DiscCategory.Games,
"(video)" => DiscCategory.Video,
"(audio)" => DiscCategory.Audio,
_ => null,
};
}
@@ -1074,7 +1073,7 @@ namespace MPF.Processors
// Only continue to check SSv2 for XGD3
if (xgdType != 3)
return true;
// Determine if XGD3 SS.bin is SSv1 (Original Kreon) or SSv2 (0800 / Repaired Kreon)
#if NET20
var checkArr = new byte[72];
@@ -1085,6 +1084,67 @@ namespace MPF.Processors
#endif
}
/// <summary>
/// Determine if a given SS.bin is valid but contains zeroed challenge responses
/// </summary>
/// <param name="ssPath">Path to the SS file to check</param>
/// <returns>True if valid but partial SS.bin, false otherwise</returns>
public static bool IsValidPartialSS(string ssPath)
{
if (!File.Exists(ssPath))
return false;
byte[] ss = File.ReadAllBytes(ssPath);
if (ss.Length != 2048)
return false;
return IsValidPartialSS(ss);
}
/// <summary>
/// Determine if a given SS is valid but contains zeroed challenge responses
/// </summary>
/// <param name="ss">Byte array of SS sector</param>
/// <returns>True if SS is a valid but partial SS, false otherwise</returns>
public static bool IsValidPartialSS(byte[] ss)
{
// Check 1 sector long
if (ss.Length != 2048)
return false;
// Must be a valid XGD type
if (!GetXGDType(ss, out int xgdType))
return false;
// Determine challenge table offset, XGD1 is never partial
int ccrt_offset = 0;
if (xgdType == 1)
return false;
else if (xgdType == 2)
ccrt_offset = 0x200;
else if (xgdType == 3)
ccrt_offset = 0x20;
int[] entry_offsets = { 0, 9, 18, 27, 36, 45, 54, 63 };
int[] entry_lengths = { 8, 8, 8, 8, 4, 4, 4, 4 };
for (int i = 0; i < entry_offsets.Length; i++)
{
bool emptyResponse = true;
for (int b = 0; b < entry_lengths[i]; b++)
{
if (ss[ccrt_offset + entry_offsets[i] + b] != 0x00)
{
emptyResponse = false;
break;
}
}
if (emptyResponse)
return true;
}
return false;
}
/// <summary>
/// Determine if a given SS has already been cleaned
/// </summary>
@@ -1228,7 +1288,7 @@ namespace MPF.Processors
// Determine XGD type
if (!GetXGDType(ss, out int xgdType))
return false;
// Determine if XGD3 SS.bin is SSv1 (Original Kreon) or SSv2 (0800 / Repaired Kreon)
#if NET20
var checkArr = new byte[72];
@@ -1239,7 +1299,7 @@ namespace MPF.Processors
#endif
// Do not produce an SS hash for bad SS (SSv1 XGD3 / Unrepaired Kreon SS)
if(xgdType == 3 && !ssv2)
if (xgdType == 3 && !ssv2)
return false;
switch (xgdType)

View File

@@ -1,14 +1,16 @@
using System;
using System.Collections.Generic;
using System.IO;
#if NET452_OR_GREATER || NETCOREAPP
using System.IO.Compression;
#endif
using System.Text;
using System.Text.RegularExpressions;
using SabreTools.Hashing;
using SabreTools.RedumpLib;
using SabreTools.RedumpLib.Data;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Archives.Zip;
using SharpCompress.Compressors;
using SharpCompress.Compressors.ZStandard;
#endif
namespace MPF.Processors
{
@@ -18,15 +20,40 @@ namespace MPF.Processors
public sealed class Redumper : BaseProcessor
{
/// <inheritdoc/>
public Redumper(RedumpSystem? system, MediaType? type) : base(system, type) { }
public Redumper(RedumpSystem? system) : base(system) { }
#region BaseProcessor Implementations
/// <inheritdoc/>
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, bool redumpCompat)
public override MediaType? DetermineMediaType(string? outputDirectory, string outputFilename)
{
// If the filename is invalid
if (string.IsNullOrEmpty(outputFilename))
return null;
// Reassemble the base path
string basePath = Path.GetFileNameWithoutExtension(outputFilename);
if (!string.IsNullOrEmpty(outputDirectory))
basePath = Path.Combine(outputDirectory, basePath);
// Use the log first, if it exists
if (GetDiscType($"{basePath}.log", out MediaType? mediaType))
return mediaType;
// Use the profile for older Redumper versions
if (GetDiscProfile($"{basePath}.log", out string? discProfile))
return GetDiscTypeFromProfile(discProfile);
// The type could not be determined
return null;
}
/// <inheritdoc/>
public override void GenerateSubmissionInfo(SubmissionInfo info, MediaType? mediaType, string basePath, bool redumpCompat)
{
// Ensure that required sections exist
info = Builder.EnsureAllSections(info);
info.CommonDiscInfo!.Comments = string.Empty;
// Get the dumping program and version
info.DumpingInfo!.DumpingProgram ??= string.Empty;
@@ -43,25 +70,47 @@ namespace MPF.Processors
}
// Fill in the disc type data
if (GetDiscType($"{basePath}.log", out var discTypeOrBookType))
if (GetDiscProfile($"{basePath}.log", out var discTypeOrBookType))
info.DumpingInfo.ReportedDiscType = discTypeOrBookType;
// Fill in the volume labels
if (GetVolumeLabels($"{basePath}.log", out var volLabels))
VolumeLabels = volLabels;
// Get the PVD, if it exists
info.Extras!.PVD = GetPVD($"{basePath}.log") ?? "Disc has no PVD";
string? sfsvd = GetSFSVD($"{basePath}.log");
if (!string.IsNullOrEmpty(sfsvd))
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.HighSierraVolumeDescriptor] = sfsvd!;
switch (Type)
// Get the Datafile information
info.TracksAndWriteOffsets!.ClrMameProData = GetDatfile($"{basePath}.log");
// Get the write offset, if it exists
string? writeOffset = GetWriteOffset($"{basePath}.log");
info.CommonDiscInfo.RingWriteOffset = writeOffset;
info.TracksAndWriteOffsets.OtherWriteOffsets = writeOffset;
// Attempt to get multisession data
string? multiSessionInfo = GetMultisessionInformation($"{basePath}.log");
if (!string.IsNullOrEmpty(multiSessionInfo))
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.Multisession] = multiSessionInfo!;
// Fill in the volume labels (ignore for Xbox/Xbox360)
if (System != RedumpSystem.MicrosoftXbox && System != RedumpSystem.MicrosoftXbox360)
{
if (GetVolumeLabels($"{basePath}.log", out var volLabels))
VolumeLabels = volLabels;
}
// Pre-compress the skeleton and state using Zstandard
if (File.Exists($"{basePath}.skeleton"))
_ = CompressZstandard($"{basePath}.skeleton");
if (File.Exists($"{basePath}.state"))
_ = CompressZstandard($"{basePath}.state");
// Extract info based generically on MediaType
switch (mediaType)
{
case MediaType.CDROM:
info.Extras!.PVD = GetPVD($"{basePath}.log") ?? "Disc has no PVD";
info.TracksAndWriteOffsets!.ClrMameProData = GetDatfile($"{basePath}.log");
info.TracksAndWriteOffsets.Cuesheet = ProcessingTool.GetFullFile($"{basePath}.cue") ?? string.Empty;
// Attempt to get the write offset
string cdWriteOffset = GetWriteOffset($"{basePath}.log") ?? string.Empty;
info.CommonDiscInfo!.RingWriteOffset = cdWriteOffset;
info.TracksAndWriteOffsets.OtherWriteOffsets = cdWriteOffset;
// Attempt to get the error count
if (GetErrorCount($"{basePath}.log", out long redumpErrors, out long c2Errors))
{
@@ -69,11 +118,6 @@ namespace MPF.Processors
info.DumpingInfo.C2ErrorsCount = (c2Errors == -1 ? "Error retrieving error count" : c2Errors.ToString());
}
// Attempt to get multisession data
string? cdMultiSessionInfo = GetMultisessionInformation($"{basePath}.log");
if (!string.IsNullOrEmpty(cdMultiSessionInfo))
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.Multisession] = cdMultiSessionInfo!;
// Attempt to get extra metadata if it's an audio disc
if (IsAudio(info.TracksAndWriteOffsets.Cuesheet))
{
@@ -95,9 +139,6 @@ namespace MPF.Processors
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
case MediaType.NintendoWiiUOpticalDisc:
info.Extras!.PVD = GetPVD($"{basePath}.log") ?? "Disc has no PVD";
info.TracksAndWriteOffsets!.ClrMameProData = GetDatfile($"{basePath}.log");
// Get the individual hash data, as per internal
if (ProcessingTool.GetISOHashValues(info.TracksAndWriteOffsets.ClrMameProData, out long size, out var crc32, out var md5, out var sha1))
{
@@ -117,10 +158,10 @@ namespace MPF.Processors
// Attempt to get the error count
long scsiErrors = GetSCSIErrorCount($"{basePath}.log");
info.CommonDiscInfo!.ErrorsCount = (scsiErrors == -1 ? "Error retrieving error count" : scsiErrors.ToString());
info.CommonDiscInfo.ErrorsCount = (scsiErrors == -1 ? "Error retrieving error count" : scsiErrors.ToString());
// Bluray-specific options
if (Type == MediaType.BluRay || Type == MediaType.NintendoWiiUOpticalDisc)
if (mediaType == MediaType.BluRay || mediaType == MediaType.NintendoWiiUOpticalDisc)
{
int trimLength = -1;
switch (System)
@@ -163,7 +204,7 @@ namespace MPF.Processors
case RedumpSystem.SonyElectronicBook:
info.CopyProtection!.SecuROMData = GetSecuROMData($"{basePath}.log", out SecuROMScheme secuROMScheme) ?? string.Empty;
if (secuROMScheme == SecuROMScheme.Unknown)
info.CommonDiscInfo!.Comments = "Warning: Incorrect SecuROM sector count" + Environment.NewLine;
info.CommonDiscInfo.Comments += $"Warning: Incorrect SecuROM sector count{Environment.NewLine}";
// Needed for some odd copy protections
info.CopyProtection!.Protection += GetDVDProtection($"{basePath}.log", false) ?? string.Empty;
@@ -177,7 +218,7 @@ namespace MPF.Processors
case RedumpSystem.KonamiPython2:
if (GetPlayStationInfo($"{basePath}.log", out string? kp2EXEDate, out string? kp2Serial, out string? kp2Version))
{
info.CommonDiscInfo!.EXEDateBuildDate = kp2EXEDate;
info.CommonDiscInfo.EXEDateBuildDate = kp2EXEDate;
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = kp2Serial ?? string.Empty;
info.VersionAndEditions!.Version = kp2Version ?? string.Empty;
}
@@ -185,46 +226,6 @@ namespace MPF.Processors
break;
case RedumpSystem.MicrosoftXbox:
// If .dmi / .pfi / .ss don't already exist, create them
if (!File.Exists($"{basePath}.dmi"))
RemoveHeaderAndTrim($"{basePath}.manufacturer", $"{basePath}.dmi");
if (!File.Exists($"{basePath}.pfi"))
RemoveHeaderAndTrim($"{basePath}.physical", $"{basePath}.pfi");
if (!File.Exists($"{basePath}.ss"))
ProcessingTool.CleanSS($"{basePath}.security", $"{basePath}.ss");
string xmidString = ProcessingTool.GetXMID($"{basePath}.dmi");
var xmid = SabreTools.Serialization.Wrappers.XMID.Create(xmidString);
if (xmid != null)
{
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.XMID] = xmidString?.TrimEnd('\0') ?? string.Empty;
info.CommonDiscInfo.Serial = xmid.Serial ?? string.Empty;
if (!redumpCompat)
{
info.VersionAndEditions!.Version = xmid.Version ?? string.Empty;
info.CommonDiscInfo.Region = ProcessingTool.GetXGDRegion(xmid.Model.RegionIdentifier);
}
}
string? dmi1Crc = HashTool.GetFileHash($"{basePath}.dmi", HashType.CRC32);
if (dmi1Crc != null)
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.DMIHash] = dmi1Crc.ToUpperInvariant();
string? pfi1Crc = HashTool.GetFileHash($"{basePath}.pfi", HashType.CRC32);
if (pfi1Crc != null)
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.PFIHash] = pfi1Crc.ToUpperInvariant();
if (ProcessingTool.IsValidSS($"{basePath}.ss"))
{
string? ss1Crc = HashTool.GetFileHash($"{basePath}.ss", HashType.CRC32);
if (ss1Crc != null)
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.SSHash] = ss1Crc.ToUpperInvariant();
}
string? ranges1 = ProcessingTool.GetSSRanges($"{basePath}.ss");
if (!string.IsNullOrEmpty(ranges1))
info.Extras!.SecuritySectorRanges = ranges1;
break;
case RedumpSystem.MicrosoftXbox360:
// If .dmi / .pfi / .ss don't already exist, create them
if (!File.Exists($"{basePath}.dmi"))
@@ -234,46 +235,60 @@ namespace MPF.Processors
if (!File.Exists($"{basePath}.ss"))
ProcessingTool.CleanSS($"{basePath}.security", $"{basePath}.ss");
string xemidString = ProcessingTool.GetXeMID($"{basePath}.dmi");
var xemid = SabreTools.Serialization.Wrappers.XeMID.Create(xemidString);
if (xemid != null)
string xmidString = ProcessingTool.GetXMID($"{basePath}.dmi").Trim('\0');
if (!string.IsNullOrEmpty(xmidString))
{
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.XeMID] = xemidString?.TrimEnd('\0') ?? string.Empty;
info.CommonDiscInfo.Serial = xemid.Serial ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.XMID] = xmidString;
var xmid = SabreTools.Serialization.Wrappers.XMID.Create(xmidString);
info.CommonDiscInfo.Serial = xmid?.Serial ?? string.Empty;
if (!redumpCompat)
info.VersionAndEditions!.Version = xemid.Version ?? string.Empty;
info.CommonDiscInfo.Region = ProcessingTool.GetXGDRegion(xemid.Model.RegionIdentifier);
{
info.VersionAndEditions!.Version = xmid?.Version ?? string.Empty;
info.CommonDiscInfo.Region = ProcessingTool.GetXGDRegion(xmid?.Model.RegionIdentifier);
}
}
string? dmi23Crc = HashTool.GetFileHash($"{basePath}.dmi", HashType.CRC32);
if (dmi23Crc != null)
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.DMIHash] = dmi23Crc.ToUpperInvariant();
string? pfi23Crc = HashTool.GetFileHash($"{basePath}.pfi", HashType.CRC32);
if (pfi23Crc != null)
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.PFIHash] = pfi23Crc.ToUpperInvariant();
if (ProcessingTool.IsValidSS($"{basePath}.ss"))
string xemidString = ProcessingTool.GetXeMID($"{basePath}.dmi").Trim('\0');
if (!string.IsNullOrEmpty(xemidString))
{
string? ss23Crc = HashTool.GetFileHash($"{basePath}.ss", HashType.CRC32);
if (ss23Crc != null)
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.SSHash] = ss23Crc.ToUpperInvariant();
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.XeMID] = xemidString;
var xemid = SabreTools.Serialization.Wrappers.XeMID.Create(xemidString);
info.CommonDiscInfo.Serial = xemid?.Serial ?? string.Empty;
if (!redumpCompat)
{
info.VersionAndEditions!.Version = xemid?.Version ?? string.Empty;
info.CommonDiscInfo.Region = ProcessingTool.GetXGDRegion(xemid?.Model.RegionIdentifier);
}
}
string? ranges23 = ProcessingTool.GetSSRanges($"{basePath}.ss");
if (!string.IsNullOrEmpty(ranges23))
info.Extras!.SecuritySectorRanges = ranges23;
string? dmiCrc = HashTool.GetFileHash($"{basePath}.dmi", HashType.CRC32);
if (dmiCrc != null)
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.DMIHash] = dmiCrc.ToUpperInvariant();
string? pfiCrc = HashTool.GetFileHash($"{basePath}.pfi", HashType.CRC32);
if (pfiCrc != null)
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.PFIHash] = pfiCrc.ToUpperInvariant();
if (ProcessingTool.IsValidSS($"{basePath}.ss") && !ProcessingTool.IsValidPartialSS($"{basePath}.ss"))
{
string? ssCrc = HashTool.GetFileHash($"{basePath}.ss", HashType.CRC32);
if (ssCrc != null)
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.SSHash] = ssCrc.ToUpperInvariant();
}
string? ssRanges = ProcessingTool.GetSSRanges($"{basePath}.ss");
if (!string.IsNullOrEmpty(ssRanges))
info.Extras!.SecuritySectorRanges = ssRanges;
break;
case RedumpSystem.NamcoSegaNintendoTriforce:
if (Type == MediaType.CDROM)
if (mediaType == MediaType.CDROM)
{
info.Extras!.Header = GetGDROMHeader($"{basePath}.log",
out string? buildDate,
out string? serial,
out _,
out string? version) ?? string.Empty;
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = serial ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = serial ?? string.Empty;
info.CommonDiscInfo.EXEDateBuildDate = buildDate ?? string.Empty;
// TODO: Support region setting from parsed value
info.VersionAndEditions!.Version = version ?? string.Empty;
@@ -282,20 +297,20 @@ namespace MPF.Processors
case RedumpSystem.SegaMegaCDSegaCD:
info.Extras!.Header = GetSegaCDHeader($"{basePath}.log", out var scdBuildDate, out var scdSerial, out _) ?? string.Empty;
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = scdSerial ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = scdSerial ?? string.Empty;
info.CommonDiscInfo.EXEDateBuildDate = scdBuildDate ?? string.Empty;
// TODO: Support region setting from parsed value
break;
case RedumpSystem.SegaChihiro:
if (Type == MediaType.CDROM)
if (mediaType == MediaType.CDROM)
{
info.Extras!.Header = GetGDROMHeader($"{basePath}.log",
out string? buildDate,
out string? serial,
out _,
out string? version) ?? string.Empty;
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = serial ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = serial ?? string.Empty;
info.CommonDiscInfo.EXEDateBuildDate = buildDate ?? string.Empty;
// TODO: Support region setting from parsed value
info.VersionAndEditions!.Version = version ?? string.Empty;
@@ -303,14 +318,14 @@ namespace MPF.Processors
break;
case RedumpSystem.SegaDreamcast:
if (Type == MediaType.CDROM)
if (mediaType == MediaType.CDROM)
{
info.Extras!.Header = GetGDROMHeader($"{basePath}.log",
out string? buildDate,
out string? serial,
out _,
out string? version) ?? string.Empty;
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = serial ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = serial ?? string.Empty;
info.CommonDiscInfo.EXEDateBuildDate = buildDate ?? string.Empty;
// TODO: Support region setting from parsed value
info.VersionAndEditions!.Version = version ?? string.Empty;
@@ -318,14 +333,14 @@ namespace MPF.Processors
break;
case RedumpSystem.SegaNaomi:
if (Type == MediaType.CDROM)
if (mediaType == MediaType.CDROM)
{
info.Extras!.Header = GetGDROMHeader($"{basePath}.log",
out string? buildDate,
out string? serial,
out _,
out string? version) ?? string.Empty;
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = serial ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = serial ?? string.Empty;
info.CommonDiscInfo.EXEDateBuildDate = buildDate ?? string.Empty;
// TODO: Support region setting from parsed value
info.VersionAndEditions!.Version = version ?? string.Empty;
@@ -333,14 +348,14 @@ namespace MPF.Processors
break;
case RedumpSystem.SegaNaomi2:
if (Type == MediaType.CDROM)
if (mediaType == MediaType.CDROM)
{
info.Extras!.Header = GetGDROMHeader($"{basePath}.log",
out string? buildDate,
out string? serial,
out _,
out string? version) ?? string.Empty;
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = serial ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = serial ?? string.Empty;
info.CommonDiscInfo.EXEDateBuildDate = buildDate ?? string.Empty;
// TODO: Support region setting from parsed value
info.VersionAndEditions!.Version = version ?? string.Empty;
@@ -353,7 +368,7 @@ namespace MPF.Processors
out string? saturnSerial,
out _,
out string? saturnVersion) ?? string.Empty;
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = saturnSerial ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = saturnSerial ?? string.Empty;
info.CommonDiscInfo.EXEDateBuildDate = saturnBuildDate ?? string.Empty;
// TODO: Support region setting from parsed value
info.VersionAndEditions!.Version = saturnVersion ?? string.Empty;
@@ -362,7 +377,7 @@ namespace MPF.Processors
case RedumpSystem.SonyPlayStation:
if (GetPlayStationInfo($"{basePath}.log", out string? psxEXEDate, out string? psxSerial, out var _))
{
info.CommonDiscInfo!.EXEDateBuildDate = psxEXEDate;
info.CommonDiscInfo.EXEDateBuildDate = psxEXEDate;
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = psxSerial ?? string.Empty;
}
@@ -375,21 +390,21 @@ namespace MPF.Processors
case RedumpSystem.SonyPlayStation2:
if (GetPlayStationInfo($"{basePath}.log", out string? ps2EXEDate, out string? ps2Serial, out var ps2Version))
{
info.CommonDiscInfo!.EXEDateBuildDate = ps2EXEDate;
info.CommonDiscInfo.EXEDateBuildDate = ps2EXEDate;
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = ps2Serial ?? string.Empty;
info.VersionAndEditions!.Version = ps2Version ?? string.Empty;
}
string? ps2Protection = GetPlayStation2Protection($"{basePath}.log");
if (ps2Protection != null)
info.CommonDiscInfo!.Comments = $"<b>Protection</b>: {ps2Protection}" + Environment.NewLine;
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.Protection] = ps2Protection;
break;
case RedumpSystem.SonyPlayStation3:
if (GetPlayStationInfo($"{basePath}.log", out var _, out string? ps3Serial, out var ps3Version))
{
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = ps3Serial ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = ps3Serial ?? string.Empty;
info.VersionAndEditions!.Version = ps3Version ?? string.Empty;
}
@@ -398,7 +413,7 @@ namespace MPF.Processors
case RedumpSystem.SonyPlayStation4:
if (GetPlayStationInfo($"{basePath}.log", out var _, out string? ps4Serial, out var ps4Version))
{
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = ps4Serial ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = ps4Serial ?? string.Empty;
info.VersionAndEditions!.Version = ps4Version ?? string.Empty;
}
@@ -407,7 +422,7 @@ namespace MPF.Processors
case RedumpSystem.SonyPlayStation5:
if (GetPlayStationInfo($"{basePath}.log", out var _, out string? ps5Serial, out var ps5Version))
{
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = ps5Serial ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = ps5Serial ?? string.Empty;
info.VersionAndEditions!.Version = ps5Version ?? string.Empty;
}
@@ -416,19 +431,17 @@ namespace MPF.Processors
}
/// <inheritdoc/>
internal override List<OutputFile> GetOutputFiles(string? outputDirectory, string outputFilename)
internal override List<OutputFile> GetOutputFiles(MediaType? mediaType, string? outputDirectory, string outputFilename)
{
// Remove the extension by default
outputFilename = Path.GetFileNameWithoutExtension(outputFilename);
// Get the base path
string basePath;
if (string.IsNullOrEmpty(outputDirectory))
basePath = outputFilename;
else
basePath = Path.Combine(outputDirectory, outputFilename);
// Assemble the base path
string basePath = Path.GetFileNameWithoutExtension(outputFilename);
if (!string.IsNullOrEmpty(outputDirectory))
basePath = Path.Combine(outputDirectory, basePath);
switch (Type)
switch (mediaType)
{
case MediaType.CDROM:
case MediaType.GDROM:
@@ -440,9 +453,12 @@ namespace MPF.Processors
new($"{outputFilename}.atip", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"atip"),
new($"{outputFilename}.cache", OutputFileFlags.Binary
new([$"{outputFilename}.cache", $"{outputFilename}.1.cache"], OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"cache"),
new($"{outputFilename}.2.cache", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"cache_2"),
new($"{outputFilename}.cdtext", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"cdtext"),
@@ -463,10 +479,13 @@ namespace MPF.Processors
"pma"),
new([$"{outputFilename}.scram", $"{outputFilename}.scrap"], OutputFileFlags.Required
| OutputFileFlags.Deleteable),
new($"{outputFilename}.state", OutputFileFlags.Required
| OutputFileFlags.Binary
// TODO: Required if Zstandard version doesn't exist
new($"{outputFilename}.state", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"state"),
new($"{outputFilename}.state.zst", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"state_zst"),
new($"{outputFilename}.subcode", OutputFileFlags.Required
| OutputFileFlags.Binary
| OutputFileFlags.Zippable,
@@ -507,6 +526,9 @@ namespace MPF.Processors
cdrom.Add(new($"{trackName}.skeleton", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
$"skeleton_{trackNumber}"));
cdrom.Add(new($"{trackName}.skeleton.zst", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
$"skeleton_zst_{trackNumber}"));
trackNumber++;
}
}
@@ -518,6 +540,9 @@ namespace MPF.Processors
cdrom.Add(new($"{outputFilename}.skeleton", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"skeleton"));
cdrom.Add(new($"{outputFilename}.skeleton.zst", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"skeleton_zst"));
}
return cdrom;
@@ -526,13 +551,6 @@ namespace MPF.Processors
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
return [
// .asus is obsolete: newer redumper produces .cache instead
new($"{outputFilename}.asus", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"asus"),
new($"{outputFilename}.cache", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"cache"),
new($"{outputFilename}.dmi", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"dmi"),
@@ -569,19 +587,26 @@ namespace MPF.Processors
new($"{outputFilename}.skeleton", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"skeleton"),
new($"{outputFilename}.skeleton.zst", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"skeleton_zst"),
new($"{outputFilename}.ss", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"ss"),
// ssv1 and ssv2 extensions are obsolete
new($"{outputFilename}.ssv1", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"ssv1"),
new($"{outputFilename}.ssv2", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"ssv2"),
new($"{outputFilename}.state", OutputFileFlags.Required
| OutputFileFlags.Binary
// TODO: Required if Zstandard version doesn't exist
new($"{outputFilename}.state", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"state"),
new($"{outputFilename}.state.zst", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"state_zst"),
];
case MediaType.HDDVD: // TODO: Confirm that this information outputs
@@ -616,10 +641,16 @@ namespace MPF.Processors
new($"{outputFilename}.skeleton", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"skeleton"),
new($"{outputFilename}.state", OutputFileFlags.Required
| OutputFileFlags.Binary
new($"{outputFilename}.skeleton.zst", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"skeleton_zst"),
// TODO: Required if Zstandard version doesn't exist
new($"{outputFilename}.state", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"state"),
new($"{outputFilename}.state.zst", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"state_zst"),
];
}
@@ -630,6 +661,57 @@ namespace MPF.Processors
#region Private Extra Methods
/// <summary>
/// Attempt to compress a file to Zstandard, removing the original on success
/// </summary>
/// <param name="file">Full path to an existing file</param>
/// <returns>True if the compression was a success, false otherwise</returns>
private static bool CompressZstandard(string file)
{
#if NET20 || NET35 || NET40 || NET452
// Compression is not available for this framework version
return false;
#else
// Ensure the file exists
if (!File.Exists(file))
return false;
try
{
// Prepare the input and output streams
using var ifs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using var ofs = File.Open($"{file}.zst", FileMode.Create, FileAccess.Write, FileShare.None);
using var zst = new ZStandardStream(ofs, CompressionMode.Compress, compressionLevel: 19, leaveOpen: true);
// Compress and write in blocks
int read = 0;
do
{
byte[] buffer = new byte[3 * 1024 * 1024];
read = ifs.Read(buffer, 0, buffer.Length);
if (read == 0)
break;
zst.Write(buffer, 0, read);
zst.Flush();
} while (read > 0);
}
catch
{
// Try to delete the incomplete
try { File.Delete($"{file}.zst"); } catch { }
return false;
}
// Try to delete the file
try { File.Delete(file); } catch { }
return true;
#endif
}
/// <summary>
/// Get if the datfile exists in the log
/// </summary>
@@ -647,7 +729,7 @@ namespace MPF.Processors
if (!string.IsNullOrEmpty(outputDirectory))
basePath = Path.Combine(outputDirectory, basePath);
#if NET20 || NET35 || NET40
#if NET20 || NET35 || NET40 || NET452
// Assume the zipfile has the file in it
return File.Exists($"{basePath}_logs.zip");
#else
@@ -658,14 +740,23 @@ namespace MPF.Processors
try
{
// Try to open the archive
using ZipArchive archive = ZipFile.OpenRead($"{basePath}_logs.zip");
using ZipArchive archive = ZipArchive.Open($"{basePath}_logs.zip");
// Get the log entry and check it, if possible
var entry = archive.GetEntry(outputFilename);
if (entry == null)
ZipArchiveEntry? logEntry = null;
foreach (var entry in archive.Entries)
{
if (entry.Key == outputFilename)
{
logEntry = entry;
break;
}
}
if (logEntry == null)
return false;
using var sr = new StreamReader(entry.Open());
using var sr = new StreamReader(logEntry.OpenEntryStream());
return GetDatfile(sr) != null;
}
catch
@@ -865,14 +956,14 @@ namespace MPF.Processors
}
/// <summary>
/// Get reported disc type information, if possible
/// Get reported disc profile information, if possible
/// </summary>
/// <param name="log">Log file location</param>
/// <returns>True if disc type info was set, false otherwise</returns>
internal static bool GetDiscType(string log, out string? discTypeOrBookType)
/// <returns>True if disc profile information was set, false otherwise</returns>
internal static bool GetDiscProfile(string log, out string? discProfile)
{
// Set the default values
discTypeOrBookType = null;
discProfile = null;
// If the file doesn't exist, we can't get the info
if (string.IsNullOrEmpty(log))
@@ -893,7 +984,7 @@ namespace MPF.Processors
if (line.StartsWith("current profile:"))
{
// current profile: <discType>
discTypeOrBookType = line.Substring("current profile: ".Length);
discProfile = line.Substring("current profile: ".Length);
}
line = sr.ReadLine();
@@ -904,11 +995,121 @@ namespace MPF.Processors
catch
{
// We don't care what the exception is right now
discTypeOrBookType = null;
discProfile = null;
return false;
}
}
/// <summary>
/// Get reported disc type, if possible
/// </summary>
/// <param name="log">Log file location</param>
/// <returns>True if disc type was set, false otherwise</returns>
internal static bool GetDiscType(string log, out MediaType? discType)
{
// Set the default values
discType = null;
// If the file doesn't exist, we can't get the info
if (string.IsNullOrEmpty(log))
return false;
if (!File.Exists(log))
return false;
try
{
using var sr = File.OpenText(log);
var line = sr.ReadLine()?.TrimEnd();
while (line != null)
{
// If the line isn't the non-embedded disc type, skip
if (!line.StartsWith("disc type:"))
{
line = sr.ReadLine()?.TrimEnd();
continue;
}
// disc type: <discType>
string discTypeStr = line.Substring("disc type: ".Length);
// Set the media type based on the string
discType = discTypeStr switch
{
"CD" => MediaType.CDROM,
"DVD" => MediaType.DVD,
"BLURAY" => MediaType.BluRay,
"BLURAY-R" => MediaType.BluRay,
"HD-DVD" => MediaType.HDDVD,
_ => null,
};
return discType != null;
}
return false;
}
catch
{
// We don't care what the exception is right now
discType = null;
return false;
}
}
/// <summary>
/// Convert the profile to a media type, if possible
/// </summary>
/// <param name="profile">Profile string to check</param>
/// <returns>Media type on success, null otherwise</returns>
internal static MediaType? GetDiscTypeFromProfile(string? profile)
{
return profile switch
{
"reserved" => null,
"non removable disk" => null,
"removable disk" => null,
"MO erasable" => null,
"MO write once" => null,
"AS MO" => null,
"CD-ROM" => MediaType.CDROM,
"CD-R" => MediaType.CDROM,
"CD-RW" => MediaType.CDROM,
"DVD-ROM" => MediaType.DVD,
"DVD-R" => MediaType.DVD,
"DVD-RAM" => MediaType.DVD,
"DVD-RW RO" => MediaType.DVD,
"DVD-RW" => MediaType.DVD,
"DVD-R DL" => MediaType.DVD,
"DVD-R DL LJR" => MediaType.DVD,
"DVD+RW" => MediaType.DVD,
"DVD+R" => MediaType.DVD,
"DDCD-ROM" => MediaType.CDROM,
"DDCD-R" => MediaType.CDROM,
"DDCD-RW" => MediaType.CDROM,
"DVD+RW DL" => MediaType.DVD,
"DVD+R DL" => MediaType.DVD,
"BD-ROM" => MediaType.BluRay,
"BD-R" => MediaType.BluRay,
"BD-R RRM" => MediaType.BluRay,
"BD-RW" => MediaType.BluRay,
"HD DVD-ROM" => MediaType.HDDVD,
"HD DVD-R" => MediaType.HDDVD,
"HD DVD-RAM" => MediaType.HDDVD,
"HD DVD-RW" => MediaType.HDDVD,
"HD DVD-R DL" => MediaType.HDDVD,
"HD DVD-RW DL" => MediaType.HDDVD,
"NON STANDARD" => null,
_ => null,
};
}
/// <summary>
/// Get the DVD protection information, if possible
/// </summary>
@@ -1093,7 +1294,7 @@ namespace MPF.Processors
}
// Reset C2 errors when a media errors section is found
else if (line.StartsWith("media errors:"))
else if (line.StartsWith("media errors:") || line.StartsWith("initial dump media errors:"))
{
c2Errors = 0;
}
@@ -1689,6 +1890,44 @@ namespace MPF.Processors
}
}
/// <summary>
/// Get the SFSVD from the input file, if possible
/// </summary>
/// <param name="log">Log file location</param>
/// <returns>Newline-delimited SFSVD if possible, null on error</returns>
internal static string? GetSFSVD(string log)
{
// If the file doesn't exist, we can't get info from it
if (string.IsNullOrEmpty(log))
return null;
if (!File.Exists(log))
return null;
try
{
// Fast forward to the SFSVD line
using var sr = File.OpenText(log);
while (!sr.EndOfStream && sr.ReadLine()?.TrimStart()?.StartsWith("SFSVD:") == false) ;
if (sr.EndOfStream)
return null;
// Now that we're at the relevant entries, read each line in and concatenate
string? sfsvdString = string.Empty, line = sr.ReadLine();
while (line?.StartsWith("03") == true)
{
sfsvdString += line + "\n";
line = sr.ReadLine();
}
return sfsvdString.TrimEnd('\n');
}
catch
{
// We don't care what the exception is right now
return null;
}
}
/// <summary>
/// Get the non-zero data start from the input file, if possible
/// </summary>
@@ -2143,6 +2382,7 @@ namespace MPF.Processors
// redumper v2022.10.28 [Oct 28 2022, 05:41:43] (print usage: --help,-h)
// redumper v2022.12.22 build_87 [Dec 22 2022, 01:56:26]
// redumper v2025.03.29 build_481
// redumper (build: b652)
try
{
@@ -2156,10 +2396,7 @@ namespace MPF.Processors
nextLine = sr.ReadLine()?.Trim() ?? string.Empty;
// Generate regex
// Permissive
var regex = new Regex(@"^redumper (v.+)", RegexOptions.Compiled);
// Strict
//var regex = new Regex(@"^redumper (v\d{4}\.\d{2}\.\d{2}(| build_\d+)) \[.+\]", RegexOptions.Compiled);
var regex = new Regex(@"^redumper (.+)", RegexOptions.Compiled);
// Extract the version string
var match = regex.Match(nextLine);

View File

@@ -1,11 +1,10 @@
using System;
using System.Collections.Generic;
using System.IO;
#if NET452_OR_GREATER || NETCOREAPP
using System.IO.Compression;
using System.Linq;
#endif
using System.Text.RegularExpressions;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Archives.Zip;
#endif
namespace MPF.Processors
{
@@ -52,7 +51,7 @@ namespace MPF.Processors
// Ensure the directory exists
if (!Directory.Exists(outputDirectory))
return false;
// Get list of all files in directory
var directoryFiles = Directory.GetFiles(outputDirectory);
foreach (string file in directoryFiles)
@@ -64,7 +63,7 @@ namespace MPF.Processors
return false;
}
#if NET452_OR_GREATER || NETCOREAPP
#if NET462_OR_GREATER || NETCOREAPP
/// <inheritdoc/>
public override bool Exists(ZipArchive? archive)
{
@@ -73,10 +72,12 @@ namespace MPF.Processors
return false;
// Get list of all files in archive
var archiveFiles = archive.Entries.Select(e => e.Name).ToList();
foreach (string file in archiveFiles)
foreach (var entry in archive.Entries)
{
if (Array.Exists(Filenames, pattern => Regex.IsMatch(file, pattern)))
if (entry.Key == null)
continue;
if (Array.Exists(Filenames, pattern => Regex.IsMatch(entry.Key, pattern)))
return true;
}
@@ -92,7 +93,7 @@ namespace MPF.Processors
return [];
List<string> paths = [];
// Get list of all files in directory
var directoryFiles = Directory.GetFiles(outputDirectory);
foreach (string file in directoryFiles)

View File

@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using SabreTools.Data.Models.Logiqx;
using SabreTools.Hashing;
using SabreTools.Models.Logiqx;
using SabreTools.RedumpLib;
using SabreTools.RedumpLib.Data;
@@ -14,106 +14,100 @@ namespace MPF.Processors
public sealed class UmdImageCreator : BaseProcessor
{
/// <inheritdoc/>
public UmdImageCreator(RedumpSystem? system, MediaType? type) : base(system, type) { }
public UmdImageCreator(RedumpSystem? system) : base(system) { }
#region BaseProcessor Implementations
/// <inheritdoc/>
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, bool redumpCompat)
public override MediaType? DetermineMediaType(string? outputDirectory, string outputFilename)
=> MediaType.UMD;
/// <inheritdoc/>
public override void GenerateSubmissionInfo(SubmissionInfo info, MediaType? mediaType, string basePath, bool redumpCompat)
{
// Ensure that required sections exist
info = Builder.EnsureAllSections(info);
// TODO: Determine if there's a UMDImageCreator version anywhere
info.DumpingInfo!.DumpingDate = ProcessingTool.GetFileModifiedDate(basePath + "_disc.txt")?.ToString("yyyy-MM-dd HH:mm:ss");
info.DumpingInfo!.DumpingDate = ProcessingTool.GetFileModifiedDate($"{basePath}_disc.txt")?.ToString("yyyy-MM-dd HH:mm:ss");
// Get the PVD, if it exists
info.Extras!.PVD = GetPVD($"{basePath}_mainInfo.txt") ?? string.Empty;
// Get the Datafile information
if (HashTool.GetStandardHashes($"{basePath}.iso", out long filesize, out var crc32, out var md5, out var sha1))
{
// Create a Datafile from the hashes
var datafile = new Datafile
{
Game = [new Game { Rom = [new Rom { Name = string.Empty, Size = filesize.ToString(), CRC = crc32, MD5 = md5, SHA1 = sha1 }] }]
};
// Fill in the hash data
info.TracksAndWriteOffsets!.ClrMameProData = ProcessingTool.GenerateDatfile(datafile);
info.SizeAndChecksums!.Size = filesize;
info.SizeAndChecksums.CRC32 = crc32;
info.SizeAndChecksums.MD5 = md5;
info.SizeAndChecksums.SHA1 = sha1;
}
// Get internal information
if (GetUMDAuxInfo($"{basePath}_disc.txt",
out var title,
out DiscCategory? category,
out string? serial,
out var version,
out var layer,
out long size))
{
info.CommonDiscInfo!.Title = title ?? string.Empty;
info.CommonDiscInfo.Category = category ?? DiscCategory.Games;
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = serial ?? string.Empty;
info.VersionAndEditions!.Version = version ?? string.Empty;
info.SizeAndChecksums!.Size = size;
if (!string.IsNullOrEmpty(layer))
info.SizeAndChecksums.Layerbreak = long.Parse(layer ?? "-1");
}
// Fill in the volume labels
if (GetVolumeLabels($"{basePath}_volDesc.txt", out var volLabels))
VolumeLabels = volLabels;
// Extract info based generically on MediaType
switch (Type)
{
case MediaType.UMD:
info.Extras!.PVD = GetPVD(basePath + "_mainInfo.txt") ?? string.Empty;
if (HashTool.GetStandardHashes(basePath + ".iso", out long filesize, out var crc32, out var md5, out var sha1))
{
// Get the Datafile information
var datafile = new Datafile
{
Game = [new Game { Rom = [new Rom { Name = string.Empty, Size = filesize.ToString(), CRC = crc32, MD5 = md5, SHA1 = sha1 }] }]
};
// Fill in the hash data
info.TracksAndWriteOffsets!.ClrMameProData = ProcessingTool.GenerateDatfile(datafile);
info.SizeAndChecksums!.Size = filesize;
info.SizeAndChecksums.CRC32 = crc32;
info.SizeAndChecksums.MD5 = md5;
info.SizeAndChecksums.SHA1 = sha1;
}
if (GetUMDAuxInfo(basePath + "_disc.txt",
out var title,
out DiscCategory? category,
out string? serial,
out var version,
out var layer,
out long size))
{
info.CommonDiscInfo!.Title = title ?? string.Empty;
info.CommonDiscInfo.Category = category ?? DiscCategory.Games;
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = serial ?? string.Empty;
info.VersionAndEditions!.Version = version ?? string.Empty;
info.SizeAndChecksums!.Size = size;
if (!string.IsNullOrEmpty(layer))
info.SizeAndChecksums.Layerbreak = long.Parse(layer ?? "-1");
}
break;
}
}
/// <inheritdoc/>
internal override List<OutputFile> GetOutputFiles(string? outputDirectory, string outputFilename)
internal override List<OutputFile> GetOutputFiles(MediaType? mediaType, string? outputDirectory, string outputFilename)
{
// Remove the extension by default
outputFilename = Path.GetFileNameWithoutExtension(outputFilename);
switch (Type)
{
case MediaType.UMD:
return [
new($"{outputFilename}.iso", OutputFileFlags.Required),
return [
new($"{outputFilename}.iso", OutputFileFlags.Required),
new($"{outputFilename}_disc.txt", OutputFileFlags.Required
| OutputFileFlags.Artifact
| OutputFileFlags.Zippable,
"disc"),
new($"{outputFilename}_drive.txt", OutputFileFlags.Artifact
| OutputFileFlags.Zippable,
"drive"),
new($"{outputFilename}_mainError.txt", OutputFileFlags.Required
| OutputFileFlags.Artifact
| OutputFileFlags.Zippable,
"main_error"),
new($"{outputFilename}_mainInfo.txt", OutputFileFlags.Required
| OutputFileFlags.Artifact
| OutputFileFlags.Zippable,
"main_info"),
new($"{outputFilename}_PFI.bin", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"pfi"),
new($"{outputFilename}_volDesc.txt", OutputFileFlags.Required
| OutputFileFlags.Artifact
| OutputFileFlags.Zippable,
"vol_desc"),
];
}
return [];
new($"{outputFilename}_disc.txt", OutputFileFlags.Required
| OutputFileFlags.Artifact
| OutputFileFlags.Zippable,
"disc"),
new($"{outputFilename}_drive.txt", OutputFileFlags.Artifact
| OutputFileFlags.Zippable,
"drive"),
new($"{outputFilename}_mainError.txt", OutputFileFlags.Required
| OutputFileFlags.Artifact
| OutputFileFlags.Zippable,
"main_error"),
new($"{outputFilename}_mainInfo.txt", OutputFileFlags.Required
| OutputFileFlags.Artifact
| OutputFileFlags.Zippable,
"main_info"),
new($"{outputFilename}_PFI.bin", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"pfi"),
new($"{outputFilename}_volDesc.txt", OutputFileFlags.Required
| OutputFileFlags.Artifact
| OutputFileFlags.Zippable,
"vol_desc"),
];
}
#endregion
@@ -190,13 +184,13 @@ namespace MPF.Processors
break;
if (line.StartsWith("TITLE") && title == null)
title = line.Split(' ')[1];
title = line.Substring("TITLE: ".Length);
else if (line.StartsWith("DISC_ID") && version == null)
serial = line.Split(' ')[1];
else if (line.StartsWith("DISC_VERSION") && version == null)
version = line.Split(' ')[1];
else if (line.StartsWith("pspUmdTypes"))
category = ProcessingTool.GetUMDCategory(line.Split(' ')[1]);
category = ProcessingTool.GetUMDCategory(line.Split(' ')[2]);
else if (line.StartsWith("L0 length"))
layer = line.Split(' ')[2];
else if (line.StartsWith("FileSize:"))

View File

@@ -1,8 +1,8 @@
using System.Collections.Generic;
using System.IO;
using SabreTools.Data.Models.Logiqx;
using SabreTools.Hashing;
using SabreTools.IO.Extensions;
using SabreTools.Models.Logiqx;
using SabreTools.RedumpLib;
using SabreTools.RedumpLib.Data;
@@ -14,12 +14,16 @@ namespace MPF.Processors
public sealed class XboxBackupCreator : BaseProcessor
{
/// <inheritdoc/>
public XboxBackupCreator(RedumpSystem? system, MediaType? type) : base(system, type) { }
public XboxBackupCreator(RedumpSystem? system) : base(system) { }
#region BaseProcessor Implementations
/// <inheritdoc/>
public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, bool redumpCompat)
public override MediaType? DetermineMediaType(string? outputDirectory, string outputFilename)
=> MediaType.DVD;
/// <inheritdoc/>
public override void GenerateSubmissionInfo(SubmissionInfo info, MediaType? mediaType, string basePath, bool redumpCompat)
{
// Ensure that required sections exist
info = Builder.EnsureAllSections(info);
@@ -38,152 +42,131 @@ namespace MPF.Processors
info.DumpingInfo.DumpingDate = ProcessingTool.GetFileModifiedDate(logPath)?.ToString("yyyy-MM-dd HH:mm:ss");
info.DumpingInfo.Model = GetDrive(logPath) ?? "Unknown Drive";
// Get the Datafile information
Datafile? datafile = GenerateDatafile($"{basePath}.iso");
info.TracksAndWriteOffsets!.ClrMameProData = ProcessingTool.GenerateDatfile(datafile);
// Get the individual hash data, as per internal
if (ProcessingTool.GetISOHashValues(datafile, out long size, out var crc32, out var md5, out var sha1))
{
info.SizeAndChecksums!.Size = size;
info.SizeAndChecksums.CRC32 = crc32;
info.SizeAndChecksums.MD5 = md5;
info.SizeAndChecksums.SHA1 = sha1;
}
// Get Layerbreak from .dvd file if possible
if (GetLayerbreak($"{basePath}.dvd", out long layerbreak))
info.SizeAndChecksums!.Layerbreak = layerbreak;
// Look for read errors
if (GetReadErrors(logPath, out long readErrors))
info.CommonDiscInfo!.ErrorsCount = readErrors == -1 ? "Error retrieving error count" : readErrors.ToString();
// Extract info based generically on MediaType
switch (Type)
switch (System)
{
case MediaType.DVD:
// Get Layerbreak from .dvd file if possible
if (GetLayerbreak($"{basePath}.dvd", out long layerbreak))
info.SizeAndChecksums!.Layerbreak = layerbreak;
// Hash data
if (HashTool.GetStandardHashes(basePath + ".iso", out long filesize, out var crc32, out var md5, out var sha1))
case RedumpSystem.MicrosoftXbox:
string xmidString = ProcessingTool.GetXMID(Path.Combine(outputDirectory, "DMI.bin"));
var xmid = SabreTools.Serialization.Wrappers.XMID.Create(xmidString);
if (xmid != null)
{
// Get the Datafile information
var datafile = new Datafile
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.XMID] = xmidString?.TrimEnd('\0') ?? string.Empty;
info.CommonDiscInfo.Serial = xmid.Serial ?? string.Empty;
if (!redumpCompat)
{
Game = [new Game { Rom = [new Rom { Name = string.Empty, Size = filesize.ToString(), CRC = crc32, MD5 = md5, SHA1 = sha1 }] }]
};
// Fill in the hash data
info.TracksAndWriteOffsets!.ClrMameProData = ProcessingTool.GenerateDatfile(datafile);
info.SizeAndChecksums!.Size = filesize;
info.SizeAndChecksums.CRC32 = crc32;
info.SizeAndChecksums.MD5 = md5;
info.SizeAndChecksums.SHA1 = sha1;
info.VersionAndEditions!.Version = xmid.Version ?? string.Empty;
info.CommonDiscInfo.Region = ProcessingTool.GetXGDRegion(xmid.Model.RegionIdentifier);
}
}
switch (System)
break;
case RedumpSystem.MicrosoftXbox360:
// Get PVD from ISO
if (GetPVD($"{basePath}.iso", out string? pvd))
info.Extras!.PVD = pvd;
// Parse Media ID
//string? mediaID = GetMediaID(logPath);
// Parse DMI.bin
string xemidString = ProcessingTool.GetXeMID(Path.Combine(outputDirectory, "DMI.bin"));
var xemid = SabreTools.Serialization.Wrappers.XeMID.Create(xemidString);
if (xemid != null)
{
case RedumpSystem.MicrosoftXbox:
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.XeMID] = xemidString?.TrimEnd('\0') ?? string.Empty;
info.CommonDiscInfo.Serial = xemid.Serial ?? string.Empty;
if (!redumpCompat)
info.VersionAndEditions!.Version = xemid.Version ?? string.Empty;
// Parse DMI.bin
string xmidString = ProcessingTool.GetXMID(Path.Combine(outputDirectory, "DMI.bin"));
var xmid = SabreTools.Serialization.Wrappers.XMID.Create(xmidString);
if (xmid != null)
{
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.XMID] = xmidString?.TrimEnd('\0') ?? string.Empty;
info.CommonDiscInfo.Serial = xmid.Serial ?? string.Empty;
if (!redumpCompat)
{
info.VersionAndEditions!.Version = xmid.Version ?? string.Empty;
info.CommonDiscInfo.Region = ProcessingTool.GetXGDRegion(xmid.Model.RegionIdentifier);
}
}
break;
case RedumpSystem.MicrosoftXbox360:
// Get PVD from ISO
if (GetPVD(basePath + ".iso", out string? pvd))
info.Extras!.PVD = pvd;
// Parse Media ID
//string? mediaID = GetMediaID(logPath);
// Parse DMI.bin
string xemidString = ProcessingTool.GetXeMID(Path.Combine(outputDirectory, "DMI.bin"));
var xemid = SabreTools.Serialization.Wrappers.XeMID.Create(xemidString);
if (xemid != null)
{
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.XeMID] = xemidString?.TrimEnd('\0') ?? string.Empty;
info.CommonDiscInfo.Serial = xemid.Serial ?? string.Empty;
if (!redumpCompat)
info.VersionAndEditions!.Version = xemid.Version ?? string.Empty;
info.CommonDiscInfo.Region = ProcessingTool.GetXGDRegion(xemid.Model.RegionIdentifier);
}
break;
info.CommonDiscInfo.Region = ProcessingTool.GetXGDRegion(xemid.Model.RegionIdentifier);
}
// Get the output file paths
string dmiPath = Path.Combine(outputDirectory, "DMI.bin");
string pfiPath = Path.Combine(outputDirectory, "PFI.bin");
string ssPath = Path.Combine(outputDirectory, "SS.bin");
// Deal with SS.bin
if (File.Exists(ssPath))
{
// Save security sector ranges
string? ranges = ProcessingTool.GetSSRanges(ssPath);
if (!string.IsNullOrEmpty(ranges))
info.Extras!.SecuritySectorRanges = ranges;
// Recreate RawSS.bin
RecreateSS(logPath!, ssPath, Path.Combine(outputDirectory, "RawSS.bin"));
// Run ss_sector_range to get repeatable SS hash
ProcessingTool.CleanSS(ssPath, ssPath);
}
// DMI/PFI/SS CRC32 hashes
if (File.Exists(dmiPath))
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.DMIHash] = HashTool.GetFileHash(dmiPath, HashType.CRC32)?.ToUpperInvariant() ?? string.Empty;
if (File.Exists(pfiPath))
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.PFIHash] = HashTool.GetFileHash(pfiPath, HashType.CRC32)?.ToUpperInvariant() ?? string.Empty;
if (File.Exists(ssPath))
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.SSHash] = HashTool.GetFileHash(ssPath, HashType.CRC32)?.ToUpperInvariant() ?? string.Empty;
break;
}
// Get the output file paths
string dmiPath = Path.Combine(outputDirectory, "DMI.bin");
string pfiPath = Path.Combine(outputDirectory, "PFI.bin");
string ssPath = Path.Combine(outputDirectory, "SS.bin");
// Deal with SS.bin
if (File.Exists(ssPath))
{
// Save security sector ranges
string? ranges = ProcessingTool.GetSSRanges(ssPath);
if (!string.IsNullOrEmpty(ranges))
info.Extras!.SecuritySectorRanges = ranges;
// Recreate RawSS.bin
RecreateSS(logPath!, ssPath, Path.Combine(outputDirectory, "RawSS.bin"));
// Run ss_sector_range to get repeatable SS hash
ProcessingTool.CleanSS(ssPath, ssPath);
}
// DMI/PFI/SS CRC32 hashes
if (File.Exists(dmiPath))
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.DMIHash] = HashTool.GetFileHash(dmiPath, HashType.CRC32)?.ToUpperInvariant() ?? string.Empty;
if (File.Exists(pfiPath))
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.PFIHash] = HashTool.GetFileHash(pfiPath, HashType.CRC32)?.ToUpperInvariant() ?? string.Empty;
if (File.Exists(ssPath))
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.SSHash] = HashTool.GetFileHash(ssPath, HashType.CRC32)?.ToUpperInvariant() ?? string.Empty;
}
/// <inheritdoc/>
internal override List<OutputFile> GetOutputFiles(string? outputDirectory, string outputFilename)
internal override List<OutputFile> GetOutputFiles(MediaType? mediaType, string? outputDirectory, string outputFilename)
{
// Remove the extension by default
outputFilename = Path.GetFileNameWithoutExtension(outputFilename);
switch (Type)
{
case MediaType.DVD:
return [
new($"{outputFilename}.dvd", OutputFileFlags.Artifact
| OutputFileFlags.Zippable,
"dvd"),
new($"{outputFilename}.iso", OutputFileFlags.Required),
new("DMI.bin", OutputFileFlags.Required
| OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"dmi"),
new RegexOutputFile("[lL]og\\.txt", OutputFileFlags.Required
| OutputFileFlags.Artifact
| OutputFileFlags.Zippable,
"log"),
new("PFI.bin", OutputFileFlags.Required
| OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"pfi"),
new("RawSS.bin", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"raw_ss"),
new("SS.bin", OutputFileFlags.Required
| OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"ss"),
];
}
return [
new($"{outputFilename}.dvd", OutputFileFlags.Artifact
| OutputFileFlags.Zippable,
"dvd"),
new($"{outputFilename}.iso", OutputFileFlags.Required),
return [];
new("DMI.bin", OutputFileFlags.Required
| OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"dmi"),
new RegexOutputFile("[lL]og\\.txt", OutputFileFlags.Required
| OutputFileFlags.Artifact
| OutputFileFlags.Zippable,
"log"),
new("PFI.bin", OutputFileFlags.Required
| OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"pfi"),
new("RawSS.bin", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"raw_ss"),
new("SS.bin", OutputFileFlags.Required
| OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"ss"),
];
}
#endregion

View File

@@ -4,6 +4,7 @@ using System.Windows.Data;
using MPF.Frontend;
using MPF.Frontend.ComboBoxItems;
using SabreTools.RedumpLib.Data;
using LogCompression = MPF.Processors.LogCompression;
using RedumperDriveType = MPF.ExecutionContexts.Redumper.DriveType;
using RedumperReadMethod = MPF.ExecutionContexts.Redumper.ReadMethod;
using RedumperSectorOrder = MPF.ExecutionContexts.Redumper.SectorOrder;
@@ -18,6 +19,7 @@ namespace MPF.UI
{
DiscCategory discCategory => new Element<DiscCategory>(discCategory),
InternalProgram internalProgram => new Element<InternalProgram>(internalProgram),
LogCompression logCompression => new Element<LogCompression>(logCompression),
MediaType mediaType => new Element<MediaType>(mediaType),
RedumperReadMethod readMethod => new Element<RedumperReadMethod>(readMethod),
RedumperSectorOrder sectorOrder => new Element<RedumperSectorOrder>(sectorOrder),
@@ -40,6 +42,7 @@ namespace MPF.UI
{
Element<DiscCategory> dcElement => dcElement.Value,
Element<InternalProgram> ipElement => ipElement.Value,
Element<LogCompression> lcElement => lcElement.Value,
Element<MediaType> mtElement => mtElement.Value,
Element<RedumperReadMethod> rmElement => rmElement.Value,
Element<RedumperSectorOrder> soElement => soElement.Value,

View File

@@ -18,7 +18,7 @@
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<UseWindowsForms>true</UseWindowsForms>
<UseWPF>true</UseWPF>
<VersionPrefix>3.3.2</VersionPrefix>
<VersionPrefix>3.5.0</VersionPrefix>
<!-- Package Properties -->
<AssemblyName>MPF</AssemblyName>
@@ -70,14 +70,14 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.RedumpLib" Version="1.6.7" />
<PackageReference Include="SabreTools.RedumpLib" Version="[1.7.4]" />
</ItemGroup>
<ItemGroup>
<Page Update="UserControls\UserInput.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
</Page>
<Page Update="Windows\DiscInformationWindow.xaml">
<Page Update="Windows\MediaInformationWindow.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
</Page>
<Page Update="Windows\RingCodeGuideWindow.xaml">

View File

@@ -85,7 +85,7 @@
<Button x:Name="InputPathBrowseButton" Grid.Row="0" Grid.Column="1" Height="22" Width="50" HorizontalAlignment="Right" Content="Browse"
IsEnabled="{Binding InputPathBrowseButtonEnabled}" Style="{DynamicResource CustomButtonStyle}"/>
<Label x:Name="SystemMediaTypeLabel" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" Content="System/Media Type" />
<Label x:Name="SystemTypeLabel" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" Content="System Type" />
<ComboBox x:Name="SystemTypeComboBox" Grid.Row="1" Grid.Column="1" Height="22" Width="250" HorizontalAlignment="Left"
ItemsSource="{Binding Systems}" SelectedItem="{Binding Path=CurrentSystem, Converter={StaticResource ElementConverter}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding SystemTypeComboBoxEnabled}" Style="{DynamicResource CustomComboBoxStyle}">
@@ -99,9 +99,6 @@
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
<ComboBox x:Name="MediaTypeComboBox" Grid.Row="1" Grid.Column="1" Height="22" Width="140" HorizontalAlignment="Right"
ItemsSource="{Binding MediaTypes}" SelectedItem="{Binding Path=CurrentMediaType, Converter={StaticResource ElementConverter}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding MediaTypeComboBoxEnabled}" Style="{DynamicResource CustomComboBoxStyle}" />
<Label x:Name="DumpingProgramLabel" Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" Content="Dumping Program"/>
<ComboBox x:Name="DumpingProgramComboBox" Grid.Row="2" Grid.Column="1" Height="22" Width="250" HorizontalAlignment="Left"

View File

@@ -29,7 +29,6 @@ namespace MPF.UI.Windows
private ComboBox? DumpingProgramComboBox => ItemHelper.FindChild<ComboBox>(this, "DumpingProgramComboBox");
private Button? InputPathBrowseButton => ItemHelper.FindChild<Button>(this, "InputPathBrowseButton");
private TextBox? InputPathTextBox => ItemHelper.FindChild<TextBox>(this, "InputPathTextBox");
private ComboBox? MediaTypeComboBox => ItemHelper.FindChild<ComboBox>(this, "MediaTypeComboBox");
private ComboBox? SystemTypeComboBox => ItemHelper.FindChild<ComboBox>(this, "SystemTypeComboBox");
#endregion
@@ -89,7 +88,6 @@ namespace MPF.UI.Windows
// User Area SelectionChanged
SystemTypeComboBox!.SelectionChanged += SystemTypeComboBoxSelectionChanged;
MediaTypeComboBox!.SelectionChanged += MediaTypeComboBoxSelectionChanged;
DumpingProgramComboBox!.SelectionChanged += DumpingProgramComboBoxSelectionChanged;
// User Area TextChanged
@@ -125,14 +123,14 @@ namespace MPF.UI.Windows
}
/// <summary>
/// Show the disc information window
/// Show the media information window
/// </summary>
/// <param name="options">Options set to pass to the information window</param>
/// <param name="submissionInfo">SubmissionInfo object to display and possibly change</param>
/// <returns>Dialog open result</returns>
public bool? ShowDiscInformationWindow(Options? options, ref SubmissionInfo? submissionInfo)
public bool? ShowMediaInformationWindow(Options? options, ref SubmissionInfo? submissionInfo)
{
var discInformationWindow = new DiscInformationWindow(options ?? new Options(), submissionInfo)
var mediaInformationWindow = new MediaInformationWindow(options ?? new Options(), submissionInfo)
{
Focusable = true,
Owner = this,
@@ -141,12 +139,12 @@ namespace MPF.UI.Windows
WindowStartupLocation = WindowStartupLocation.CenterOwner,
};
discInformationWindow.Closed += delegate { Activate(); };
bool? result = discInformationWindow.ShowDialog();
mediaInformationWindow.Closed += delegate { Activate(); };
bool? result = mediaInformationWindow.ShowDialog();
// Copy back the submission info changes, if necessary
if (result == true)
submissionInfo = (discInformationWindow.DiscInformationViewModel.SubmissionInfo.Clone() as SubmissionInfo)!;
submissionInfo = (mediaInformationWindow.MediaInformationViewModel.SubmissionInfo.Clone() as SubmissionInfo)!;
return result;
}
@@ -160,8 +158,8 @@ namespace MPF.UI.Windows
/// </summary>
private async void OnCheckDumpClick(object sender, EventArgs e)
{
string? errorMessage = await CheckDumpViewModel.CheckDump(ShowDiscInformationWindow);
if (string.IsNullOrEmpty(errorMessage))
var result = await CheckDumpViewModel.CheckDump(ShowMediaInformationWindow);
if (result)
{
bool? checkAgain = DisplayUserMessage("Check Complete", "The dump has been processed successfully! Would you like to check another dump?", 2, false);
if (checkAgain == false)
@@ -171,7 +169,8 @@ namespace MPF.UI.Windows
}
else
{
DisplayUserMessage("Check Failed", errorMessage!, 1, false);
string message = result.Message.Length > 0 ? result.Message : "Please check all files exist and try again!";
DisplayUserMessage("Check Failed", message, 1, false);
}
}
@@ -211,15 +210,6 @@ namespace MPF.UI.Windows
CheckDumpViewModel.ChangeInputPath();
}
/// <summary>
/// Handler for MediaTypeComboBox SelectionChanged event
/// </summary>
public void MediaTypeComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (CheckDumpViewModel.CanExecuteSelectionChanged)
CheckDumpViewModel.ChangeMediaType();
}
/// <summary>
/// Handler for SystemTypeComboBox SelectionChanged event
/// </summary>

View File

@@ -134,7 +134,7 @@
<RowDefinition/>
</Grid.RowDefinitions>
<Label x:Name="SystemMediaTypeLabel" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Content="System/Media Type" />
<Label x:Name="SystemMediaTypeLabel" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Content="System" />
<ComboBox x:Name="SystemTypeComboBox" Grid.Row="0" Grid.Column="1" Height="22" Width="250" HorizontalAlignment="Left"
ItemsSource="{Binding Systems}" SelectedItem="{Binding Path=CurrentSystem, Converter={StaticResource ElementConverter}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding SystemTypeComboBoxEnabled}" Style="{DynamicResource CustomComboBoxStyle}">
@@ -150,7 +150,8 @@
</ComboBox>
<ComboBox x:Name="MediaTypeComboBox" Grid.Row="0" Grid.Column="1" Height="22" Width="140" HorizontalAlignment="Right"
ItemsSource="{Binding MediaTypes}" SelectedItem="{Binding Path=CurrentMediaType, Converter={StaticResource ElementConverter}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding MediaTypeComboBoxEnabled}" Style="{DynamicResource CustomComboBoxStyle}" />
IsEnabled="{Binding MediaTypeComboBoxEnabled}" Style="{DynamicResource CustomComboBoxStyle}"
Visibility="Hidden" />
<Label x:Name="OutputPathLabel" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" Content="Output Path"/>
<TextBox x:Name="OutputPathTextBox" Grid.Row="1" Grid.Column="1" Height="22" Width="345" HorizontalAlignment="Left" VerticalContentAlignment="Center"

View File

@@ -47,6 +47,7 @@ namespace MPF.UI.Windows
private ComboBox? MediaTypeComboBox => ItemHelper.FindChild<ComboBox>(this, "MediaTypeComboBox");
private Button? OutputPathBrowseButton => ItemHelper.FindChild<Button>(this, "OutputPathBrowseButton");
private TextBox? OutputPathTextBox => ItemHelper.FindChild<TextBox>(this, "OutputPathTextBox");
private Label? SystemMediaTypeLabel => ItemHelper.FindChild<Label>(this, "SystemMediaTypeLabel");
private ComboBox? SystemTypeComboBox => ItemHelper.FindChild<ComboBox>(this, "SystemTypeComboBox");
#endregion
@@ -108,11 +109,14 @@ namespace MPF.UI.Windows
if (MainViewModel.Options.ShowDebugViewMenuItem)
DebugViewMenuItem!.Visibility = Visibility.Visible;
MainViewModel.Init(LogOutput!.EnqueueLog, DisplayUserMessage, ShowDiscInformationWindow);
MainViewModel.Init(LogOutput!.EnqueueLog, DisplayUserMessage, ShowMediaInformationWindow);
// Set the UI color scheme according to the options
ApplyTheme();
// Hide or show the media type box based on program
SetMediaTypeVisibility();
// Check for updates, if necessary
if (MainViewModel.Options.CheckForUpdatesOnStartup)
CheckForUpdates(showIfSame: false);
@@ -205,8 +209,14 @@ namespace MPF.UI.Windows
MainViewModel.CheckForUpdates(out bool different, out string message, out var url);
// If we have a new version, put it in the clipboard
if (different && !string.IsNullOrEmpty(url))
Clipboard.SetText(url);
if (MainViewModel.Options.CopyUpdateUrlToClipboard && different && !string.IsNullOrEmpty(url))
{
try
{
Clipboard.SetText(url);
}
catch { }
}
if (showIfSame || different)
CustomMessageBox.Show(this, message, "Version Update Check", MessageBoxButton.OK, different ? MessageBoxImage.Exclamation : MessageBoxImage.Information);
@@ -231,22 +241,22 @@ namespace MPF.UI.Windows
public void ShowDebugDiscInfoWindow()
{
var submissionInfo = MainViewModel.CreateDebugSubmissionInfo();
_ = ShowDiscInformationWindow(MainViewModel.Options, ref submissionInfo);
_ = ShowMediaInformationWindow(MainViewModel.Options, ref submissionInfo);
Formatter.ProcessSpecialFields(submissionInfo!);
}
/// <summary>
/// Show the disc information window
/// Show the media information window
/// </summary>
/// <param name="options">Options set to pass to the information window</param>
/// <param name="submissionInfo">SubmissionInfo object to display and possibly change</param>
/// <returns>Dialog open result</returns>
public bool? ShowDiscInformationWindow(Options? options, ref SubmissionInfo? submissionInfo)
public bool? ShowMediaInformationWindow(Options? options, ref SubmissionInfo? submissionInfo)
{
if (options?.ShowDiscEjectReminder == true)
CustomMessageBox.Show(this, "It is now safe to eject the disc", "Eject", MessageBoxButton.OK, MessageBoxImage.Information);
var discInformationWindow = new DiscInformationWindow(options ?? new Options(), submissionInfo)
var mediaInformationWindow = new MediaInformationWindow(options ?? new Options(), submissionInfo)
{
Focusable = true,
Owner = this,
@@ -255,12 +265,12 @@ namespace MPF.UI.Windows
WindowStartupLocation = WindowStartupLocation.CenterOwner,
};
discInformationWindow.Closed += delegate { Activate(); };
bool? result = discInformationWindow.ShowDialog();
mediaInformationWindow.Closed += delegate { Activate(); };
bool? result = mediaInformationWindow.ShowDialog();
// Copy back the submission info changes, if necessary
if (result == true)
submissionInfo = (discInformationWindow.DiscInformationViewModel.SubmissionInfo.Clone() as SubmissionInfo)!;
submissionInfo = (mediaInformationWindow.MediaInformationViewModel.SubmissionInfo.Clone() as SubmissionInfo)!;
return result;
}
@@ -337,6 +347,37 @@ namespace MPF.UI.Windows
optionsWindow.Show();
}
/// <summary>
/// Set media type combo box visibility based on current program
/// </summary>
public void SetMediaTypeVisibility()
{
// Only DiscImageCreator uses the media type box
if (MainViewModel.CurrentProgram != InternalProgram.DiscImageCreator)
{
SystemMediaTypeLabel!.Content = "System";
MediaTypeComboBox!.Visibility = Visibility.Hidden;
return;
}
// If there are no media types defined
if (MainViewModel.MediaTypes == null)
{
SystemMediaTypeLabel!.Content = "System";
MediaTypeComboBox!.Visibility = Visibility.Hidden;
return;
}
// Only systems with more than one media type should show the box
bool visible = MainViewModel.MediaTypes.Count > 1;
SystemMediaTypeLabel!.Content = visible
? "System/Media Type"
: "System";
MediaTypeComboBox!.Visibility = visible
? Visibility.Visible
: Visibility.Hidden;
}
/// <summary>
/// Set the UI color scheme according to the options
/// </summary>
@@ -431,6 +472,9 @@ namespace MPF.UI.Windows
// Set the UI color scheme according to the options
ApplyTheme();
// Hide or show the media type box based on program
SetMediaTypeVisibility();
}
#region Menu Bar
@@ -515,7 +559,7 @@ namespace MPF.UI.Windows
public void DriveSpeedComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (MainViewModel.CanExecuteSelectionChanged)
MainViewModel.EnsureDiscInformation();
MainViewModel.EnsureMediaInformation();
}
/// <summary>
@@ -524,7 +568,10 @@ namespace MPF.UI.Windows
public void DumpingProgramComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (MainViewModel.CanExecuteSelectionChanged)
{
MainViewModel.ChangeDumpingProgram();
SetMediaTypeVisibility();
}
}
/// <summary>
@@ -557,7 +604,7 @@ namespace MPF.UI.Windows
public void OutputPathBrowseButtonClick(object sender, RoutedEventArgs e)
{
BrowseFile();
MainViewModel.EnsureDiscInformation();
MainViewModel.EnsureMediaInformation();
}
/// <summary>
@@ -566,7 +613,7 @@ namespace MPF.UI.Windows
public void OutputPathTextBoxTextChanged(object sender, TextChangedEventArgs e)
{
if (MainViewModel.CanExecuteSelectionChanged)
MainViewModel.EnsureDiscInformation();
MainViewModel.EnsureMediaInformation();
}
/// <summary>
@@ -581,7 +628,10 @@ namespace MPF.UI.Windows
public void SystemTypeComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (MainViewModel.CanExecuteSelectionChanged)
{
MainViewModel.ChangeSystem();
SetMediaTypeVisibility();
}
}
/// <summary>

View File

@@ -1,4 +1,4 @@
<coreWindows:WindowBase x:Class="MPF.UI.Windows.DiscInformationWindow"
<coreWindows:WindowBase x:Class="MPF.UI.Windows.MediaInformationWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
@@ -8,7 +8,7 @@
xmlns:redump="clr-namespace:SabreTools.RedumpLib.Data;assembly=SabreTools.RedumpLib"
xmlns:coreWindows="clr-namespace:MPF.UI.Windows"
mc:Ignorable="d"
Title="Disc Information" Width="600" WindowStyle="None"
Title="Media Information" Width="600" WindowStyle="None"
WindowStartupLocation="CenterOwner" ResizeMode="CanMinimize" SizeToContent="Height"
AllowsTransparency="True" Background="Transparent">
@@ -32,7 +32,7 @@
<Image Grid.Column="0" Source="/Images/Icon.ico" Height="20" Width="20" Margin="1" MouseDown="TitleMouseDown" />
<Label Grid.Column="1" Grid.ColumnSpan="4" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" MouseDown="TitleMouseDown">
<Label.Content>
<Run FontWeight="Bold" Text="Disc Information" />
<Run FontWeight="Bold" Text="Media Information" />
</Label.Content>
<Label.ContextMenu>
<ContextMenu Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
@@ -72,7 +72,7 @@
<TabItem x:Name="CommonInfo" Header="Common Info" Style="{DynamicResource CustomTabItemStyle}">
<ScrollViewer CanContentScroll="False" VerticalScrollBarVisibility="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MaxHeight="500">
<StackPanel Orientation="Vertical">
<GroupBox Header="Common Disc Information" Margin="5" Padding="5" BorderThickness="1" BorderBrush="LightGray"
<GroupBox Header="Common Media Information" Margin="5" Padding="5" BorderThickness="1" BorderBrush="LightGray"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<StackPanel Orientation="Vertical">
<controls:UserInput Label="Title"
@@ -174,6 +174,16 @@
<GroupBox Header="Extras" Margin="5" Padding="5" BorderThickness="1" BorderBrush="LightGray"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<StackPanel Orientation="Vertical">
<Grid x:Name="PCMacHybridGrid" Visibility="Collapsed">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.75*" />
<ColumnDefinition Width="1.75*" />
</Grid.ColumnDefinitions>
<Label/>
<CheckBox Grid.Column="1" x:Name="PCMacHybridCheckBox" Content="PC/Mac Hybrid" Margin="0,4"
IsChecked="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)PCMacHybrid], Mode=TwoWay}"/>
</Grid>
<controls:UserInput x:Name="CommentsTextBox" Label="Comments"
Text="{Binding SubmissionInfo.CommonDiscInfo.Comments, Mode=TwoWay}" TextHeight="50"
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top" />
@@ -183,33 +193,9 @@
Text="{Binding Path=SubmissionInfo.Extras.DiscKey, Mode=TwoWay}"/>
<controls:UserInput x:Name="DiscIDTextBox" Label="Disc ID" Visibility="Collapsed"
Text="{Binding Path=SubmissionInfo.Extras.DiscID, Mode=TwoWay}"/>
<controls:UserInput x:Name="GenreTextBox" Label="Genre"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)Genre], Mode=TwoWay}"/>
<controls:UserInput x:Name="ProtectionTextBox" Label="Protection" ToolTip="CAUTION: Only edit if you know what you are doing!"
Text="{Binding SubmissionInfo.CopyProtection.Protection, Mode=TwoWay}" TextHeight="75" TextWrapping="Wrap"
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.75*" />
<ColumnDefinition Width="1.75*" />
</Grid.ColumnDefinitions>
<Label/>
<CheckBox Grid.Column="1" x:Name="PostgapTypeCheckBox" Content="Postgap type (Form 2)" Margin="0,4"
IsChecked="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)PostgapType], Mode=TwoWay}"/>
</Grid>
<controls:UserInput x:Name="SeriesTextBox" Label="Series"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)Series], Mode=TwoWay}"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.75*" />
<ColumnDefinition Width="1.75*" />
</Grid.ColumnDefinitions>
<Label/>
<CheckBox Grid.Column="1" x:Name="VCDCheckBox" Content="V-CD" Margin="0,4"
IsChecked="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)VCD], Mode=TwoWay}"/>
</Grid>
</StackPanel>
</GroupBox>
@@ -254,6 +240,8 @@
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)FoxInteractiveID], Mode=TwoWay}"/>
<controls:UserInput x:Name="GTInteractiveIDTextBox" Label="GT Interactive ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)GTInteractiveID], Mode=TwoWay}"/>
<controls:UserInput x:Name="InterplayIDTextBox" Label="Interplay ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)InterplayID], Mode=TwoWay}"/>
<controls:UserInput x:Name="JASRACIDTextBox" Label="JASRAC ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)JASRACID], Mode=TwoWay}"/>
<controls:UserInput x:Name="KingRecordsIDTextBox" Label="King Records ID"
@@ -320,7 +308,7 @@
<controls:UserInput x:Name="GamesTextBox" Label="Games" TextHeight="50"
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[(redump:SiteCode)Games], Mode=TwoWay}"/>
<controls:UserInput x:Name="NetYarozeGamesTextBox" Label="Net Yaroze Games" TextHeight="50"
<controls:UserInput x:Name="NetYarozeGamesTextBox" Label="Net Yaroze Games" Visibility="Collapsed" TextHeight="50"
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[(redump:SiteCode)NetYarozeGames], Mode=TwoWay}"/>

View File

@@ -6,9 +6,9 @@ using SabreTools.RedumpLib.Data;
namespace MPF.UI.Windows
{
/// <summary>
/// Interaction logic for DiscInformationWindow.xaml
/// Interaction logic for MediaInformationWindow.xaml
/// </summary>
public partial class DiscInformationWindow : WindowBase
public partial class MediaInformationWindow : WindowBase
{
#if NET35
@@ -20,11 +20,18 @@ namespace MPF.UI.Windows
#region Additional Info
private Grid? PCMacHybridGrid => ItemHelper.FindChild<Grid>(this, "PCMacHybridGrid");
private UserInput? DiscIDTextBox => ItemHelper.FindChild<UserInput>(this, "DiscIDTextBox");
private UserInput? DiscKeyTextBox => ItemHelper.FindChild<UserInput>(this, "DiscKeyTextBox");
#endregion
#region Contents
private UserInput? NetYarozeGamesTextBox => ItemHelper.FindChild<UserInput>(this, "NetYarozeGamesTextBox");
#endregion
#region Ringcodes
private GroupBox? L0Info => ItemHelper.FindChild<GroupBox>(this, "L0Info");
@@ -102,14 +109,14 @@ namespace MPF.UI.Windows
#endif
/// <summary>
/// Read-only access to the current disc information view model
/// Read-only access to the current media information view model
/// </summary>
public DiscInformationViewModel DiscInformationViewModel => DataContext as DiscInformationViewModel ?? new DiscInformationViewModel(new Options(), new SubmissionInfo());
public MediaInformationViewModel MediaInformationViewModel => DataContext as MediaInformationViewModel ?? new MediaInformationViewModel(new Options(), new SubmissionInfo());
/// <summary>
/// Constructor
/// </summary>
public DiscInformationWindow(Options options, SubmissionInfo? submissionInfo)
public MediaInformationWindow(Options options, SubmissionInfo? submissionInfo)
{
#if NET40_OR_GREATER || NETCOREAPP
InitializeComponent();
@@ -124,14 +131,14 @@ namespace MPF.UI.Windows
System.Windows.Shell.WindowChrome.SetWindowChrome(this, chrome);
#endif
DataContext = new DiscInformationViewModel(options, submissionInfo);
DiscInformationViewModel.Load();
DataContext = new MediaInformationViewModel(options, submissionInfo);
MediaInformationViewModel.Load();
// Limit lists, if necessary
if (options.EnableRedumpCompatibility)
{
DiscInformationViewModel.SetRedumpRegions();
DiscInformationViewModel.SetRedumpLanguages();
MediaInformationViewModel.SetRedumpRegions();
MediaInformationViewModel.SetRedumpLanguages();
}
// Add handlers
@@ -325,8 +332,6 @@ namespace MPF.UI.Windows
case DiscType.NintendoWiiOpticalDiscSL:
case DiscType.NintendoWiiOpticalDiscDL:
case DiscType.NintendoWiiUOpticalDiscSL:
case DiscType.UMDSL:
case DiscType.UMDDL:
// Quad-layer discs
if (submissionInfo?.SizeAndChecksums?.Layerbreak3 != default(long))
{
@@ -421,6 +426,23 @@ namespace MPF.UI.Windows
break;
case DiscType.UMDSL:
case DiscType.UMDDL:
L0Info!.Header = reverseOrder ? "Layer 0 (Outer)" : "Layer 0 (Inner)";
L0MasteringRing!.Label = "Mastering Ring";
L0MasteringSID!.Label = "Mastering SID";
L0Toolstamp!.Label = "Toolstamp/Mastering Code";
L0MouldSID!.Label = "Data Side Mould SID";
L0AdditionalMould!.Label = "Data Side Additional Mould";
L1Info!.Header = reverseOrder ? "Layer 1 (Inner)" : "Layer 1 (Outer)";
L1MasteringRing!.Label = "Mastering Ring";
L1MasteringSID!.Label = "Mastering SID";
L1Toolstamp!.Label = "Toolstamp/Mastering Code";
L1MouldSID!.Label = "Label Side Mould SID";
L1AdditionalMould!.Label = "Label Side Additional Mould";
break;
// All other media we assume to have no rings
default:
L0Info!.Visibility = Visibility.Collapsed;
@@ -440,10 +462,22 @@ namespace MPF.UI.Windows
var system = submissionInfo?.CommonDiscInfo?.System;
switch (system)
{
case RedumpSystem.AppleMacintosh:
PCMacHybridGrid!.Visibility = Visibility.Visible;
break;
case RedumpSystem.IBMPCcompatible:
PCMacHybridGrid!.Visibility = Visibility.Visible;
break;
case RedumpSystem.NintendoWiiU:
DiscKeyTextBox!.Visibility = Visibility.Visible;
break;
case RedumpSystem.SonyPlayStation:
NetYarozeGamesTextBox!.Visibility = Visibility.Visible;
break;
case RedumpSystem.SonyPlayStation2:
LanguageSelectionGrid!.Visibility = Visibility.Visible;
break;
@@ -481,7 +515,7 @@ namespace MPF.UI.Windows
/// </summary>
private void OnAcceptClick(object sender, RoutedEventArgs e)
{
DiscInformationViewModel.Save();
MediaInformationViewModel.Save();
DialogResult = true;
Close();
}

View File

@@ -82,6 +82,11 @@
ToolTip="Check for updates when the application starts" Margin="0,4"
/>
<CheckBox VerticalAlignment="Center" Content="Copy Update URL to Clipboard"
IsChecked="{Binding Options.CopyUpdateUrlToClipboard}"
ToolTip="If an update is found, try to copy the update URL to the clipboard" Margin="0,4"
/>
<CheckBox VerticalAlignment="Center" Content="Fast Update Label"
IsChecked="{Binding Options.FastUpdateLabel}"
ToolTip="Bypasses disc checks to quickly update the output path. Use with caution!" Margin="0,4"
@@ -90,22 +95,16 @@
</GroupBox>
<GroupBox Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Detection">
<UniformGrid Columns="2" Rows="3">
<CheckBox x:Name="SkipMediaTypeDetectionCheckBox" VerticalAlignment="Center" Content="Skip Type Detect"
IsChecked="{Binding Options.SkipMediaTypeDetection}"
ToolTip="Disable trying to guess media type inserted (may improve performance at startup)" Margin="0,4"
/>
<UniformGrid Columns="2" Rows="2">
<CheckBox VerticalAlignment="Center" Content="Skip System Detect"
IsChecked="{Binding Options.SkipSystemDetection}"
ToolTip="Disable trying to guess system (may improve performance at startup)" Margin="0,4"
/>
<CheckBox VerticalAlignment="Center" Content="No Fixed Drives"
IsChecked="{Binding Options.IgnoreFixedDrives}"
ToolTip="Ignore hard drives and other fixed drives" Margin="0,4"
IsChecked="{Binding Options.IgnoreFixedDrives}"
ToolTip="Ignore hard drives and other fixed drives" Margin="0,4"
/>
<Label/> <!-- Empty label for padding -->
<Label VerticalAlignment="Center" Content="Default System:" HorizontalAlignment="Right" />
<ComboBox x:Name="DefaultSystemComboBox" Height="22" Width="200" HorizontalAlignment="Left"
@@ -192,10 +191,10 @@
<TabItem Header="Dumping" Style="{DynamicResource CustomTabItemStyle}">
<StackPanel>
<GroupBox Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Dumping">
<UniformGrid Columns="2" Rows="6">
<UniformGrid Columns="2" Rows="7">
<CheckBox VerticalAlignment="Center" Content="Show Disc Info"
IsChecked="{Binding Options.PromptForDiscInformation}"
ToolTip="Enable showing the disc information output after dumping" Margin="0,4"
ToolTip="Enable showing the media information output after dumping" Margin="0,4"
/>
<CheckBox VerticalAlignment="Center" Content="Pull All Information"
@@ -244,6 +243,12 @@
ToolTip="Compress output log files to reduce space" Margin="0,4"
/>
<Label VerticalAlignment="Center" Content="Log Compression:" HorizontalAlignment="Right" />
<ComboBox x:Name="LogCompressionComboBox" Height="22" Width="200" HorizontalAlignment="Left"
ItemsSource="{Binding LogCompressions}" SelectedItem="{Binding Options.LogCompression, Converter={StaticResource ElementConverter}, Mode=TwoWay}"
Style="{DynamicResource CustomComboBoxStyle}" IsEnabled="{Binding Options.CompressLogFiles}"
/>
<CheckBox VerticalAlignment="Center" Content="Delete Unnecessary Files"
IsChecked="{Binding Options.DeleteUnnecessaryFiles}"
ToolTip="Delete unnecesary output files to reduce space" Margin="0,4"
@@ -403,12 +408,16 @@
</GroupBox>
<GroupBox Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Redumper">
<UniformGrid Columns="2" Rows="7">
<UniformGrid Columns="2" Rows="8">
<CheckBox VerticalAlignment="Center" Content="Enable Verbose Output"
IsChecked="{Binding Options.RedumperEnableVerbose}"
ToolTip="Enable verbose output in logs" Margin="0,4"
/>
<Label/> <!-- Empty label for padding -->
<CheckBox VerticalAlignment="Center" Content="Enable Refine Sector Mode Flag"
IsChecked="{Binding Options.RedumperRefineSectorMode}"
ToolTip="Enable the refine sector mode flag by default" Margin="0,4"
/>
<Label Content="Reread Tries:" VerticalAlignment="Center" HorizontalAlignment="Right"/>
<TextBox VerticalAlignment="Center" VerticalContentAlignment="Center" Width="200" HorizontalAlignment="Left"
@@ -472,7 +481,8 @@
IsEnabled="{Binding Options.RetrieveMatchInformation}" />
<Label VerticalAlignment="Center" HorizontalAlignment="Right" Content="Password" />
<PasswordBox x:Name="RedumpPasswordBox" Height="22" HorizontalAlignment="Stretch" PasswordChar="*" />
<PasswordBox x:Name="RedumpPasswordBox" Height="22" HorizontalAlignment="Stretch" PasswordChar="*"
IsEnabled="{Binding Options.RetrieveMatchInformation}"/>
<Button x:Name="RedumpLoginTestButton" Height="22" Width="80" Content="Test Login"
Style="{DynamicResource CustomButtonStyle}"

View File

@@ -81,31 +81,31 @@ function download_programs() {
declare -A DL_MAP
# Aaru
DL_MAP["Aaru_linux-arm64"]="https://github.com/aaru-dps/Aaru/releases/download/v5.3.2/aaru-5.3.2_linux_arm64.tar.gz"
DL_MAP["Aaru_linux-x64"]="https://github.com/aaru-dps/Aaru/releases/download/v5.3.2/aaru-5.3.2_linux_amd64.tar.gz"
DL_MAP["Aaru_osx-arm64"]="https://github.com/aaru-dps/Aaru/releases/download/v5.3.2/aaru-5.3.2_macos.zip"
DL_MAP["Aaru_osx-x64"]="https://github.com/aaru-dps/Aaru/releases/download/v5.3.2/aaru-5.3.2_macos.zip"
DL_MAP["Aaru_win-arm64"]="https://github.com/aaru-dps/Aaru/releases/download/v5.3.2/aaru-5.3.2_windows_aarch64.zip"
DL_MAP["Aaru_win-x86"]="https://github.com/aaru-dps/Aaru/releases/download/v5.3.2/aaru-5.3.2_windows_x86.zip"
DL_MAP["Aaru_win-x64"]="https://github.com/aaru-dps/Aaru/releases/download/v5.3.2/aaru-5.3.2_windows_x64.zip"
DL_MAP["Aaru_linux-arm64"]="https://github.com/aaru-dps/Aaru/releases/download/v5.4.1/aaru-5.4.1_linux_arm64.tar.gz"
DL_MAP["Aaru_linux-x64"]="https://github.com/aaru-dps/Aaru/releases/download/v5.4.1/aaru-5.4.1_linux_amd64.tar.gz"
DL_MAP["Aaru_osx-arm64"]="https://github.com/aaru-dps/Aaru/releases/download/v5.4.1/aaru-5.4.1_macos-aarch64.zip"
DL_MAP["Aaru_osx-x64"]="https://github.com/aaru-dps/Aaru/releases/download/v5.4.1/aaru-5.4.1_macos.zip"
DL_MAP["Aaru_win-arm64"]="https://github.com/aaru-dps/Aaru/releases/download/v5.4.1/aaru-5.4.1_windows_aarch64.zip"
DL_MAP["Aaru_win-x86"]="https://github.com/aaru-dps/Aaru/releases/download/v5.4.1/aaru-5.4.1_windows_x64.zip"
DL_MAP["Aaru_win-x64"]="https://github.com/aaru-dps/Aaru/releases/download/v5.4.1/aaru-5.4.1_windows_x64.zip"
# DiscImageCreator
DL_MAP["Creator_linux-arm64"]=""
DL_MAP["Creator_linux-x64"]="https://github.com/user-attachments/files/20000183/DiscImageCreator_20250501.tar.gz"
DL_MAP["Creator_linux-x64"]="https://github.com/user-attachments/files/22080484/DiscImageCreator_20250901.tar.gz"
DL_MAP["Creator_osx-arm64"]="https://github.com/user-attachments/files/20000184/DiscImageCreator_20250501.zip"
DL_MAP["Creator_osx-x64"]="https://github.com/user-attachments/files/20000184/DiscImageCreator_20250501.zip"
DL_MAP["Creator_win-arm64"]=""
DL_MAP["Creator_win-x86"]="https://github.com/user-attachments/files/20000181/DiscImageCreator_20250501.zip"
DL_MAP["Creator_win-x64"]="https://github.com/user-attachments/files/20000181/DiscImageCreator_20250501.zip"
DL_MAP["Creator_win-x86"]="https://github.com/user-attachments/files/22080480/DiscImageCreator_20250901.zip"
DL_MAP["Creator_win-x64"]="https://github.com/user-attachments/files/22080480/DiscImageCreator_20250901.zip"
# Redumper
DL_MAP["Redumper_linux-arm64"]=""
DL_MAP["Redumper_linux-x64"]="https://github.com/superg/redumper/releases/download/build_610/redumper-2025.06.12_build610-Linux64.zip"
DL_MAP["Redumper_osx-arm64"]="https://github.com/superg/redumper/releases/download/build_610/redumper-2025.06.12_build610-Darwin64.zip"
DL_MAP["Redumper_osx-x64"]="https://github.com/superg/redumper/releases/download/build_610/redumper-2025.06.12_build610-Darwin64.zip"
DL_MAP["Redumper_win-arm64"]=""
DL_MAP["Redumper_win-x86"]="https://github.com/superg/redumper/releases/download/build_610/redumper-2025.06.12_build610-Windows32.zip"
DL_MAP["Redumper_win-x64"]="https://github.com/superg/redumper/releases/download/build_610/redumper-2025.06.12_build610-Windows64.zip"
DL_MAP["Redumper_linux-arm64"]="https://github.com/superg/redumper/releases/download/b655/redumper-b655-linux-arm64.zip"
DL_MAP["Redumper_linux-x64"]="https://github.com/superg/redumper/releases/download/b655/redumper-b655-linux-x64.zip"
DL_MAP["Redumper_osx-arm64"]="https://github.com/superg/redumper/releases/download/b655/redumper-b655-macos-arm64.zip"
DL_MAP["Redumper_osx-x64"]=""
DL_MAP["Redumper_win-arm64"]="https://github.com/superg/redumper/releases/download/b655/redumper-b655-windows-arm64.zip"
DL_MAP["Redumper_win-x86"]="https://github.com/superg/redumper/releases/download/b655/redumper-b655-windows-x86.zip"
DL_MAP["Redumper_win-x64"]="https://github.com/superg/redumper/releases/download/b655/redumper-b655-windows-x64.zip"
# Download and extract files
echo "===== Downloading Required Programs ====="

View File

@@ -70,31 +70,31 @@ function Download-Programs {
$DL_PREFIXES = ("Aaru", "Creator", "Redumper")
$DL_MAP = @{
# Aaru
"Aaru_linux-arm64" = "https://github.com/aaru-dps/Aaru/releases/download/v5.3.2/aaru-5.3.2_linux_arm64.tar.gz"
"Aaru_linux-x64" = "https://github.com/aaru-dps/Aaru/releases/download/v5.3.2/aaru-5.3.2_linux_amd64.tar.gz"
"Aaru_osx-arm64" = "https://github.com/aaru-dps/Aaru/releases/download/v5.3.2/aaru-5.3.2_macos.zip"
"Aaru_osx-x64" = "https://github.com/aaru-dps/Aaru/releases/download/v5.3.2/aaru-5.3.2_macos.zip"
"Aaru_win-arm64" = "https://github.com/aaru-dps/Aaru/releases/download/v5.3.2/aaru-5.3.2_windows_aarch64.zip"
"Aaru_win-x86" = "https://github.com/aaru-dps/Aaru/releases/download/v5.3.2/aaru-5.3.2_windows_x86.zip"
"Aaru_win-x64" = "https://github.com/aaru-dps/Aaru/releases/download/v5.3.2/aaru-5.3.2_windows_x64.zip"
"Aaru_linux-arm64" = "https://github.com/aaru-dps/Aaru/releases/download/v5.4.1/aaru-5.4.1_linux_arm64.tar.gz"
"Aaru_linux-x64" = "https://github.com/aaru-dps/Aaru/releases/download/v5.4.1/aaru-5.4.1_linux_amd64.tar.gz"
"Aaru_osx-arm64" = "https://github.com/aaru-dps/Aaru/releases/download/v5.4.1/aaru-5.4.1_macos-aarch64.zip"
"Aaru_osx-x64" = "https://github.com/aaru-dps/Aaru/releases/download/v5.4.1/aaru-5.4.1_macos.zip"
"Aaru_win-arm64" = "https://github.com/aaru-dps/Aaru/releases/download/v5.4.1/aaru-5.4.1_windows_aarch64.zip"
"Aaru_win-x86" = "https://github.com/aaru-dps/Aaru/releases/download/v5.4.1/aaru-5.4.1_windows_x64.zip"
"Aaru_win-x64" = "https://github.com/aaru-dps/Aaru/releases/download/v5.4.1/aaru-5.4.1_windows_x64.zip"
# DiscImageCreator
"Creator_linux-arm64" = ""
"Creator_linux-x64" = "https://github.com/user-attachments/files/20000183/DiscImageCreator_20250501.tar.gz"
"Creator_linux-x64" = "https://github.com/user-attachments/files/22080484/DiscImageCreator_20250901.tar.gz"
"Creator_osx-arm64" = "https://github.com/user-attachments/files/20000184/DiscImageCreator_20250501.zip"
"Creator_osx-x64" = "https://github.com/user-attachments/files/20000184/DiscImageCreator_20250501.zip"
"Creator_win-arm64" = ""
"Creator_win-x86" = "https://github.com/user-attachments/files/20000181/DiscImageCreator_20250501.zip"
"Creator_win-x64" = "https://github.com/user-attachments/files/20000181/DiscImageCreator_20250501.zip"
"Creator_win-x86" = "https://github.com/user-attachments/files/22080480/DiscImageCreator_20250901.zip"
"Creator_win-x64" = "https://github.com/user-attachments/files/22080480/DiscImageCreator_20250901.zip"
# Redumper
"Redumper_linux-arm64" = ""
"Redumper_linux-x64" = "https://github.com/superg/redumper/releases/download/build_610/redumper-2025.06.12_build610-Linux64.zip"
"Redumper_osx-arm64" = "https://github.com/superg/redumper/releases/download/build_610/redumper-2025.06.12_build610-Darwin64.zip"
"Redumper_osx-x64" = "https://github.com/superg/redumper/releases/download/build_610/redumper-2025.06.12_build610-Darwin64.zip"
"Redumper_win-arm64" = ""
"Redumper_win-x86" = "https://github.com/superg/redumper/releases/download/build_610/redumper-2025.06.12_build610-Windows32.zip"
"Redumper_win-x64" = "https://github.com/superg/redumper/releases/download/build_610/redumper-2025.06.12_build610-Windows64.zip"
"Redumper_linux-arm64" = "https://github.com/superg/redumper/releases/download/b655/redumper-b655-linux-arm64.zip"
"Redumper_linux-x64" = "https://github.com/superg/redumper/releases/download/b655/redumper-b655-linux-x64.zip"
"Redumper_osx-arm64" = "https://github.com/superg/redumper/releases/download/b655/redumper-b655-macos-arm64.zip"
"Redumper_osx-x64" = ""
"Redumper_win-arm64" = "https://github.com/superg/redumper/releases/download/b655/redumper-b655-windows-arm64.zip"
"Redumper_win-x86" = "https://github.com/superg/redumper/releases/download/b655/redumper-b655-windows-x86.zip"
"Redumper_win-x64" = "https://github.com/superg/redumper/releases/download/b655/redumper-b655-windows-x64.zip"
}
# Download and extract files