Compare commits

...

51 Commits
3.3.3 ... 3.4.1

Author SHA1 Message Date
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
55 changed files with 893 additions and 569 deletions

View File

@@ -1,3 +1,57 @@
### 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

View File

@@ -12,7 +12,7 @@
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<VersionPrefix>3.3.3</VersionPrefix>
<VersionPrefix>3.4.1</VersionPrefix>
<!-- Package Properties -->
<Title>MPF CLI</Title>
@@ -43,7 +43,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.RedumpLib" Version="1.6.8" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.7.4" />
</ItemGroup>
</Project>

View File

@@ -44,20 +44,19 @@ namespace MPF.CLI
// 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);
opts = InteractiveMode(options, out knownSystem);
}
// Use normal commandline parameters
else
{
// Try processing the common arguments
bool success = OptionsLoader.ProcessCommonArguments(args, out mediaType, out knownSystem, out var error);
bool success = OptionsLoader.ProcessCommonArguments(args, out knownSystem, out var error);
if (!success)
{
DisplayHelp(error);
@@ -123,13 +122,20 @@ namespace MPF.CLI
DisplayHelp("Both a device path and file path need to be supplied, exiting...");
return;
}
if (options.InternalProgram == InternalProgram.DiscImageCreator
&& opts.CustomParams == null
&& (opts.MediaType == null || opts.MediaType == MediaType.NONE))
{
DisplayHelp("Media type is required for DiscImageCreator, exiting...");
return;
}
// Normalize the file path
if (opts.FilePath != null)
opts.FilePath = FrontendTool.NormalizeOutputPaths(opts.FilePath, getFullPath: true);
if (opts.FilePath != null)
opts.FilePath = FrontendTool.NormalizeOutputPaths(opts.FilePath, getFullPath: true);
// Get the speed from the options
int speed = opts.DriveSpeed ?? FrontendTool.GetDefaultSpeedForMediaType(mediaType, options);
int speed = opts.DriveSpeed ?? FrontendTool.GetDefaultSpeedForMediaType(opts.MediaType, options);
// Populate an environment
var drive = Drive.Create(null, opts.DevicePath ?? string.Empty);
@@ -138,22 +144,22 @@ namespace MPF.CLI
drive,
knownSystem,
options.InternalProgram);
env.SetExecutionContext(mediaType, null);
env.SetExecutionContext(opts.MediaType, null);
env.SetProcessor();
// Process the parameters
string? paramStr = opts.CustomParams ?? env.GetFullParameters(mediaType, speed);
string? paramStr = opts.CustomParams ?? env.GetFullParameters(opts.MediaType, speed);
if (string.IsNullOrEmpty(paramStr))
{
DisplayHelp("No valid environment could be created, exiting...");
return;
}
env.SetExecutionContext(mediaType, paramStr);
env.SetExecutionContext(opts.MediaType, paramStr);
// Invoke the dumping program
Console.WriteLine($"Invoking {options.InternalProgram} using '{paramStr}'");
var dumpResult = env.Run(mediaType).GetAwaiter().GetResult();
var dumpResult = env.Run(opts.MediaType).GetAwaiter().GetResult();
Console.WriteLine(dumpResult.Message);
if (!dumpResult)
return;
@@ -174,12 +180,12 @@ namespace MPF.CLI
drive,
knownSystem,
internalProgram: null);
env.SetExecutionContext(mediaType, null);
env.SetExecutionContext(opts.MediaType, null);
env.SetProcessor();
}
// Finally, attempt to do the output dance
var verifyResult = env.VerifyAndSaveDumpOutput(mediaType: mediaType)
var verifyResult = env.VerifyAndSaveDumpOutput()
.ConfigureAwait(false).GetAwaiter().GetResult();
Console.WriteLine(verifyResult.Message);
}
@@ -194,7 +200,7 @@ namespace MPF.CLI
Console.WriteLine(error);
Console.WriteLine("Usage:");
Console.WriteLine("MPF.CLI <mediatype> <system> [options]");
Console.WriteLine("MPF.CLI <system> [options]");
Console.WriteLine();
Console.WriteLine("Standalone Options:");
Console.WriteLine("-h, -?, --help Show this help text");
@@ -208,6 +214,7 @@ namespace MPF.CLI
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)");
@@ -233,14 +240,14 @@ namespace MPF.CLI
/// <summary>
/// Enable interactive mode for entering information
/// </summary>
private static CommandOptions InteractiveMode(Options options, out MediaType mediaType, out RedumpSystem? system)
private static CommandOptions InteractiveMode(Options options, out RedumpSystem? system)
{
// Create return values
var opts = new CommandOptions
{
MediaType = MediaType.NONE,
FilePath = Path.Combine(options.DefaultOutputPath ?? "ISO", "track.bin"),
};
mediaType = MediaType.NONE;
system = options.DefaultSystem;
// Create state values
@@ -251,9 +258,9 @@ namespace MPF.CLI
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($"1) Set system (Currently '{system}')");
Console.WriteLine($"2) Set dumping program (Currently '{options.InternalProgram}')");
Console.WriteLine($"3) Set media type (Currently '{opts.MediaType}')");
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}')");
@@ -268,11 +275,11 @@ namespace MPF.CLI
switch (result)
{
case "1":
goto mediaType;
case "2":
goto system;
case "3":
case "2":
goto dumpingProgram;
case "3":
goto mediaType;
case "4":
goto devicePath;
case "5":
@@ -304,14 +311,6 @@ namespace MPF.CLI
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:");
@@ -328,6 +327,14 @@ namespace MPF.CLI
options.InternalProgram = result.ToInternalProgram();
goto root;
mediaType:
Console.WriteLine();
Console.WriteLine("Input the media type and press Enter:");
Console.Write("> ");
result = Console.ReadLine();
opts.MediaType = OptionsLoader.ToMediaType(result);
goto root;
devicePath:
Console.WriteLine();
Console.WriteLine("Input the device path and press Enter:");
@@ -412,6 +419,17 @@ namespace MPF.CLI
startIndex++;
}
// Use a device path
else if (args[startIndex].StartsWith("-t=") || args[startIndex].StartsWith("--mediatype="))
{
opts.MediaType = OptionsLoader.ToMediaType(args[startIndex].Split('=')[1].Trim('"'));
}
else if (args[startIndex] == "-t" || args[startIndex] == "--mediatype")
{
opts.MediaType = OptionsLoader.ToMediaType(args[startIndex + 1].Trim('"'));
startIndex++;
}
// Use a device path
else if (args[startIndex].StartsWith("-d=") || args[startIndex].StartsWith("--device="))
{
@@ -488,6 +506,12 @@ namespace MPF.CLI
/// </summary>
private class CommandOptions
{
/// <summary>
/// Media type to dump
/// </summary>
/// <remarks>Required for DIC and if custom parameters not set</remarks>
public MediaType? MediaType { get; set; } = null;
/// <summary>
/// Path to the device to dump
/// </summary>

View File

@@ -12,7 +12,7 @@
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<VersionPrefix>3.3.3</VersionPrefix>
<VersionPrefix>3.4.1</VersionPrefix>
<!-- Package Properties -->
<Title>MPF Check</Title>
@@ -43,7 +43,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.RedumpLib" Version="1.6.8" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.7.4" />
</ItemGroup>
</Project>

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.8" />
<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,7 +41,7 @@ namespace MPF.ExecutionContexts.Test
};
[Theory]
[InlineData(null, null, null, "filename.bin", null, "")]
[InlineData(null, null, null, "filename.bin", null, "disc --verbose --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.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")]

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.3</VersionPrefix>
<VersionPrefix>3.4.1</VersionPrefix>
<WarningsNotAsErrors>NU5104</WarningsNotAsErrors>
<!-- Package Properties -->
@@ -32,7 +32,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.RedumpLib" Version="1.6.8" />
<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>
@@ -241,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)
@@ -270,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/>
@@ -291,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)
{
@@ -350,7 +333,6 @@ namespace MPF.ExecutionContexts.Redumper
}
string? readMethod = GetStringSetting(options, SettingConstants.ReadMethod, SettingConstants.ReadMethodDefault);
if (!string.IsNullOrEmpty(readMethod) && readMethod != ReadMethod.NONE.ToString())
{
this[FlagStrings.DriveReadMethod] = true;
@@ -390,7 +372,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);
@@ -402,13 +384,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;
@@ -417,7 +403,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;
@@ -444,16 +430,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

@@ -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

@@ -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.8" />
<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

@@ -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

@@ -449,14 +449,12 @@ namespace MPF.Frontend
/// <summary>
/// Verify that the current environment has a complete dump and create submission info is possible
/// </summary>
/// <param name="mediaType">Media type for controlling expected file sets, if available</param>
/// <param name="resultProgress">Optional result progress callback</param>
/// <param name="protectionProgress">Optional protection progress callback</param>
/// <param name="processUserInfo">Optional user prompt to deal with submission information</param>
/// <param name="seedInfo">A seed SubmissionInfo object that contains user data</param>
/// <returns>Result instance with the outcome</returns>
public async Task<ResultEventArgs> VerifyAndSaveDumpOutput(
MediaType? mediaType = null,
IProgress<ResultEventArgs>? resultProgress = null,
IProgress<ProtectionProgress>? protectionProgress = null,
ProcessUserInfoDelegate? processUserInfo = null,
@@ -485,16 +483,8 @@ namespace MPF.Frontend
var outputDirectory = Path.GetDirectoryName(OutputPath);
var outputFilename = Path.GetFileName(OutputPath);
// Determine the media type from the processor, if not provided
mediaType ??= _processor.DetermineMediaType(outputDirectory, outputFilename);
// Check to make sure that the output had all the correct files
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])}"));
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);
// Extract the information from the output files
resultProgress.Report(ResultEventArgs.Success("Extracting output information from output files..."));
@@ -507,7 +497,15 @@ namespace MPF.Frontend
_processor,
resultProgress,
protectionProgress);
resultProgress.Report(ResultEventArgs.Success("Extracting information complete!"));
if (submissionInfo == null)
{
resultProgress.Report(ResultEventArgs.Failure("There was an issue extracting information!"));
return ResultEventArgs.Failure();
}
else
{
resultProgress.Report(ResultEventArgs.Success("Extracting information complete!"));
}
// Inject seed submission info data, if necessary
if (seedInfo != null)

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.3</VersionPrefix>
<VersionPrefix>3.4.1</VersionPrefix>
<!-- Package Properties -->
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
@@ -31,12 +31,13 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="BinaryObjectScanner" Version="3.3.4" />
<PackageReference Include="LibIRD" Version="0.9.3" />
<PackageReference Include="BinaryObjectScanner" Version="3.4.2" />
<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.8" />
<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.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

@@ -123,6 +123,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>
@@ -427,6 +436,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
@@ -561,15 +579,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

@@ -119,42 +119,6 @@ namespace MPF.Frontend.Tools
return true;
}
/// <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>

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))
@@ -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,10 +51,6 @@ 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);
@@ -77,9 +73,9 @@ namespace MPF.Frontend.Tools
SubmissionInfo info = CreateDefaultSubmissionInfo(processor, system, mediaType, options.AddPlaceholders);
// Get specific tool output handling
processor?.GenerateSubmissionInfo(info, mediaType, basePath, options.EnableRedumpCompatibility);
processor.GenerateSubmissionInfo(info, mediaType, basePath, options.EnableRedumpCompatibility);
if (options.IncludeArtifacts)
info.Artifacts = processor?.GenerateArtifacts(mediaType, 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)
@@ -1002,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 _))
@@ -1066,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();
@@ -507,7 +422,6 @@ namespace MPF.Frontend.ViewModels
// Finally, attempt to do the output dance
var result = await env.VerifyAndSaveDumpOutput(
mediaType: CurrentMediaType,
resultProgress: resultProgress,
protectionProgress: protectionProgress,
processUserInfo: processUserInfo);
@@ -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
@@ -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()}.");
@@ -1366,6 +1359,10 @@ namespace MPF.Frontend.ViewModels
/// </summary>
public void EnsureMediaInformation()
{
// If the drive list is empty, ignore updates
if (Drives.Count == 0)
return;
// Get the current environment information
_environment = DetermineEnvironment();
@@ -1639,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))
@@ -1665,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
@@ -2100,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())])}");
@@ -2113,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();
@@ -2190,23 +2196,6 @@ namespace MPF.Frontend.ViewModels
// 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
@@ -2256,7 +2245,6 @@ namespace MPF.Frontend.ViewModels
if (result)
{
result = await _environment.VerifyAndSaveDumpOutput(
mediaType: CurrentMediaType,
resultProgress: resultProgress,
protectionProgress: protectionProgress,
processUserInfo: _processUserInfo);
@@ -2304,6 +2292,7 @@ namespace MPF.Frontend.ViewModels
MediaScanButtonEnabled = false;
UpdateVolumeLabelEnabled = false;
CopyProtectScanButtonEnabled = false;
StartStopButtonEnabled = false;
}
else
{
@@ -2324,6 +2313,7 @@ namespace MPF.Frontend.ViewModels
MediaScanButtonEnabled = true;
UpdateVolumeLabelEnabled = true;
CopyProtectScanButtonEnabled = true;
StartStopButtonEnabled = true;
}
}

View File

@@ -1,6 +1,6 @@
using System;
using System.IO;
using SabreTools.Models.Logiqx;
using SabreTools.Data.Models.Logiqx;
using Xunit;
namespace MPF.Processors.Test

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;

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.8" />
<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,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

@@ -103,7 +103,7 @@ namespace MPF.Processors.Test
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(MediaType.CDROM, outputDirectory, outputFilename);
Assert.Equal(16, actual.Count);
Assert.Equal(17, actual.Count);
}
[Fact]
@@ -114,7 +114,7 @@ namespace MPF.Processors.Test
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
var actual = processor.GetOutputFiles(MediaType.DVD, outputDirectory, outputFilename);
Assert.Equal(17, actual.Count);
Assert.Equal(15, actual.Count);
}
[Fact]

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

@@ -291,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,

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;
@@ -409,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;

View File

@@ -6,7 +6,7 @@ using System.IO.Compression;
#endif
using System.Text;
using SabreTools.Hashing;
using SabreTools.Models.Logiqx;
using SabreTools.Data.Models.Logiqx;
using SabreTools.RedumpLib.Data;
namespace MPF.Processors
@@ -312,42 +312,50 @@ namespace MPF.Processors
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

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;

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;
@@ -289,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;

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;

View File

@@ -12,7 +12,7 @@
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<VersionPrefix>3.3.3</VersionPrefix>
<VersionPrefix>3.4.1</VersionPrefix>
<WarningsNotAsErrors>NU5104</WarningsNotAsErrors>
<!-- Package Properties -->
@@ -33,13 +33,13 @@
</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.8" />
<PackageReference Include="SabreTools.Serialization" Version="1.8.6" />
<PackageReference Include="SabreTools.Hashing" Version="1.5.0" />
<PackageReference Include="SabreTools.IO" Version="1.7.5" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.7.4" />
<PackageReference Include="SabreTools.Serialization" Version="2.0.0" />
<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="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,6 +1,6 @@
using System.Collections.Generic;
using System.IO;
using SabreTools.Models.Logiqx;
using SabreTools.Data.Models.Logiqx;
using SabreTools.RedumpLib;
using SabreTools.RedumpLib.Data;

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
@@ -133,7 +132,7 @@ namespace MPF.Processors
{
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];
@@ -1126,8 +1125,8 @@ namespace MPF.Processors
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};
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;
@@ -1289,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];
@@ -1300,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

@@ -51,6 +51,7 @@ namespace MPF.Processors
{
// 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;
@@ -72,13 +73,16 @@ namespace MPF.Processors
// 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!;
// 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.CommonDiscInfo.RingWriteOffset = writeOffset;
info.TracksAndWriteOffsets.OtherWriteOffsets = writeOffset;
// Attempt to get multisession data
@@ -146,7 +150,7 @@ 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 (mediaType == MediaType.BluRay || mediaType == MediaType.NintendoWiiUOpticalDisc)
@@ -192,7 +196,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;
@@ -206,7 +210,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;
}
@@ -226,7 +230,7 @@ namespace MPF.Processors
string xmidString = ProcessingTool.GetXMID($"{basePath}.dmi").Trim('\0');
if (!string.IsNullOrEmpty(xmidString))
{
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.XMID] = xmidString;
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.XMID] = xmidString;
var xmid = SabreTools.Serialization.Wrappers.XMID.Create(xmidString);
info.CommonDiscInfo.Serial = xmid?.Serial ?? string.Empty;
if (!redumpCompat)
@@ -239,7 +243,7 @@ namespace MPF.Processors
string xemidString = ProcessingTool.GetXeMID($"{basePath}.dmi").Trim('\0');
if (!string.IsNullOrEmpty(xemidString))
{
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.XeMID] = xemidString;
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.XeMID] = xemidString;
var xemid = SabreTools.Serialization.Wrappers.XeMID.Create(xemidString);
info.CommonDiscInfo.Serial = xemid?.Serial ?? string.Empty;
if (!redumpCompat)
@@ -251,15 +255,15 @@ namespace MPF.Processors
string? dmiCrc = HashTool.GetFileHash($"{basePath}.dmi", HashType.CRC32);
if (dmiCrc != null)
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.DMIHash] = dmiCrc.ToUpperInvariant();
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();
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();
info.CommonDiscInfo.CommentsSpecialFields![SiteCode.SSHash] = ssCrc.ToUpperInvariant();
}
string? ssRanges = ProcessingTool.GetSSRanges($"{basePath}.ss");
@@ -276,7 +280,7 @@ namespace MPF.Processors
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;
@@ -285,7 +289,7 @@ 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;
@@ -298,7 +302,7 @@ namespace MPF.Processors
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;
@@ -313,7 +317,7 @@ namespace MPF.Processors
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;
@@ -328,7 +332,7 @@ namespace MPF.Processors
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;
@@ -343,7 +347,7 @@ namespace MPF.Processors
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;
@@ -356,7 +360,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;
@@ -365,7 +369,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;
}
@@ -378,21 +382,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;
}
@@ -401,7 +405,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;
}
@@ -410,7 +414,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;
}
@@ -441,9 +445,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"),
@@ -527,13 +534,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"),
@@ -573,6 +573,7 @@ namespace MPF.Processors
new($"{outputFilename}.ss", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"ss"),
// ssv1 and ssv2 extensions are obsolete
new($"{outputFilename}.ssv1", OutputFileFlags.Binary
| OutputFileFlags.Zippable,
"ssv1"),
@@ -1204,7 +1205,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;
}
@@ -1800,6 +1801,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>
@@ -2254,6 +2293,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
{
@@ -2267,10 +2307,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,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;
@@ -184,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;

View File

@@ -18,7 +18,7 @@
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<UseWindowsForms>true</UseWindowsForms>
<UseWPF>true</UseWPF>
<VersionPrefix>3.3.3</VersionPrefix>
<VersionPrefix>3.4.1</VersionPrefix>
<!-- Package Properties -->
<AssemblyName>MPF</AssemblyName>
@@ -70,7 +70,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.RedumpLib" Version="1.6.8" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.7.4" />
</ItemGroup>
<ItemGroup>

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
@@ -160,8 +158,8 @@ namespace MPF.UI.Windows
/// </summary>
private async void OnCheckDumpClick(object sender, EventArgs e)
{
string? errorMessage = await CheckDumpViewModel.CheckDump(ShowMediaInformationWindow);
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 ?? "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
@@ -113,6 +114,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();
// 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);
@@ -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
@@ -524,7 +568,10 @@ namespace MPF.UI.Windows
public void DumpingProgramComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (MainViewModel.CanExecuteSelectionChanged)
{
MainViewModel.ChangeDumpingProgram();
SetMediaTypeVisibility();
}
}
/// <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

@@ -240,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"

View File

@@ -332,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))
{
@@ -428,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;

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"
@@ -403,12 +402,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 +475,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_631/redumper-2025.07.14_build631-Linux64.zip"
DL_MAP["Redumper_osx-arm64"]="https://github.com/superg/redumper/releases/download/build_631/redumper-2025.07.14_build631-Darwin64.zip"
DL_MAP["Redumper_osx-x64"]="https://github.com/superg/redumper/releases/download/build_631/redumper-2025.07.14_build631-Darwin64.zip"
DL_MAP["Redumper_win-arm64"]=""
DL_MAP["Redumper_win-x86"]="https://github.com/superg/redumper/releases/download/build_631/redumper-2025.07.14_build631-Windows32.zip"
DL_MAP["Redumper_win-x64"]="https://github.com/superg/redumper/releases/download/build_631/redumper-2025.07.14_build631-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_631/redumper-2025.07.14_build631-Linux64.zip"
"Redumper_osx-arm64" = "https://github.com/superg/redumper/releases/download/build_631/redumper-2025.07.14_build631-Darwin64.zip"
"Redumper_osx-x64" = "https://github.com/superg/redumper/releases/download/build_631/redumper-2025.07.14_build631-Darwin64.zip"
"Redumper_win-arm64" = ""
"Redumper_win-x86" = "https://github.com/superg/redumper/releases/download/build_631/redumper-2025.07.14_build631-Windows32.zip"
"Redumper_win-x64" = "https://github.com/superg/redumper/releases/download/build_631/redumper-2025.07.14_build631-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