mirror of
https://github.com/SabreTools/MPF.git
synced 2026-02-04 13:45:29 +00:00
Compare commits
185 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87400793eb | ||
|
|
45f79d95b1 | ||
|
|
c8a4a61028 | ||
|
|
44091981b2 | ||
|
|
d3352643fc | ||
|
|
114c7fb38a | ||
|
|
dc7da708dc | ||
|
|
72e56aa1c7 | ||
|
|
99ceab07ad | ||
|
|
c0f6c072ce | ||
|
|
e039124f6c | ||
|
|
c96e4a4c7a | ||
|
|
622a08acf3 | ||
|
|
f44b6bf0d0 | ||
|
|
a6d75e15ea | ||
|
|
a02f03c4cb | ||
|
|
d48f5132fb | ||
|
|
ed4ac24efa | ||
|
|
9f3b8a7c2c | ||
|
|
612d4bb1f5 | ||
|
|
b58a50d246 | ||
|
|
af83811d57 | ||
|
|
66835fe6ab | ||
|
|
34cc1d33c6 | ||
|
|
a42d14e3b8 | ||
|
|
87aa165edf | ||
|
|
d217d62007 | ||
|
|
27bcc0d40a | ||
|
|
e1df075cde | ||
|
|
8358692e8d | ||
|
|
e1fae01dab | ||
|
|
d206ab140a | ||
|
|
9d8722ab17 | ||
|
|
c4fa40c403 | ||
|
|
1d0b06bfbe | ||
|
|
2cdf473dcb | ||
|
|
1af9e2c2da | ||
|
|
9a1815fa1e | ||
|
|
f601961c49 | ||
|
|
406acd34c5 | ||
|
|
31cdcbbc25 | ||
|
|
2215ce71c9 | ||
|
|
1872fbb1c8 | ||
|
|
d99f912ac2 | ||
|
|
00a76fb648 | ||
|
|
187e951a47 | ||
|
|
c0b9b27aae | ||
|
|
b76bb17396 | ||
|
|
2efa6d3623 | ||
|
|
3972ce633d | ||
|
|
0dc7901393 | ||
|
|
a25ba6eaa5 | ||
|
|
4ea48dfe57 | ||
|
|
8f7ad8b2ee | ||
|
|
3b9800df07 | ||
|
|
4c80d3234e | ||
|
|
9e4af1d66b | ||
|
|
73555df2ea | ||
|
|
3ca78604fd | ||
|
|
0138046923 | ||
|
|
2129184209 | ||
|
|
dd2116f8a6 | ||
|
|
814c2d9149 | ||
|
|
b3f7276044 | ||
|
|
ad88aa980b | ||
|
|
aca55e9203 | ||
|
|
cc3330bb27 | ||
|
|
1370909db7 | ||
|
|
08cc0c394b | ||
|
|
cb6692aea3 | ||
|
|
b3badb3a55 | ||
|
|
cbf73901d3 | ||
|
|
4822e45d58 | ||
|
|
1d930d36bf | ||
|
|
9effcc403d | ||
|
|
05dcc039bd | ||
|
|
cb08656abc | ||
|
|
69b22fc736 | ||
|
|
bf857f6ce7 | ||
|
|
7ebf2378b3 | ||
|
|
aec25dab37 | ||
|
|
e11969780d | ||
|
|
02c98b1547 | ||
|
|
c864589478 | ||
|
|
bdea1593be | ||
|
|
f6b78c07ca | ||
|
|
982a217d32 | ||
|
|
06588752ad | ||
|
|
9b057d7141 | ||
|
|
93fb3a85b5 | ||
|
|
7320f9ba66 | ||
|
|
a94f43ae0c | ||
|
|
e19a3f02e5 | ||
|
|
375c2c896c | ||
|
|
b151e79aed | ||
|
|
b45901c133 | ||
|
|
fab54ca0ae | ||
|
|
31dd32f19b | ||
|
|
f51c79d282 | ||
|
|
743c943363 | ||
|
|
91f6e266d1 | ||
|
|
8e843647bf | ||
|
|
151402dc50 | ||
|
|
057f340c9c | ||
|
|
f3f9c63156 | ||
|
|
7910a79917 | ||
|
|
cc7acfcd00 | ||
|
|
5580e208f5 | ||
|
|
56ef06d651 | ||
|
|
204dfca126 | ||
|
|
eb337a8aaf | ||
|
|
aa6fd781e8 | ||
|
|
32bcfa1d42 | ||
|
|
3b2e14d0de | ||
|
|
88a0ce38f9 | ||
|
|
110c8337aa | ||
|
|
3dc79fea6b | ||
|
|
fb036385f9 | ||
|
|
428bb2817b | ||
|
|
791caff240 | ||
|
|
d92015d071 | ||
|
|
de98bd9e0b | ||
|
|
67f5a7794a | ||
|
|
fbef94f634 | ||
|
|
0e8363f06e | ||
|
|
a1bafe0426 | ||
|
|
c51461592c | ||
|
|
ef5f996ec4 | ||
|
|
aa5998a52e | ||
|
|
37207c1cb0 | ||
|
|
d1813fdbc7 | ||
|
|
faf9d1d6f8 | ||
|
|
0360df0604 | ||
|
|
fe6487eeb4 | ||
|
|
b9eedd1cf6 | ||
|
|
26281b8f0b | ||
|
|
f0508fdf93 | ||
|
|
166d69c7ec | ||
|
|
fabf08ba55 | ||
|
|
0e5d8af0e9 | ||
|
|
3e1263ebff | ||
|
|
c0ed830241 | ||
|
|
4209158807 | ||
|
|
6d79ebf449 | ||
|
|
88ab691f07 | ||
|
|
37b1dc574c | ||
|
|
ad56e249ed | ||
|
|
f28cfe3d69 | ||
|
|
9643442281 | ||
|
|
dd44ec7ac1 | ||
|
|
801c1126cf | ||
|
|
4fd72efc46 | ||
|
|
9ec045cb21 | ||
|
|
52801ee94c | ||
|
|
2077d53964 | ||
|
|
14046e9217 | ||
|
|
2766debffc | ||
|
|
4f4688899c | ||
|
|
8151db9696 | ||
|
|
227c61b588 | ||
|
|
61224fba7b | ||
|
|
1dbf5516d8 | ||
|
|
10fe6ac32a | ||
|
|
e39ee66726 | ||
|
|
fff2db75d0 | ||
|
|
3a14db53c6 | ||
|
|
8b76b82e0f | ||
|
|
e110c55e1a | ||
|
|
85c30fbad3 | ||
|
|
14e5c74c65 | ||
|
|
b180e31b56 | ||
|
|
d172a45891 | ||
|
|
e74289116e | ||
|
|
68b932bad0 | ||
|
|
c4793e849c | ||
|
|
1c525a6d2e | ||
|
|
c8610ee16a | ||
|
|
0fb3bc1106 | ||
|
|
3cf133d750 | ||
|
|
f0be6b0bc9 | ||
|
|
e0ccb8b10d | ||
|
|
940afae1fd | ||
|
|
94ba339ef2 | ||
|
|
bfead10d87 | ||
|
|
97f9a73fc1 |
2
.gitmodules
vendored
2
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
||||
[submodule "MPF.Library/Aaru/CICMMetadata"]
|
||||
path = MPF.Library/Aaru/CICMMetadata
|
||||
path = CICMMetadata
|
||||
url = https://github.com/claunia/CICMMetadata
|
||||
135
CHANGELIST.md
135
CHANGELIST.md
@@ -1,3 +1,138 @@
|
||||
### 2.3 (2022-02-05)
|
||||
- Start overhauling Redump information pulling, again
|
||||
- Add internal structure for special site codes
|
||||
- Add new tabs for special site information
|
||||
- Clean up default handling of fields
|
||||
- Try to handle multi-line fields during parsing
|
||||
- Fix CSSKey log handling
|
||||
- Show most read-only fields in new tab
|
||||
- Add horizontal scroll to user input
|
||||
- Tweak new disc information fields and tabs
|
||||
- Allow internal serial and volume label to be hidden
|
||||
- Be smarter about showing update checks
|
||||
- Ensure all fields are read-only on read-only tab
|
||||
- Add model for 2-layer ringcode guide
|
||||
- Add first attempt 2-layer ringcode guide
|
||||
- Add even more safety to clone
|
||||
- Sanitize filename after check
|
||||
- Handle pulled linebreaks better
|
||||
- Skip anti-modchip string in some cases
|
||||
- Handle pulled linebreaks better, again
|
||||
- Tweak more Disc Info window formatting
|
||||
- Skip unnecessary newlines in parsing
|
||||
- Force scroll visibility, tweak text sizes again
|
||||
- Fix newline skipping
|
||||
- Add missing continue statement
|
||||
- Add newlines for mutliline special fields
|
||||
- Omit volume label for "Audio CD"
|
||||
- Remove Enter/Escape registration on disc info window
|
||||
- Logically group more things in disc info window
|
||||
- Remove tab key from disc info window
|
||||
- Add `<tab>` processing
|
||||
- Unban newly opened consoles
|
||||
- Tweak minimalized layout a bit more
|
||||
- Add tab setting
|
||||
- Further disc info window tweaks
|
||||
- Changed IsEnabled to IsReadOnly
|
||||
- Fix scrolling issues in disc info window
|
||||
- Convert postgap and VCD fields to checkboxes
|
||||
- Adjust width ratios for disc info window
|
||||
- Fix IsReadOnly
|
||||
- Only include booleans if the value is true
|
||||
- Add hidden debug option for "ShowDebugViewMenuItem"
|
||||
- Fix incorrect header check
|
||||
- Make protection read-only field multiline
|
||||
- Reformat Saturn internal date
|
||||
- Fix Sega CD internal serial reading
|
||||
- Fix crash on invalid parameters
|
||||
- Differentiate XMID and XeMID
|
||||
- Conditionally pull region from Redump
|
||||
- Be smarter about volume labels
|
||||
- Use volume label in checks, not formatted version
|
||||
- Sync with Redump region and language selection
|
||||
- Try to delete old log archive before writing
|
||||
- Add support for all ISO language codes
|
||||
- Add support for all ISO region codes
|
||||
- Ensure ordering in output site tags
|
||||
- Make site code formatting helper method
|
||||
- Better helper method organization
|
||||
- Start supporting ordered tags and non-tags
|
||||
- Add more non-tag support; rearrange info window
|
||||
- Fix incorrect language three-letter code
|
||||
- Hook up additional Xbox field to disc info window
|
||||
- Fix non-tag tag shortnames
|
||||
- Fix parsing of non-tag tags again
|
||||
- Disable unnecessary cuesheet parsing
|
||||
- Fix incorrect region two-letter code
|
||||
- Adjust long names for some languages
|
||||
- Add Sierra ID to list of pseudo-tags
|
||||
- Add another hand-formatted version of SS tag
|
||||
- Move internal serial before volume label
|
||||
- Check for $SystemUpdate folder for X360 discs
|
||||
- Slightly rename UK and USA regions for UI
|
||||
- Add another hand-formatted version of SS tag
|
||||
- Add verification reminders for pulled tags
|
||||
- Read longer string for Saturn internal serial
|
||||
- Ensure version only pulled if one doesn't exist
|
||||
- Ensure Games pseudo-tag is multi-line
|
||||
- Add alternate pseudo-tag for Playable Demos
|
||||
- Make error clearer if something is unsupported in Check
|
||||
- Ensure drive is not null for volume labels
|
||||
- Check explicitly for no matches on Redump pull
|
||||
- Normalize PS1/PS2 executable names
|
||||
- Adjust paths for DIC just before dumping
|
||||
|
||||
### 2.2 (2021-12-30)
|
||||
- Fix Saturn header finding
|
||||
- Add Pocket PC support
|
||||
- Add HD-DVD-Video support
|
||||
- Convert to using separate Redump library code
|
||||
- Update to Aaru v5.3.0-rc1
|
||||
- Update to BurnOutSharp 1.8.0
|
||||
- Update support packages
|
||||
- Add on-startup "check for updates" option
|
||||
- Update to Aaru v5.3.0-rc2
|
||||
- Add .NET 5.0 as build target
|
||||
- Remove .NET Core 3.1 and .NET 5.0 from AppVeyor build artifacts
|
||||
- Null-safeguard RedumpLib conversions
|
||||
- Move cuesheet code to separate DLL
|
||||
- Move CICMMetadata to top-level
|
||||
- Separate out remaining functionality into individual DLLs
|
||||
- Update to Aaru v5.3.0 LTS
|
||||
- Update to DIC 20211001
|
||||
- HTTP encode password for Redump login, again
|
||||
- Fix NullReferenceException in anti-modchip scans
|
||||
- Update arcade metadata (Shizmob)
|
||||
- Add JSON output option for MPF.Check
|
||||
- Fix JSON output serialization
|
||||
- Ensure corrupt directories on media don't throw errors
|
||||
- Add retry to Redump external calls
|
||||
- Make anti-modchip scans even safer
|
||||
- Remove lower bound checking on LBA values for DIC
|
||||
- Remove offset for audio discs on DIC output
|
||||
- Start adding regression tests for DIC
|
||||
- Ensure parameters box is safer during options save
|
||||
- Fix protection sanitization and add regression tests
|
||||
- Update to DIC 20211101
|
||||
- Add protection sanitization for StarForce
|
||||
- Trim filenames for DVD protection from DIC
|
||||
- Fill out internal tests around Redump library
|
||||
- Refine the "missing disc" text
|
||||
- Overhaul XeMID handling
|
||||
- Fix output dialog issues in Options window
|
||||
- Fix saving path settings if set from dialog
|
||||
- Allow default system if skipping system detection enabled
|
||||
- Add internal support for all Redump site codes
|
||||
- Use the Volume Label special site code
|
||||
- Capture newlines in Redump fields
|
||||
- Invert condition for volume label
|
||||
- Fix missing ISN usages
|
||||
- Fix ISN string
|
||||
- Validate track count when matching Redump
|
||||
- Allow for better matching of multi track discs
|
||||
- Temporarily disable pulling comments from Redump pages
|
||||
- Add safety around volume labels
|
||||
|
||||
### 2.1 (2021-07-22)
|
||||
- Enum, no more
|
||||
- Sony works backward
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net48;netcoreapp3.1</TargetFrameworks>
|
||||
<TargetFrameworks>net48;netcoreapp3.1;net5.0</TargetFrameworks>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<OutputType>Exe</OutputType>
|
||||
<Title>MPF Check</Title>
|
||||
@@ -10,7 +10,7 @@
|
||||
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
|
||||
<Copyright>Copyright (c)2019-2021</Copyright>
|
||||
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
|
||||
<Version>2.1</Version>
|
||||
<Version>2.3</Version>
|
||||
<AssemblyVersion>$(Version)</AssemblyVersion>
|
||||
<FileVersion>$(Version)</FileVersion>
|
||||
<IncludeSource>true</IncludeSource>
|
||||
@@ -28,7 +28,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="1.7.0" GeneratePathProperty="true">
|
||||
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="1.8.0" GeneratePathProperty="true">
|
||||
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.1">
|
||||
@@ -46,6 +46,7 @@
|
||||
<Project>{51ab0928-13f9-44bf-a407-b6957a43a056}</Project>
|
||||
<Name>MPF.Library</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\RedumpLib\RedumpLib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,9 +1,13 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BurnOutSharp;
|
||||
using MPF.Data;
|
||||
using MPF.Redump;
|
||||
using MPF.Utilities;
|
||||
using MPF.Core.Converters;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.Utilities;
|
||||
using MPF.Library;
|
||||
using RedumpLib.Data;
|
||||
using RedumpLib.Web;
|
||||
|
||||
namespace MPF.Check
|
||||
{
|
||||
@@ -33,7 +37,7 @@ namespace MPF.Check
|
||||
}
|
||||
else if (args[0] == "-ls" || args[0] == "--listsystems")
|
||||
{
|
||||
ListKnownSystems();
|
||||
ListSystems();
|
||||
Console.ReadLine();
|
||||
return;
|
||||
}
|
||||
@@ -46,16 +50,16 @@ namespace MPF.Check
|
||||
}
|
||||
|
||||
// Check the MediaType
|
||||
var mediaType = Converters.ToMediaType(args[0].Trim('"'));
|
||||
var mediaType = EnumConverter.ToMediaType(args[0].Trim('"'));
|
||||
if (mediaType == MediaType.NONE)
|
||||
{
|
||||
DisplayHelp($"{args[0]} is not a recognized media type");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the KnownSystem
|
||||
var knownSystem = Converters.ToKnownSystem(args[1].Trim('"'));
|
||||
if (knownSystem == KnownSystem.NONE)
|
||||
// Check the RedumpSystem
|
||||
var knownSystem = Extensions.ToRedumpSystem(args[1].Trim('"'));
|
||||
if (knownSystem == null)
|
||||
{
|
||||
DisplayHelp($"{args[1]} is not a recognized system");
|
||||
return;
|
||||
@@ -65,7 +69,7 @@ namespace MPF.Check
|
||||
string username = null, password = null;
|
||||
string internalProgram = "DiscImageCreator";
|
||||
string path = string.Empty;
|
||||
bool scan = false, compress = false;
|
||||
bool scan = false, compress = false, json = false;
|
||||
|
||||
// Loop through and process options
|
||||
int startIndex = 2;
|
||||
@@ -108,13 +112,19 @@ namespace MPF.Check
|
||||
}
|
||||
|
||||
// Scan for protection (requires device path)
|
||||
else if (args[startIndex].StartsWith("-s") || args[startIndex].StartsWith("--scan"))
|
||||
else if (args[startIndex].Equals("-s") || args[startIndex].Equals("--scan"))
|
||||
{
|
||||
scan = true;
|
||||
}
|
||||
|
||||
// Output submission JSON
|
||||
else if (args[startIndex].Equals("-j") || args[startIndex].Equals("--json"))
|
||||
{
|
||||
json = true;
|
||||
}
|
||||
|
||||
// Compress log and extraneous files
|
||||
else if (args[startIndex].StartsWith("-z") || args[startIndex].StartsWith("--zip"))
|
||||
else if (args[startIndex].Equals("-z") || args[startIndex].Equals("--zip"))
|
||||
{
|
||||
compress = true;
|
||||
}
|
||||
@@ -163,9 +173,11 @@ namespace MPF.Check
|
||||
// Now populate an environment
|
||||
var options = new Options
|
||||
{
|
||||
InternalProgram = Converters.ToInternalProgram(internalProgram),
|
||||
InternalProgram = EnumConverter.ToInternalProgram(internalProgram),
|
||||
ScanForProtection = scan && !string.IsNullOrWhiteSpace(path),
|
||||
PromptForDiscInformation = false,
|
||||
ShowDiscEjectReminder = false,
|
||||
OutputSubmissionJSON = json,
|
||||
CompressLogFiles = compress,
|
||||
|
||||
RedumpUsername = username,
|
||||
@@ -194,7 +206,7 @@ namespace MPF.Check
|
||||
Console.WriteLine(error);
|
||||
|
||||
Console.WriteLine("Usage:");
|
||||
Console.WriteLine("MPF.Check.exe <mediatype> <system> [options] </path/to/output.bin> ...");
|
||||
Console.WriteLine("MPF.Check.exe <mediatype> <system> [options] </path/to/output.cue/iso> ...");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Standalone Options:");
|
||||
Console.WriteLine("-h, -? Show this help text");
|
||||
@@ -207,6 +219,7 @@ namespace MPF.Check
|
||||
Console.WriteLine("-u, --use <program> Dumping program output type");
|
||||
Console.WriteLine("-p, --path <drivepath> Physical drive path for additional checks");
|
||||
Console.WriteLine("-s, --scan Enable copy protection scan (requires --path)");
|
||||
Console.WriteLine("-j, --json Enable submission JSON output");
|
||||
Console.WriteLine("-z, --zip Enable log file compression");
|
||||
Console.WriteLine();
|
||||
}
|
||||
@@ -242,17 +255,19 @@ namespace MPF.Check
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List all known systems with their short usable names
|
||||
/// List all systems with their short usable names
|
||||
/// </summary>
|
||||
private static void ListKnownSystems()
|
||||
private static void ListSystems()
|
||||
{
|
||||
Console.WriteLine("Supported Known Systems:");
|
||||
foreach (var val in Enum.GetValues(typeof(KnownSystem)))
|
||||
{
|
||||
if (((KnownSystem)val) == KnownSystem.NONE)
|
||||
continue;
|
||||
var knownSystems = Enum.GetValues(typeof(RedumpSystem))
|
||||
.OfType<RedumpSystem?>()
|
||||
.Where(s => s != null && !s.IsMarker() && s.GetCategory() != SystemCategory.NONE)
|
||||
.OrderBy(s => s.LongName() ?? string.Empty);
|
||||
|
||||
Console.WriteLine($"{((KnownSystem?)val).ShortName()} - {((KnownSystem?)val).LongName()}");
|
||||
foreach (var val in knownSystems)
|
||||
{
|
||||
Console.WriteLine($"{val.ShortName()} - {val.LongName()}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
4
MPF.Core/AssemblyInfo.cs
Normal file
4
MPF.Core/AssemblyInfo.cs
Normal file
@@ -0,0 +1,4 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// Anything marked as internal can be used by the test methods
|
||||
[assembly: InternalsVisibleTo("MPF.Test")]
|
||||
381
MPF.Core/Converters/EnumConverter.cs
Normal file
381
MPF.Core/Converters/EnumConverter.cs
Normal file
@@ -0,0 +1,381 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
#if NET_FRAMEWORK
|
||||
using IMAPI2;
|
||||
#endif
|
||||
using MPF.Core.Data;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.Converters
|
||||
{
|
||||
public static class EnumConverter
|
||||
{
|
||||
#region Cross-enumeration conversions
|
||||
|
||||
/// <summary>
|
||||
/// Convert drive type to internal version, if possible
|
||||
/// </summary>
|
||||
/// <param name="driveType">DriveType value to check</param>
|
||||
/// <returns>InternalDriveType, if possible, null on error</returns>
|
||||
public static InternalDriveType? ToInternalDriveType(this DriveType driveType)
|
||||
{
|
||||
switch (driveType)
|
||||
{
|
||||
case DriveType.CDRom:
|
||||
return InternalDriveType.Optical;
|
||||
case DriveType.Fixed:
|
||||
return InternalDriveType.HardDisk;
|
||||
case DriveType.Removable:
|
||||
return InternalDriveType.Removable;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#if NET_FRAMEWORK
|
||||
/// <summary>
|
||||
/// Convert IMAPI physical media type to a MediaType
|
||||
/// </summary>
|
||||
/// <param name="type">IMAPI_MEDIA_PHYSICAL_TYPE value to check</param>
|
||||
/// <returns>MediaType if possible, null on error</returns>
|
||||
public static MediaType? IMAPIToMediaType(this IMAPI_MEDIA_PHYSICAL_TYPE type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_UNKNOWN:
|
||||
return MediaType.NONE;
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_CDROM:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_CDR:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_CDRW:
|
||||
return MediaType.CDROM;
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDROM:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDRAM:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDPLUSR:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDPLUSRW:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDPLUSR_DUALLAYER:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDDASHR:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDDASHRW:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDDASHR_DUALLAYER:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DISK:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDPLUSRW_DUALLAYER:
|
||||
return MediaType.DVD;
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_HDDVDROM:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_HDDVDR:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_HDDVDRAM:
|
||||
return MediaType.HDDVD;
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_BDROM:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_BDR:
|
||||
case IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_BDRE:
|
||||
return MediaType.BluRay;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
#region Convert to Long Name
|
||||
|
||||
/// <summary>
|
||||
/// Long name method cache
|
||||
/// </summary>
|
||||
private static readonly ConcurrentDictionary<Type, MethodInfo> LongNameMethods = new ConcurrentDictionary<Type, MethodInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// Get the string representation of a generic enumerable value
|
||||
/// </summary>
|
||||
/// <param name="value">Enum value to convert</param>
|
||||
/// <returns>String representation of that value if possible, empty string on error</returns>
|
||||
public static string GetLongName(Enum value)
|
||||
{
|
||||
try
|
||||
{
|
||||
var sourceType = value?.GetType();
|
||||
sourceType = Nullable.GetUnderlyingType(sourceType) ?? sourceType;
|
||||
|
||||
if (!LongNameMethods.TryGetValue(sourceType, out MethodInfo method))
|
||||
{
|
||||
|
||||
method = typeof(RedumpLib.Data.Extensions).GetMethod("LongName", new[] { typeof(Nullable<>).MakeGenericType(sourceType) });
|
||||
if (method == null)
|
||||
method = typeof(EnumConverter).GetMethod("LongName", new[] { typeof(Nullable<>).MakeGenericType(sourceType) });
|
||||
|
||||
LongNameMethods.TryAdd(sourceType, method);
|
||||
}
|
||||
|
||||
if (method != null)
|
||||
return method.Invoke(null, new[] { value }) as string;
|
||||
else
|
||||
return string.Empty;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Converter is not implemented for the given type
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string representation of the InternalProgram enum values
|
||||
/// </summary>
|
||||
/// <param name="prog">InternalProgram value to convert</param>
|
||||
/// <returns>String representing the value, if possible</returns>
|
||||
public static string LongName(this InternalProgram? prog)
|
||||
{
|
||||
switch (prog)
|
||||
{
|
||||
#region Dumping support
|
||||
|
||||
case InternalProgram.Aaru:
|
||||
return "Aaru";
|
||||
case InternalProgram.DD:
|
||||
return "dd";
|
||||
case InternalProgram.DiscImageCreator:
|
||||
return "DiscImageCreator";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Verification support only
|
||||
|
||||
case InternalProgram.CleanRip:
|
||||
return "CleanRip";
|
||||
|
||||
case InternalProgram.DCDumper:
|
||||
return "DCDumper";
|
||||
|
||||
case InternalProgram.UmdImageCreator:
|
||||
return "UmdImageCreator";
|
||||
|
||||
#endregion
|
||||
|
||||
case InternalProgram.NONE:
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Convert From String
|
||||
|
||||
/// <summary>
|
||||
/// Get the InternalProgram enum value for a given string
|
||||
/// </summary>
|
||||
/// <param name="internalProgram">String value to convert</param>
|
||||
/// <returns>InternalProgram represented by the string, if possible</returns>
|
||||
public static InternalProgram ToInternalProgram(string internalProgram)
|
||||
{
|
||||
switch (internalProgram.ToLowerInvariant())
|
||||
{
|
||||
// Dumping support
|
||||
case "aaru":
|
||||
case "chef":
|
||||
case "dichef":
|
||||
case "discimagechef":
|
||||
return InternalProgram.Aaru;
|
||||
case "creator":
|
||||
case "dic":
|
||||
case "dicreator":
|
||||
case "discimagecreator":
|
||||
return InternalProgram.DiscImageCreator;
|
||||
case "dd":
|
||||
return InternalProgram.DD;
|
||||
|
||||
// Verification support only
|
||||
case "cleanrip":
|
||||
case "cr":
|
||||
return InternalProgram.CleanRip;
|
||||
case "dc":
|
||||
case "dcd":
|
||||
case "dcdumper":
|
||||
return InternalProgram.DCDumper;
|
||||
case "uic":
|
||||
case "umd":
|
||||
case "umdcreator":
|
||||
case "umdimagecreator":
|
||||
return InternalProgram.UmdImageCreator;
|
||||
|
||||
default:
|
||||
return InternalProgram.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the MediaType enum value for a given string
|
||||
/// </summary>
|
||||
/// <param name="type">String value to convert</param>
|
||||
/// <returns>MediaType represented by the string, if possible</returns>
|
||||
public static MediaType ToMediaType(string type)
|
||||
{
|
||||
switch (type.ToLowerInvariant())
|
||||
{
|
||||
#region Punched Media
|
||||
|
||||
case "aperture":
|
||||
case "aperturecard":
|
||||
case "aperture card":
|
||||
return MediaType.ApertureCard;
|
||||
case "jacquardloom":
|
||||
case "jacquardloomcard":
|
||||
case "jacquard loom card":
|
||||
return MediaType.JacquardLoomCard;
|
||||
case "magneticstripe":
|
||||
case "magneticstripecard":
|
||||
case "magnetic stripe card":
|
||||
return MediaType.MagneticStripeCard;
|
||||
case "opticalphone":
|
||||
case "opticalphonecard":
|
||||
case "optical phonecard":
|
||||
return MediaType.OpticalPhonecard;
|
||||
case "punchcard":
|
||||
case "punchedcard":
|
||||
case "punched card":
|
||||
return MediaType.PunchedCard;
|
||||
case "punchtape":
|
||||
case "punchedtape":
|
||||
case "punched tape":
|
||||
return MediaType.PunchedTape;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Tape
|
||||
|
||||
case "openreel":
|
||||
case "openreeltape":
|
||||
case "open reel tape":
|
||||
return MediaType.OpenReel;
|
||||
case "datacart":
|
||||
case "datacartridge":
|
||||
case "datatapecartridge":
|
||||
case "data tape cartridge":
|
||||
return MediaType.DataCartridge;
|
||||
case "cassette":
|
||||
case "cassettetape":
|
||||
case "cassette tape":
|
||||
return MediaType.Cassette;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Disc / Disc
|
||||
|
||||
case "bd":
|
||||
case "bdrom":
|
||||
case "bd-rom":
|
||||
case "bluray":
|
||||
return MediaType.BluRay;
|
||||
case "cd":
|
||||
case "cdrom":
|
||||
case "cd-rom":
|
||||
return MediaType.CDROM;
|
||||
case "dvd":
|
||||
case "dvd5":
|
||||
case "dvd-5":
|
||||
case "dvd9":
|
||||
case "dvd-9":
|
||||
case "dvdrom":
|
||||
case "dvd-rom":
|
||||
return MediaType.DVD;
|
||||
case "fd":
|
||||
case "floppy":
|
||||
case "floppydisk":
|
||||
case "floppy disk":
|
||||
case "floppy diskette":
|
||||
return MediaType.FloppyDisk;
|
||||
case "floptical":
|
||||
return MediaType.Floptical;
|
||||
case "gd":
|
||||
case "gdrom":
|
||||
case "gd-rom":
|
||||
return MediaType.GDROM;
|
||||
case "hddvd":
|
||||
case "hd-dvd":
|
||||
case "hddvdrom":
|
||||
case "hd-dvd-rom":
|
||||
return MediaType.HDDVD;
|
||||
case "hdd":
|
||||
case "harddisk":
|
||||
case "hard disk":
|
||||
return MediaType.HardDisk;
|
||||
case "bernoullidisk":
|
||||
case "iomegabernoullidisk":
|
||||
case "bernoulli disk":
|
||||
case "iomega bernoulli disk":
|
||||
return MediaType.IomegaBernoulliDisk;
|
||||
case "jaz":
|
||||
case "iomegajaz":
|
||||
case "iomega jaz":
|
||||
return MediaType.IomegaJaz;
|
||||
case "zip":
|
||||
case "zipdisk":
|
||||
case "iomegazip":
|
||||
case "iomega zip":
|
||||
return MediaType.IomegaZip;
|
||||
case "ldrom":
|
||||
case "lvrom":
|
||||
case "ld-rom":
|
||||
case "lv-rom":
|
||||
case "laserdisc":
|
||||
case "laservision":
|
||||
case "ld-rom / lv-rom":
|
||||
return MediaType.LaserDisc;
|
||||
case "64dd":
|
||||
case "n64dd":
|
||||
case "64dddisk":
|
||||
case "n64dddisk":
|
||||
case "64dd disk":
|
||||
case "n64dd disk":
|
||||
return MediaType.Nintendo64DD;
|
||||
case "fds":
|
||||
case "famicom":
|
||||
case "nfds":
|
||||
case "nintendofamicom":
|
||||
case "famicomdisksystem":
|
||||
case "famicom disk system":
|
||||
case "famicom disk system disk":
|
||||
return MediaType.NintendoFamicomDiskSystem;
|
||||
case "gc":
|
||||
case "gamecube":
|
||||
case "nintendogamecube":
|
||||
case "nintendo gamecube":
|
||||
case "gamecube disc":
|
||||
case "gamecube game disc":
|
||||
return MediaType.NintendoGameCubeGameDisc;
|
||||
case "wii":
|
||||
case "nintendowii":
|
||||
case "nintendo wii":
|
||||
case "nintendo wii disc":
|
||||
case "wii optical disc":
|
||||
return MediaType.NintendoWiiOpticalDisc;
|
||||
case "wiiu":
|
||||
case "nintendowiiu":
|
||||
case "nintendo wiiu":
|
||||
case "nintendo wiiu disc":
|
||||
case "wiiu optical disc":
|
||||
case "wii u optical disc":
|
||||
return MediaType.NintendoWiiUOpticalDisc;
|
||||
case "umd":
|
||||
return MediaType.UMD;
|
||||
|
||||
#endregion
|
||||
|
||||
// Unsorted Formats
|
||||
case "cartridge":
|
||||
return MediaType.Cartridge;
|
||||
case "ced":
|
||||
case "rcaced":
|
||||
case "rca ced":
|
||||
case "videodisc":
|
||||
case "rca videodisc":
|
||||
return MediaType.CED;
|
||||
|
||||
default:
|
||||
return MediaType.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.Data
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Constant values for UI
|
||||
@@ -16,10 +17,10 @@ namespace MPF.Data
|
||||
public static readonly byte[] SaturnSectorZeroStart = new byte[] { 0x53, 0x45, 0x47, 0x41, 0x20, 0x53, 0x45, 0x47, 0x41, 0x53, 0x41, 0x54, 0x55, 0x52, 0x4E, 0x20 };
|
||||
|
||||
// Private lists of known drive speed ranges
|
||||
private static IReadOnlyList<int> cd { get; } = new List<int> { 1, 2, 3, 4, 6, 8, 12, 16, 20, 24, 32, 40, 44, 48, 52, 56, 72 };
|
||||
private static IReadOnlyList<int> dvd { get; } = cd.Where(s => s <= 24).ToList();
|
||||
private static IReadOnlyList<int> bd { get; } = cd.Where(s => s <= 16).ToList();
|
||||
private static IReadOnlyList<int> unknown { get; } = new List<int> { 1 };
|
||||
private static IReadOnlyList<int> CD { get; } = new List<int> { 1, 2, 3, 4, 6, 8, 12, 16, 20, 24, 32, 40, 44, 48, 52, 56, 72 };
|
||||
private static IReadOnlyList<int> DVD { get; } = CD.Where(s => s <= 24).ToList();
|
||||
private static IReadOnlyList<int> BD { get; } = CD.Where(s => s <= 16).ToList();
|
||||
private static IReadOnlyList<int> Unknown { get; } = new List<int> { 1 };
|
||||
|
||||
/// <summary>
|
||||
/// Get list of all drive speeds for a given MediaType
|
||||
@@ -32,16 +33,16 @@ namespace MPF.Data
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
case MediaType.GDROM:
|
||||
return cd;
|
||||
return CD;
|
||||
case MediaType.DVD:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
return dvd;
|
||||
return DVD;
|
||||
case MediaType.BluRay:
|
||||
return bd;
|
||||
return BD;
|
||||
default:
|
||||
return unknown;
|
||||
return Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -99,11 +100,7 @@ namespace MPF.Data
|
||||
public const string PlayStationEDCField = "EDC";
|
||||
public const string PlayStationAntiModchipField = "Anti-modchip";
|
||||
public const string PlayStationLibCryptField = "LibCrypt";
|
||||
public const string XBOXDMIHash = "DMI.bin Hashes";
|
||||
public const string XBOXPFIHash = "PFI.bin Hashes";
|
||||
public const string XBOXSSHash = "SS.bin Hashes";
|
||||
public const string XBOXSSRanges = "Security Sector Ranges";
|
||||
public const string XBOXSSVersion = "Security Sector Version";
|
||||
|
||||
// Default values
|
||||
|
||||
484
MPF.Core/Data/Drive.cs
Normal file
484
MPF.Core/Data/Drive.cs
Normal file
@@ -0,0 +1,484 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Management;
|
||||
using MPF.Core.Converters;
|
||||
using MPF.Core.Utilities;
|
||||
using RedumpLib.Data;
|
||||
#if NET_FRAMEWORK
|
||||
using IMAPI2;
|
||||
#else
|
||||
using Aaru.CommonTypes.Enums;
|
||||
using AaruDevices = Aaru.Devices;
|
||||
#endif
|
||||
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents information for a single drive
|
||||
/// </summary>
|
||||
public class Drive
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents drive type
|
||||
/// </summary>
|
||||
public InternalDriveType? InternalDriveType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Drive partition format
|
||||
/// </summary>
|
||||
public string DriveFormat => driveInfo?.DriveFormat;
|
||||
|
||||
/// <summary>
|
||||
/// Windows drive letter
|
||||
/// </summary>
|
||||
public char Letter => driveInfo?.Name[0] ?? '\0';
|
||||
|
||||
/// <summary>
|
||||
/// Windows drive path
|
||||
/// </summary>
|
||||
public string Name => driveInfo?.Name;
|
||||
|
||||
/// <summary>
|
||||
/// Represents if Windows has marked the drive as active
|
||||
/// </summary>
|
||||
public bool MarkedActive => driveInfo?.IsReady ?? false;
|
||||
|
||||
/// <summary>
|
||||
/// Media label as read by Windows
|
||||
/// </summary>
|
||||
/// <remarks>The try/catch is needed because Windows will throw an exception if the drive is not marked as active</remarks>
|
||||
public string VolumeLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return driveInfo?.VolumeLabel;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media label as read by Windows, formatted to avoid odd outputs
|
||||
/// </summary>
|
||||
public string FormattedVolumeLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
string volumeLabel = Template.DiscNotDetected;
|
||||
if (driveInfo.IsReady)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(driveInfo.VolumeLabel))
|
||||
volumeLabel = "track";
|
||||
else
|
||||
volumeLabel = driveInfo.VolumeLabel;
|
||||
}
|
||||
|
||||
foreach (char c in Path.GetInvalidFileNameChars())
|
||||
volumeLabel = volumeLabel.Replace(c, '_');
|
||||
|
||||
return volumeLabel;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DriveInfo object representing the drive, if possible
|
||||
/// </summary>
|
||||
private readonly DriveInfo driveInfo;
|
||||
|
||||
public Drive(InternalDriveType? driveType, DriveInfo driveInfo)
|
||||
{
|
||||
this.InternalDriveType = driveType;
|
||||
this.driveInfo = driveInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a list of active drives matched to their volume labels
|
||||
/// </summary>
|
||||
/// <param name="ignoreFixedDrives">Ture to ignore fixed drives from population, false otherwise</param>
|
||||
/// <returns>Active drives, matched to labels, if possible</returns>
|
||||
/// <remarks>
|
||||
/// https://stackoverflow.com/questions/3060796/how-to-distinguish-between-usb-and-floppy-devices?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
|
||||
/// https://msdn.microsoft.com/en-us/library/aa394173(v=vs.85).aspx
|
||||
/// </remarks>
|
||||
public static List<Drive> CreateListOfDrives(bool ignoreFixedDrives)
|
||||
{
|
||||
var desiredDriveTypes = new List<DriveType>() { DriveType.CDRom };
|
||||
if (!ignoreFixedDrives)
|
||||
{
|
||||
desiredDriveTypes.Add(DriveType.Fixed);
|
||||
desiredDriveTypes.Add(DriveType.Removable);
|
||||
}
|
||||
|
||||
// Get all supported drive types
|
||||
var drives = DriveInfo.GetDrives()
|
||||
.Where(d => desiredDriveTypes.Contains(d.DriveType))
|
||||
.Select(d => new Drive(EnumConverter.ToInternalDriveType(d.DriveType), d))
|
||||
.ToList();
|
||||
|
||||
// TODO: Management searcher stuff is not supported on other platforms
|
||||
// Get the floppy drives and set the flag from removable
|
||||
try
|
||||
{
|
||||
ManagementObjectSearcher searcher =
|
||||
new ManagementObjectSearcher("root\\CIMV2",
|
||||
"SELECT * FROM Win32_LogicalDisk");
|
||||
|
||||
var collection = searcher.Get();
|
||||
foreach (ManagementObject queryObj in collection)
|
||||
{
|
||||
uint? mediaType = (uint?)queryObj["MediaType"];
|
||||
if (mediaType != null && ((mediaType > 0 && mediaType < 11) || (mediaType > 12 && mediaType < 22)))
|
||||
{
|
||||
char devId = queryObj["DeviceID"].ToString()[0];
|
||||
drives.ForEach(d => { if (d.Letter == devId) { d.InternalDriveType = Data.InternalDriveType.Floppy; } });
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// No-op
|
||||
}
|
||||
|
||||
// Order the drives by drive letter
|
||||
drives = drives.OrderBy(i => i.Letter).ToList();
|
||||
|
||||
return drives;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current media type from drive letter
|
||||
/// </summary>
|
||||
/// <param name="drive"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This may eventually be replaced by Aaru.Devices being able to be about 10x more accurate.
|
||||
/// This will also end up making it so that IMAPI2 is no longer necessary. Unfortunately, that
|
||||
/// will only work for .NET Core 3.1 and beyond.
|
||||
/// </remarks>
|
||||
public (MediaType?, string) GetMediaType()
|
||||
{
|
||||
// Take care of the non-optical stuff first
|
||||
// TODO: See if any of these can be more granular, like Optical is
|
||||
if (this.InternalDriveType == Data.InternalDriveType.Floppy)
|
||||
return (MediaType.FloppyDisk, null);
|
||||
else if (this.InternalDriveType == Data.InternalDriveType.HardDisk)
|
||||
return (MediaType.HardDisk, null);
|
||||
else if (this.InternalDriveType == Data.InternalDriveType.Removable)
|
||||
return (MediaType.FlashDrive, null);
|
||||
|
||||
#if NET_FRAMEWORK
|
||||
// Get the current drive information
|
||||
string deviceId = null;
|
||||
bool loaded = false;
|
||||
try
|
||||
{
|
||||
// Get the device ID first
|
||||
var searcher = new ManagementObjectSearcher(
|
||||
"root\\CIMV2",
|
||||
$"SELECT * FROM Win32_CDROMDrive WHERE Id = '{this.Letter}:\'");
|
||||
|
||||
foreach (ManagementObject queryObj in searcher.Get())
|
||||
{
|
||||
deviceId = (string)queryObj["DeviceID"];
|
||||
loaded = (bool)queryObj["MediaLoaded"];
|
||||
}
|
||||
|
||||
// If we got no valid device, we don't care and just return
|
||||
if (deviceId == null)
|
||||
return (null, "Device could not be found");
|
||||
else if (!loaded)
|
||||
return (null, "Device is not reporting media loaded");
|
||||
|
||||
MsftDiscMaster2 discMaster = new MsftDiscMaster2();
|
||||
deviceId = deviceId.ToLower().Replace('\\', '#').Replace('/', '#');
|
||||
string id = null;
|
||||
foreach (var disc in discMaster)
|
||||
{
|
||||
if (disc.ToString().Contains(deviceId))
|
||||
id = disc.ToString();
|
||||
}
|
||||
|
||||
// If we couldn't find the drive, we don't care and return
|
||||
if (id == null)
|
||||
return (null, "Device ID could not be found");
|
||||
|
||||
// Create the required objects for reading from the drive
|
||||
MsftDiscRecorder2 recorder = new MsftDiscRecorder2();
|
||||
recorder.InitializeDiscRecorder(id);
|
||||
MsftDiscFormat2Data dataWriter = new MsftDiscFormat2Data();
|
||||
|
||||
// If the recorder is not supported, just return
|
||||
if (!dataWriter.IsRecorderSupported(recorder))
|
||||
return (null, "IMAPI2 recorder not supported");
|
||||
|
||||
// Otherwise, set the recorder to get information from
|
||||
dataWriter.Recorder = recorder;
|
||||
|
||||
var media = dataWriter.CurrentPhysicalMediaType;
|
||||
return (media.IMAPIToMediaType(), null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (null, ex.Message);
|
||||
}
|
||||
#else
|
||||
try
|
||||
{
|
||||
var device = new AaruDevices.Device(this.Name);
|
||||
if (device.Error)
|
||||
return (null, "Could not open device");
|
||||
else if (device.Type != DeviceType.ATAPI && device.Type != DeviceType.SCSI)
|
||||
return (null, "Device does not support media type detection");
|
||||
|
||||
// TODO: In order to get the disc type, Aaru.Core will need to be included as a
|
||||
// package. Unfortunately, it currently has a conflict with one of the required libraries:
|
||||
// System.Text.Encoding.CodePages (BOS uses >= 5.0.0, DotNetZip uses >= 4.5.0 && < 5.0.0)
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (null, ex.Message);
|
||||
}
|
||||
|
||||
return (null, "Media detection only supported on .NET Framework");
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current system from drive
|
||||
/// </summary>
|
||||
/// <param name="defaultValue"></param>
|
||||
/// <returns></returns>
|
||||
public RedumpSystem? GetRedumpSystem(RedumpSystem? defaultValue)
|
||||
{
|
||||
string drivePath = $"{this.Letter}:\\";
|
||||
|
||||
// If we can't read the media in that drive, we can't do anything
|
||||
if (!Directory.Exists(drivePath))
|
||||
return defaultValue;
|
||||
|
||||
// We're going to assume for floppies, HDDs, and removable drives
|
||||
// TODO: Try to be smarter about this
|
||||
if (this.InternalDriveType != Data.InternalDriveType.Optical)
|
||||
return RedumpSystem.IBMPCcompatible;
|
||||
|
||||
// Check volume labels first
|
||||
RedumpSystem? systemFromLabel = GetRedumpSystemFromVolumeLabel();
|
||||
if (systemFromLabel != null)
|
||||
return systemFromLabel;
|
||||
|
||||
#region Consoles
|
||||
|
||||
// Microsoft Xbox 360
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(drivePath, "$SystemUpdate"))
|
||||
&& Directory.EnumerateFiles(Path.Combine(drivePath, "$SystemUpdate")).Any())
|
||||
{
|
||||
return RedumpSystem.MicrosoftXbox360;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Sega Dreamcast
|
||||
if (File.Exists(Path.Combine(drivePath, "IP.BIN")))
|
||||
{
|
||||
return RedumpSystem.SegaDreamcast;
|
||||
}
|
||||
|
||||
// Sega Mega-CD / Sega-CD
|
||||
if (File.Exists(Path.Combine(drivePath, "_BOOT", "IP.BIN"))
|
||||
|| File.Exists(Path.Combine(drivePath, "_BOOT", "SP.BIN"))
|
||||
|| File.Exists(Path.Combine(drivePath, "_BOOT", "SP_AS.BIN"))
|
||||
|| File.Exists(Path.Combine(drivePath, "FILESYSTEM.BIN")))
|
||||
{
|
||||
return RedumpSystem.SegaMegaCDSegaCD;
|
||||
}
|
||||
|
||||
// Sega Saturn
|
||||
try
|
||||
{
|
||||
byte[] sector = ReadSector(0);
|
||||
if (sector != null)
|
||||
{
|
||||
if (sector.StartsWith(Interface.SaturnSectorZeroStart))
|
||||
return RedumpSystem.SegaSaturn;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Sony PlayStation and Sony PlayStation 2
|
||||
string psxExePath = Path.Combine(drivePath, "PSX.EXE");
|
||||
string systemCnfPath = Path.Combine(drivePath, "SYSTEM.CNF");
|
||||
if (File.Exists(systemCnfPath))
|
||||
{
|
||||
// Check for either BOOT or BOOT2
|
||||
var systemCnf = new IniFile(systemCnfPath);
|
||||
if (systemCnf.ContainsKey("BOOT"))
|
||||
return RedumpSystem.SonyPlayStation;
|
||||
else if (systemCnf.ContainsKey("BOOT2"))
|
||||
return RedumpSystem.SonyPlayStation2;
|
||||
}
|
||||
else if (File.Exists(psxExePath))
|
||||
{
|
||||
return RedumpSystem.SonyPlayStation;
|
||||
}
|
||||
|
||||
// V.Tech V.Flash / V.Smile Pro
|
||||
if (File.Exists(Path.Combine(drivePath, "0SYSTEM")))
|
||||
{
|
||||
return RedumpSystem.VTechVFlashVSmilePro;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Video Formats
|
||||
|
||||
// BD-Video
|
||||
if (Directory.Exists(Path.Combine(drivePath, "BDMV")))
|
||||
{
|
||||
// Technically BD-Audio has this as well, but it's hard to split that out right now
|
||||
return RedumpSystem.BDVideo;
|
||||
}
|
||||
|
||||
// DVD-Audio and DVD-Video
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(drivePath, "AUDIO_TS"))
|
||||
&& Directory.EnumerateFiles(Path.Combine(drivePath, "AUDIO_TS")).Any())
|
||||
{
|
||||
return RedumpSystem.DVDAudio;
|
||||
}
|
||||
|
||||
else if (Directory.Exists(Path.Combine(drivePath, "VIDEO_TS"))
|
||||
&& Directory.EnumerateFiles(Path.Combine(drivePath, "VIDEO_TS")).Any())
|
||||
{
|
||||
return RedumpSystem.DVDVideo;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// HD-DVD-Video
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(drivePath, "HVDVD_TS"))
|
||||
&& Directory.EnumerateFiles(Path.Combine(drivePath, "HVDVD_TS")).Any())
|
||||
{
|
||||
return RedumpSystem.HDDVDVideo;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// VCD
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(drivePath, "VCD"))
|
||||
&& Directory.EnumerateFiles(Path.Combine(drivePath, "VCD")).Any())
|
||||
{
|
||||
return RedumpSystem.VideoCD;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
#endregion
|
||||
|
||||
// Default return
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current system from the drive volume label
|
||||
/// </summary>
|
||||
/// <returns>The system based on volume label, null if none detected</returns>
|
||||
public RedumpSystem? GetRedumpSystemFromVolumeLabel()
|
||||
{
|
||||
// If the volume label is empty, we can't do anything
|
||||
if (string.IsNullOrWhiteSpace(this.VolumeLabel))
|
||||
return null;
|
||||
|
||||
// Audio CD
|
||||
if (this.VolumeLabel.Equals("Audio CD", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.AudioCD;
|
||||
|
||||
// Microsoft Xbox
|
||||
if (this.VolumeLabel.Equals("SEP13011042", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.MicrosoftXbox;
|
||||
else if (this.VolumeLabel.Equals("SEP13011042072", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.MicrosoftXbox;
|
||||
|
||||
// Microsoft Xbox 360
|
||||
if (this.VolumeLabel.Equals("XBOX360", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.MicrosoftXbox360;
|
||||
else if (this.VolumeLabel.Equals("XGD2DVD_NTSC", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.MicrosoftXbox360;
|
||||
|
||||
// Microsoft Xbox 360 - Too overly broad even if a lot of discs use this
|
||||
//if (this.VolumeLabel.Equals("CD_ROM", StringComparison.OrdinalIgnoreCase))
|
||||
// return RedumpSystem.MicrosoftXbox360; // Also for Xbox One?
|
||||
//if (this.VolumeLabel.Equals("DVD_ROM", StringComparison.OrdinalIgnoreCase))
|
||||
// return RedumpSystem.MicrosoftXbox360;
|
||||
|
||||
// Sony PlayStation 3
|
||||
if (this.VolumeLabel.Equals("PS3VOLUME", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.SonyPlayStation3;
|
||||
|
||||
// Sony PlayStation 4
|
||||
if (this.VolumeLabel.Equals("PS4VOLUME", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.SonyPlayStation4;
|
||||
|
||||
// Sony PlayStation 5
|
||||
if (this.VolumeLabel.Equals("PS5VOLUME", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.SonyPlayStation5;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a sector with a specified size from the drive
|
||||
/// </summary>
|
||||
/// <param name="num">Sector number, non-negative</param>
|
||||
/// <param name="size">Size of a sector in bytes</param>
|
||||
/// <returns>Byte array representing the sector, null on error</returns>
|
||||
public byte[] ReadSector(long num, int size = 2048)
|
||||
{
|
||||
// Missing drive leter is not supported
|
||||
if (string.IsNullOrEmpty(this.driveInfo?.Name))
|
||||
return null;
|
||||
|
||||
// We don't support negative sectors
|
||||
if (num < 0)
|
||||
return null;
|
||||
|
||||
// Wrap the following in case of device access errors
|
||||
Stream fs = null;
|
||||
try
|
||||
{
|
||||
// Open the drive as a device
|
||||
fs = File.OpenRead($"\\\\?\\{this.Letter}:");
|
||||
|
||||
// Seek to the start of the sector, if possible
|
||||
long start = num * size;
|
||||
fs.Seek(start, SeekOrigin.Begin);
|
||||
|
||||
// Read and return the sector
|
||||
byte[] buffer = new byte[size];
|
||||
fs.Read(buffer, 0, size);
|
||||
return buffer;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
fs?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
31
MPF.Core/Data/Enumerations.cs
Normal file
31
MPF.Core/Data/Enumerations.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Drive type for dumping
|
||||
/// </summary>
|
||||
public enum InternalDriveType
|
||||
{
|
||||
Optical,
|
||||
Floppy,
|
||||
HardDisk,
|
||||
Removable,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Program that is being used to dump media
|
||||
/// </summary>
|
||||
public enum InternalProgram
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
// Dumping support
|
||||
Aaru,
|
||||
DD,
|
||||
DiscImageCreator,
|
||||
|
||||
// Verification support only
|
||||
CleanRip,
|
||||
DCDumper,
|
||||
UmdImageCreator,
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace MPF.Data
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
public class IniFile : IDictionary<string, string>
|
||||
{
|
||||
@@ -1,14 +1,14 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MPF.Utilities;
|
||||
using MPF.Core.Converters;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.Data
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
public class Options : IDictionary<string, string>, ICloneable
|
||||
{
|
||||
private Dictionary<string, string> _settings;
|
||||
private readonly Dictionary<string, string> _settings;
|
||||
|
||||
#region Internal Program
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace MPF.Data
|
||||
get
|
||||
{
|
||||
string valueString = GetStringSetting(_settings, "InternalProgram", InternalProgram.DiscImageCreator.ToString());
|
||||
var valueEnum = Converters.ToInternalProgram(valueString);
|
||||
var valueEnum = EnumConverter.ToInternalProgram(valueString);
|
||||
return valueEnum == InternalProgram.NONE ? InternalProgram.DiscImageCreator : valueEnum;
|
||||
}
|
||||
set
|
||||
@@ -69,6 +69,15 @@ namespace MPF.Data
|
||||
set { _settings["EnableDarkMode"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check for updates on startup
|
||||
/// </summary>
|
||||
public bool CheckForUpdatesOnStartup
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "CheckForUpdatesOnStartup", true); }
|
||||
set { _settings["CheckForUpdatesOnStartup"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default output path for dumps
|
||||
/// </summary>
|
||||
@@ -81,20 +90,30 @@ namespace MPF.Data
|
||||
/// <summary>
|
||||
/// Default system if none can be detected
|
||||
/// </summary>
|
||||
public KnownSystem DefaultSystem
|
||||
public RedumpSystem? DefaultSystem
|
||||
{
|
||||
get
|
||||
{
|
||||
string valueString = GetStringSetting(_settings, "DefaultSystem", KnownSystem.NONE.ToString());
|
||||
var valueEnum = Converters.ToKnownSystem(valueString);
|
||||
return valueEnum ?? KnownSystem.NONE;
|
||||
string valueString = GetStringSetting(_settings, "DefaultSystem", null);
|
||||
var valueEnum = Extensions.ToRedumpSystem(valueString);
|
||||
return valueEnum;
|
||||
}
|
||||
set
|
||||
{
|
||||
_settings["DefaultSystem"] = Converters.GetLongName(value);
|
||||
_settings["DefaultSystem"] = value.LongName();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default output path for dumps
|
||||
/// </summary>
|
||||
/// <remarks>This is a hidden setting</remarks>
|
||||
public bool ShowDebugViewMenuItem
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "ShowDebugViewMenuItem", false); }
|
||||
set { _settings["ShowDebugViewMenuItem"] = value.ToString(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dumping Speeds
|
||||
@@ -260,6 +279,24 @@ namespace MPF.Data
|
||||
set { _settings["PromptForDiscInformation"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable tabs in all input fields
|
||||
/// </summary>
|
||||
public bool EnableTabsInInputFields
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "EnableTabsInInputFields", false); }
|
||||
set { _settings["EnableTabsInInputFields"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show disc eject reminder before the disc information window is shown
|
||||
/// </summary>
|
||||
public bool ShowDiscEjectReminder
|
||||
{
|
||||
get { return GetBooleanSetting(_settings, "ShowDiscEjectReminder", true); }
|
||||
set { _settings["ShowDiscEjectReminder"] = value.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Eject the disc after dumping
|
||||
/// </summary>
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MPF.Data
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
public class ProcessingQueue<T> : IDisposable
|
||||
{
|
||||
@@ -33,10 +33,7 @@ namespace MPF.Data
|
||||
/// <summary>
|
||||
/// Dispose the current instance
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.TokenSource.Cancel();
|
||||
}
|
||||
public void Dispose() => this.TokenSource.Cancel();
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue a new item for processing
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace MPF.Data
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Generic success/failure result object, with optional message
|
||||
423
MPF.Core/Data/XgdInfo.cs
Normal file
423
MPF.Core/Data/XgdInfo.cs
Normal file
@@ -0,0 +1,423 @@
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains information specific to an XGD disc
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// XGD1 XMID Format Information:
|
||||
///
|
||||
/// AABBBCCD
|
||||
/// - AA => The two-ASCII-character publisher identifier (see GetPublisher for details)
|
||||
/// - BBB => Game ID
|
||||
/// - CC => Version number
|
||||
/// - D => Region identifier (see GetRegion for details)
|
||||
///
|
||||
/// XGD2/3 XeMID Format Information:
|
||||
///
|
||||
/// AABCCCDDEFFGHH(IIIIIIII)
|
||||
/// - AA => The two-ASCII-character publisher identifier (see GetPublisher for details)
|
||||
/// - B => Platform identifier; 2 indicates Xbox 360.
|
||||
/// - CCC => Game ID
|
||||
/// - DD => SKU number (unique per SKU of a title)
|
||||
/// - E => Region identifier (see GetRegion for details)
|
||||
/// - FF => Base version; usually starts at 01 (can be 1 or 2 characters)
|
||||
/// - G => Media type identifier (see GetMediaSubtype for details)
|
||||
/// - HH => Disc number stored in [disc number][total discs] format
|
||||
/// - IIIIIIII => 8-hex-digit certification submission identifier; usually on test discs only
|
||||
/// </remarks>
|
||||
public class XgdInfo
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the information in this object is fully instantiated or not
|
||||
/// </summary>
|
||||
public bool Initialized { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Raw XMID/XeMID string that all other information is derived from
|
||||
/// </summary>
|
||||
public string XMID { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 2-character publisher identifier
|
||||
/// </summary>
|
||||
public string PublisherIdentifier { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Platform disc is made for, 2 indicates Xbox 360
|
||||
/// </summary>
|
||||
public char? PlatformIdentifier { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Game ID
|
||||
/// </summary>
|
||||
public string GameID { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// For XGD1: Internal version number
|
||||
/// For XGD2/3: Title-specific SKU
|
||||
/// </summary>
|
||||
public string SKU { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Region identifier character
|
||||
/// </summary>
|
||||
public char RegionIdentifier { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Base version of executables, usually starts at 01
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// TODO: Check if this is always 2 characters for XGD2/3
|
||||
/// </remarks>
|
||||
public string BaseVersion { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Media subtype identifier
|
||||
/// </summary>
|
||||
public char MediaSubtypeIdentifier { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Disc number stored in [disc number][total discs] format
|
||||
/// </summary>
|
||||
public string DiscNumberIdentifier { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 8-hex-digit certification submission identifier; usually on test discs only
|
||||
/// </summary>
|
||||
public string CertificationSubmissionIdentifier { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Auto-Generated Information
|
||||
|
||||
/// <summary>
|
||||
/// Human-readable name derived from the publisher identifier
|
||||
/// </summary>
|
||||
public string PublisherName => GetPublisher(this.PublisherIdentifier);
|
||||
|
||||
/// <summary>
|
||||
/// Internally represented region
|
||||
/// </summary>
|
||||
public Region? InternalRegion => GetRegion(this.RegionIdentifier);
|
||||
|
||||
/// <summary>
|
||||
/// Human-readable subtype derived from the media identifier
|
||||
/// </summary>
|
||||
public string MediaSubtype => GetMediaSubtype(this.MediaSubtypeIdentifier);
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Populate a set of XGD information from a Master ID (XMID/XeMID) string
|
||||
/// </summary>
|
||||
/// <param name="xmid">XMID/XeMID string representing the DMI information</param>
|
||||
/// <param name="validate">True if value validation should be performed, false otherwise</param>
|
||||
public XgdInfo(string xmid, bool validate = false)
|
||||
{
|
||||
this.Initialized = false;
|
||||
if (string.IsNullOrWhiteSpace(xmid))
|
||||
return;
|
||||
|
||||
this.XMID = xmid.TrimEnd('\0');
|
||||
if (string.IsNullOrWhiteSpace(this.XMID))
|
||||
return;
|
||||
|
||||
// XGD1 information is 8 characters
|
||||
if (this.XMID.Length == 8)
|
||||
this.Initialized = ParseXGD1XMID(this.XMID, validate);
|
||||
|
||||
// XGD2/3 information is semi-variable length
|
||||
else if (this.XMID.Length == 13 || this.XMID.Length == 14 || this.XMID.Length == 21 || this.XMID.Length == 22)
|
||||
this.Initialized = ParseXGD23XeMID(this.XMID, validate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the human-readable serial string
|
||||
/// </summary>
|
||||
/// <returns>Formatted serial string, null on error</returns>
|
||||
public string GetSerial()
|
||||
{
|
||||
if (!this.Initialized)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
// XGD1 doesn't use PlatformIdentifier
|
||||
if (this.PlatformIdentifier == null)
|
||||
return $"{this.PublisherIdentifier}-{this.GameID}";
|
||||
|
||||
// XGD2/3 uses a specific identifier
|
||||
else if (this.PlatformIdentifier == '2')
|
||||
return $"{this.PublisherIdentifier}-{this.PlatformIdentifier}{this.GameID}";
|
||||
|
||||
return null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the human-readable version string
|
||||
/// </summary>
|
||||
/// <returns>Formatted version string, null on error</returns>
|
||||
/// <remarks>This may differ for XGD2/3 in the future</remarks>
|
||||
public string GetVersion()
|
||||
{
|
||||
if (!this.Initialized)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
// XGD1 doesn't use PlatformIdentifier
|
||||
if (this.PlatformIdentifier == null)
|
||||
return $"1.{this.SKU}";
|
||||
|
||||
// XGD2/3 uses a specific identifier
|
||||
else if (this.PlatformIdentifier == '2')
|
||||
return $"1.{this.SKU}";
|
||||
|
||||
return null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse an XGD1 XMID string
|
||||
/// </summary>
|
||||
/// <param name="xmid">XMID string to attempt to parse</param>
|
||||
/// <param name="validate">True if value validation should be performed, false otherwise</param>
|
||||
/// <returns>True if the XMID could be parsed, false otherwise</returns>
|
||||
private bool ParseXGD1XMID(string xmid, bool validate)
|
||||
{
|
||||
if (xmid == null || xmid.Length != 8)
|
||||
return false;
|
||||
|
||||
this.PublisherIdentifier = xmid.Substring(0, 2);
|
||||
if (validate && string.IsNullOrEmpty(this.PublisherName))
|
||||
return false;
|
||||
|
||||
this.GameID = xmid.Substring(2, 3);
|
||||
this.SKU = xmid.Substring(5, 2);
|
||||
this.RegionIdentifier = xmid[7];
|
||||
if (validate && this.InternalRegion == null)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse an XGD2/3 XeMID string
|
||||
/// </summary>
|
||||
/// <param name="xemid">XeMID string to attempt to parse</param>
|
||||
/// <param name="validate">True if value validation should be performed, false otherwise</param>
|
||||
/// <returns>True if the XeMID could be parsed, false otherwise</returns>
|
||||
private bool ParseXGD23XeMID(string xemid, bool validate)
|
||||
{
|
||||
if (xemid == null
|
||||
|| (xemid.Length != 13 && xemid.Length != 14
|
||||
&& xemid.Length != 21 && xemid.Length != 22))
|
||||
return false;
|
||||
|
||||
this.PublisherIdentifier = xemid.Substring(0, 2);
|
||||
if (validate && string.IsNullOrEmpty(this.PublisherName))
|
||||
return false;
|
||||
|
||||
this.PlatformIdentifier = xemid[2];
|
||||
if (validate && this.PlatformIdentifier != '2')
|
||||
return false;
|
||||
|
||||
this.GameID = xemid.Substring(3, 3);
|
||||
this.SKU = xemid.Substring(6, 2);
|
||||
this.RegionIdentifier = xemid[8];
|
||||
if (validate && this.InternalRegion == null)
|
||||
return false;
|
||||
|
||||
if (xemid.Length == 13 || xemid.Length == 21)
|
||||
{
|
||||
this.BaseVersion = xemid.Substring(9, 1);
|
||||
this.MediaSubtypeIdentifier = xemid[10];
|
||||
if (validate && string.IsNullOrEmpty(this.MediaSubtype))
|
||||
return false;
|
||||
|
||||
this.DiscNumberIdentifier = xemid.Substring(11, 2);
|
||||
}
|
||||
else if (xemid.Length == 14 || xemid.Length == 22)
|
||||
{
|
||||
this.BaseVersion = xemid.Substring(9, 2);
|
||||
this.MediaSubtypeIdentifier = xemid[11];
|
||||
if (validate && string.IsNullOrEmpty(this.MediaSubtype))
|
||||
return false;
|
||||
|
||||
this.DiscNumberIdentifier = xemid.Substring(12, 2);
|
||||
}
|
||||
|
||||
if (xemid.Length == 21)
|
||||
this.CertificationSubmissionIdentifier = xemid.Substring(13);
|
||||
else if (xemid.Length == 22)
|
||||
this.CertificationSubmissionIdentifier = xemid.Substring(14);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Determine the XGD type based on the XGD2/3 media type identifier character
|
||||
/// </summary>
|
||||
/// <param name="mediaTypeIdentifier">Character denoting the media type</param>
|
||||
/// <returns>Media subtype as a string, if possible</returns>
|
||||
private static string GetMediaSubtype(char mediaTypeIdentifier)
|
||||
{
|
||||
switch (mediaTypeIdentifier)
|
||||
{
|
||||
case 'F': return "XGD3";
|
||||
case 'X': return "XGD2";
|
||||
case 'Z': return "Games on Demand / Marketplace Demo";
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the full name of the publisher from the 2-character identifier
|
||||
/// </summary>
|
||||
/// <param name="publisherIdentifier">Case-sensitive 2-character identifier</param>
|
||||
/// <returns>Publisher name, if possible</returns>
|
||||
/// <see cref="https://xboxdevwiki.net/Xbe#Title_ID"/>
|
||||
private static string GetPublisher(string publisherIdentifier)
|
||||
{
|
||||
switch (publisherIdentifier)
|
||||
{
|
||||
case "AC": return "Acclaim Entertainment";
|
||||
case "AH": return "ARUSH Entertainment";
|
||||
case "AQ": return "Aqua System";
|
||||
case "AS": return "ASK";
|
||||
case "AT": return "Atlus";
|
||||
case "AV": return "Activision";
|
||||
case "AY": return "Aspyr Media";
|
||||
case "BA": return "Bandai";
|
||||
case "BL": return "Black Box";
|
||||
case "BM": return "BAM! Entertainment";
|
||||
case "BR": return "Broccoli Co.";
|
||||
case "BS": return "Bethesda Softworks";
|
||||
case "BU": return "Bunkasha Co.";
|
||||
case "BV": return "Buena Vista Games";
|
||||
case "BW": return "BBC Multimedia";
|
||||
case "BZ": return "Blizzard";
|
||||
case "CC": return "Capcom";
|
||||
case "CK": return "Kemco Corporation"; // TODO: Confirm
|
||||
case "CM": return "Codemasters";
|
||||
case "CV": return "Crave Entertainment";
|
||||
case "DC": return "DreamCatcher Interactive";
|
||||
case "DX": return "Davilex";
|
||||
case "EA": return "Electronic Arts (EA)";
|
||||
case "EC": return "Encore inc";
|
||||
case "EL": return "Enlight Software";
|
||||
case "EM": return "Empire Interactive";
|
||||
case "ES": return "Eidos Interactive";
|
||||
case "FI": return "Fox Interactive";
|
||||
case "FS": return "From Software";
|
||||
case "GE": return "Genki Co.";
|
||||
case "GV": return "Groove Games";
|
||||
case "HE": return "Tru Blu (Entertainment division of Home Entertainment Suppliers)";
|
||||
case "HP": return "Hip games";
|
||||
case "HU": return "Hudson Soft";
|
||||
case "HW": return "Highwaystar";
|
||||
case "IA": return "Mad Catz Interactive";
|
||||
case "IF": return "Idea Factory";
|
||||
case "IG": return "Infogrames";
|
||||
case "IL": return "Interlex Corporation";
|
||||
case "IM": return "Imagine Media";
|
||||
case "IO": return "Ignition Entertainment";
|
||||
case "IP": return "Interplay Entertainment";
|
||||
case "IX": return "InXile Entertainment"; // TODO: Confirm
|
||||
case "JA": return "Jaleco";
|
||||
case "JW": return "JoWooD";
|
||||
case "KB": return "Kemco"; // TODO: Confirm
|
||||
case "KI": return "Kids Station Inc."; // TODO: Confirm
|
||||
case "KN": return "Konami";
|
||||
case "KO": return "KOEI";
|
||||
case "KU": return "Kobi and / or GAE (formerly Global A Entertainment)"; // TODO: Confirm
|
||||
case "LA": return "LucasArts";
|
||||
case "LS": return "Black Bean Games (publishing arm of Leader S.p.A.)";
|
||||
case "MD": return "Metro3D";
|
||||
case "ME": return "Medix";
|
||||
case "MI": return "Microïds";
|
||||
case "MJ": return "Majesco Entertainment";
|
||||
case "MM": return "Myelin Media";
|
||||
case "MP": return "MediaQuest"; // TODO: Confirm
|
||||
case "MS": return "Microsoft Game Studios";
|
||||
case "MW": return "Midway Games";
|
||||
case "MX": return "Empire Interactive"; // TODO: Confirm
|
||||
case "NK": return "NewKidCo";
|
||||
case "NL": return "NovaLogic";
|
||||
case "NM": return "Namco";
|
||||
case "OX": return "Oxygen Interactive";
|
||||
case "PC": return "Playlogic Entertainment";
|
||||
case "PL": return "Phantagram Co., Ltd.";
|
||||
case "RA": return "Rage";
|
||||
case "SA": return "Sammy";
|
||||
case "SC": return "SCi Games";
|
||||
case "SE": return "SEGA";
|
||||
case "SN": return "SNK";
|
||||
case "SS": return "Simon & Schuster";
|
||||
case "SU": return "Success Corporation";
|
||||
case "SW": return "Swing! Deutschland";
|
||||
case "TA": return "Takara";
|
||||
case "TC": return "Tecmo";
|
||||
case "TD": return "The 3DO Company (or just 3DO)";
|
||||
case "TK": return "Takuyo";
|
||||
case "TM": return "TDK Mediactive";
|
||||
case "TQ": return "THQ";
|
||||
case "TS": return "Titus Interactive";
|
||||
case "TT": return "Take-Two Interactive Software";
|
||||
case "US": return "Ubisoft";
|
||||
case "VC": return "Victor Interactive Software";
|
||||
case "VN": return "Vivendi Universal (just took Interplays publishing rights)"; // TODO: Confirm
|
||||
case "VU": return "Vivendi Universal Games";
|
||||
case "VV": return "Vivendi Universal Games"; // TODO: Confirm
|
||||
case "WE": return "Wanadoo Edition";
|
||||
case "WR": return "Warner Bros. Interactive Entertainment"; // TODO: Confirm
|
||||
case "XI": return "XPEC Entertainment and Idea Factory";
|
||||
case "XK": return "Xbox kiosk disk?"; // TODO: Confirm
|
||||
case "XL": return "Xbox special bundled or live demo disk?"; // TODO: Confirm
|
||||
case "XM": return "Evolved Games"; // TODO: Confirm
|
||||
case "XP": return "XPEC Entertainment";
|
||||
case "XR": return "Panorama";
|
||||
case "YB": return "YBM Sisa (South-Korea)";
|
||||
case "ZD": return "Zushi Games (formerly Zoo Digital Publishing)";
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine the region based on the XGD serial character
|
||||
/// </summary>
|
||||
/// <param name="region">Character denoting the region</param>
|
||||
/// <returns>Region, if possible</returns>
|
||||
private static Region? GetRegion(char region)
|
||||
{
|
||||
switch (region)
|
||||
{
|
||||
case 'W': return Region.World;
|
||||
case 'A': return Region.UnitedStatesOfAmerica;
|
||||
case 'J': return Region.JapanAsia;
|
||||
case 'E': return Region.Europe;
|
||||
case 'K': return Region.USAJapan;
|
||||
case 'L': return Region.USAEurope;
|
||||
case 'H': return Region.JapanEurope;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,27 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using MPF.Data;
|
||||
using OptimizedCRC;
|
||||
|
||||
namespace MPF.Hashing
|
||||
namespace MPF.Core.Hashing
|
||||
{
|
||||
/// <summary>
|
||||
/// Available hashing types
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum Hash
|
||||
{
|
||||
CRC = 1 << 0,
|
||||
MD5 = 1 << 1,
|
||||
SHA1 = 1 << 2,
|
||||
SHA256 = 1 << 3,
|
||||
SHA384 = 1 << 4,
|
||||
SHA512 = 1 << 5,
|
||||
|
||||
// Special combinations
|
||||
Standard = CRC | MD5 | SHA1,
|
||||
All = CRC | MD5 | SHA1 | SHA256 | SHA384 | SHA512,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Async hashing class wraper
|
||||
/// </summary>
|
||||
@@ -28,7 +44,7 @@ namespace MPF.Hashing
|
||||
switch (HashType)
|
||||
{
|
||||
case Hash.CRC:
|
||||
_hasher = new OptimizedCRC.OptimizedCRC();
|
||||
_hasher = new OptimizedCRC();
|
||||
break;
|
||||
|
||||
case Hash.MD5:
|
||||
@@ -66,7 +82,7 @@ namespace MPF.Hashing
|
||||
switch (HashType)
|
||||
{
|
||||
case Hash.CRC:
|
||||
(_hasher as OptimizedCRC.OptimizedCRC).Update(buffer, 0, size);
|
||||
(_hasher as OptimizedCRC).Update(buffer, 0, size);
|
||||
break;
|
||||
|
||||
case Hash.MD5:
|
||||
@@ -88,7 +104,7 @@ namespace MPF.Hashing
|
||||
switch (HashType)
|
||||
{
|
||||
case Hash.CRC:
|
||||
(_hasher as OptimizedCRC.OptimizedCRC).Update(emptyBuffer, 0, 0);
|
||||
(_hasher as OptimizedCRC).Update(emptyBuffer, 0, 0);
|
||||
break;
|
||||
|
||||
case Hash.MD5:
|
||||
@@ -109,7 +125,7 @@ namespace MPF.Hashing
|
||||
switch (HashType)
|
||||
{
|
||||
case Hash.CRC:
|
||||
return BitConverter.GetBytes((_hasher as OptimizedCRC.OptimizedCRC).Value).Reverse().ToArray();
|
||||
return BitConverter.GetBytes((_hasher as OptimizedCRC).Value).Reverse().ToArray();
|
||||
|
||||
case Hash.MD5:
|
||||
case Hash.SHA1:
|
||||
@@ -24,7 +24,8 @@
|
||||
|
||||
using System;
|
||||
|
||||
namespace OptimizedCRC
|
||||
//namespace OptimizedCRC
|
||||
namespace MPF.Core.Hashing
|
||||
{
|
||||
internal class OptimizedCRC : IDisposable
|
||||
{
|
||||
@@ -2,7 +2,8 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace Compress.ThreadReaders
|
||||
//namespace Compress.ThreadReaders
|
||||
namespace MPF.Core.Hashing
|
||||
{
|
||||
public class ThreadLoadBuffer : IDisposable
|
||||
{
|
||||
65
MPF.Core/MPF.Core.csproj
Normal file
65
MPF.Core/MPF.Core.csproj
Normal file
@@ -0,0 +1,65 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net48;netcoreapp3.1;net5.0</TargetFrameworks>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
|
||||
<Copyright>Copyright (c)2019-2021</Copyright>
|
||||
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
|
||||
<Version>2.3</Version>
|
||||
<AssemblyVersion>$(Version)</AssemblyVersion>
|
||||
<FileVersion>$(Version)</FileVersion>
|
||||
<IncludeSource>true</IncludeSource>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<NrtRevisionFormat>$(Version)-{chash:8}</NrtRevisionFormat>
|
||||
<NrtResolveSimpleAttributes>true</NrtResolveSimpleAttributes>
|
||||
<NrtShowRevision>false</NrtShowRevision>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)'=='net48'">
|
||||
<DefineConstants>NET_FRAMEWORK</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)'=='net48'">
|
||||
<COMReference Include="IMAPI2">
|
||||
<Guid>{2735412F-7F64-5B0F-8F00-5D77AFBE261E}</Guid>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>0</VersionMinor>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<Isolated>False</Isolated>
|
||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
<COMReference Include="IMAPI2FS">
|
||||
<Guid>{2C941FD0-975B-59BE-A960-9A2A262853A5}</Guid>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>0</VersionMinor>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<Isolated>False</Isolated>
|
||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RedumpLib\RedumpLib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="System.Management" Version="6.0.0-rc.1.21451.13" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)'!='net48'">
|
||||
<PackageReference Include="Aaru.Devices" Version="5.3.0-rc2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Management" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,12 +1,12 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace MPF.Utilities
|
||||
namespace MPF.Core.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Big endian reading overloads for BinaryReader
|
||||
/// </summary>
|
||||
internal static class BinaryReaderExtensions
|
||||
public static class BinaryReaderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads the specified number of bytes from the stream, starting from a specified point in the byte array.
|
||||
144
MPF.Core/Utilities/EnumExtensions.cs
Normal file
144
MPF.Core/Utilities/EnumExtensions.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.Core.Utilities
|
||||
{
|
||||
public static class EnumExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Determine if a system is okay if it's not detected by Windows
|
||||
/// </summary>
|
||||
/// <param name="system">RedumpSystem value to check</param>
|
||||
/// <returns>True if Windows show see a disc when dumping, false otherwise</returns>
|
||||
public static bool DetectedByWindows(this RedumpSystem? system)
|
||||
{
|
||||
switch (system)
|
||||
{
|
||||
case RedumpSystem.AmericanLaserGames3DO:
|
||||
case RedumpSystem.AppleMacintosh:
|
||||
case RedumpSystem.Atari3DO:
|
||||
case RedumpSystem.AtariJaguarCDInteractiveMultimediaSystem:
|
||||
case RedumpSystem.NewJatreCDi:
|
||||
case RedumpSystem.NintendoGameCube:
|
||||
case RedumpSystem.NintendoWii:
|
||||
case RedumpSystem.NintendoWiiU:
|
||||
case RedumpSystem.PhilipsCDi:
|
||||
case RedumpSystem.PhilipsCDiDigitalVideo:
|
||||
case RedumpSystem.Panasonic3DOInteractiveMultiplayer:
|
||||
case RedumpSystem.PanasonicM2:
|
||||
case RedumpSystem.PioneerLaserActive:
|
||||
case RedumpSystem.SuperAudioCD:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if the media supports drive speeds
|
||||
/// </summary>
|
||||
/// <param name="type">MediaType value to check</param>
|
||||
/// <returns>True if the media has variable dumping speeds, false otherwise</returns>
|
||||
public static bool DoesSupportDriveSpeed(this MediaType? type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
case MediaType.DVD:
|
||||
case MediaType.GDROM:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.BluRay:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if a system has reversed ringcodes
|
||||
/// </summary>
|
||||
/// <param name="system">RedumpSystem value to check</param>
|
||||
/// <returns>True if the system has reversed ringcodes, false otherwise</returns>
|
||||
public static bool HasReversedRingcodes(this RedumpSystem? system)
|
||||
{
|
||||
switch (system)
|
||||
{
|
||||
case RedumpSystem.SonyPlayStation2:
|
||||
case RedumpSystem.SonyPlayStation3:
|
||||
case RedumpSystem.SonyPlayStation4:
|
||||
//case RedumpSystem.SonyPlayStation5:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if a system is considered audio-only
|
||||
/// </summary>
|
||||
/// <param name="system">RedumpSystem value to check</param>
|
||||
/// <returns>True if the system is audio-only, false otherwise</returns>
|
||||
/// <remarks>
|
||||
/// Philips CD-i should NOT be in this list. It's being included until there's a
|
||||
/// reasonable distinction between CD-i and CD-i ready on the database side.
|
||||
/// </remarks>
|
||||
public static bool IsAudio(this RedumpSystem? system)
|
||||
{
|
||||
switch (system)
|
||||
{
|
||||
case RedumpSystem.AtariJaguarCDInteractiveMultimediaSystem:
|
||||
case RedumpSystem.AudioCD:
|
||||
case RedumpSystem.DVDAudio:
|
||||
case RedumpSystem.HasbroVideoNow:
|
||||
case RedumpSystem.HasbroVideoNowColor:
|
||||
case RedumpSystem.HasbroVideoNowJr:
|
||||
case RedumpSystem.HasbroVideoNowXP:
|
||||
case RedumpSystem.PhilipsCDi:
|
||||
case RedumpSystem.SuperAudioCD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if a system is a marker value
|
||||
/// </summary>
|
||||
/// <param name="system">RedumpSystem value to check</param>
|
||||
/// <returns>True if the system is a marker value, false otherwise</returns>
|
||||
public static bool IsMarker(this RedumpSystem? system)
|
||||
{
|
||||
switch (system)
|
||||
{
|
||||
case RedumpSystem.MarkerArcadeEnd:
|
||||
case RedumpSystem.MarkerComputerEnd:
|
||||
case RedumpSystem.MarkerDiscBasedConsoleEnd:
|
||||
// case RedumpSystem.MarkerOtherConsoleEnd:
|
||||
case RedumpSystem.MarkerOtherEnd:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if a system is considered XGD
|
||||
/// </summary>
|
||||
/// <param name="system">RedumpSystem value to check</param>
|
||||
/// <returns>True if the system is XGD, false otherwise</returns>
|
||||
public static bool IsXGD(this RedumpSystem? system)
|
||||
{
|
||||
switch (system)
|
||||
{
|
||||
case RedumpSystem.MicrosoftXbox:
|
||||
case RedumpSystem.MicrosoftXbox360:
|
||||
case RedumpSystem.MicrosoftXboxOne:
|
||||
case RedumpSystem.MicrosoftXboxSeriesXS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MPF.Utilities
|
||||
namespace MPF.Core.Utilities
|
||||
{
|
||||
internal static class Logging
|
||||
public static class Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Process a chunk of text and send it to a handler
|
||||
@@ -38,15 +37,15 @@ namespace MPF.Utilities
|
||||
string line = new string(buffer, 0, read);
|
||||
|
||||
// If we have no newline characters, store in the string builder
|
||||
if (!line.Contains('\r') && !line.Contains('\n'))
|
||||
if (!line.Contains("\r") && !line.Contains("\n"))
|
||||
sb.Append(line);
|
||||
|
||||
// If we have a newline, append and log
|
||||
else if (line.Contains('\n') || line.Contains("\r\n"))
|
||||
else if (line.Contains("\n") || line.Contains("\r\n"))
|
||||
ProcessNewLines(sb, line, baseClass, handler);
|
||||
|
||||
// If we have a carriage return only, append and log first and last instances
|
||||
else if (line.Contains('\r'))
|
||||
else if (line.Contains("\r"))
|
||||
ProcessCarriageReturns(sb, line, baseClass, handler);
|
||||
}
|
||||
}
|
||||
@@ -71,7 +70,7 @@ namespace MPF.Utilities
|
||||
for (int i = 0; i < split.Length; i++)
|
||||
{
|
||||
// If the chunk contains a carriage return, handle it like a separate line
|
||||
if (split[i].Contains('\r'))
|
||||
if (split[i].Contains("\r"))
|
||||
{
|
||||
ProcessCarriageReturns(sb, split[i], baseClass, handler);
|
||||
continue;
|
||||
@@ -1,8 +1,11 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using MPF.Redump;
|
||||
using MPF.Core.Data;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.Utilities
|
||||
namespace MPF.Core.Utilities
|
||||
{
|
||||
public static class Tools
|
||||
{
|
||||
@@ -70,6 +73,54 @@ namespace MPF.Utilities
|
||||
|
||||
#endregion
|
||||
|
||||
#region Support
|
||||
|
||||
/// <summary>
|
||||
/// Verify that, given a system and a media type, they are correct
|
||||
/// </summary>
|
||||
public static Result GetSupportStatus(RedumpSystem? system, MediaType? type)
|
||||
{
|
||||
// No system chosen, update status
|
||||
if (system == null)
|
||||
return Result.Failure("Please select a valid system");
|
||||
|
||||
// If we're on an unsupported type, update the status accordingly
|
||||
switch (type)
|
||||
{
|
||||
// Fully supported types
|
||||
case MediaType.BluRay:
|
||||
case MediaType.CDROM:
|
||||
case MediaType.DVD:
|
||||
case MediaType.FloppyDisk:
|
||||
case MediaType.HardDisk:
|
||||
case MediaType.CompactFlash:
|
||||
case MediaType.SDCard:
|
||||
case MediaType.FlashDrive:
|
||||
case MediaType.HDDVD:
|
||||
return Result.Success($"{type.LongName()} ready to dump");
|
||||
|
||||
// Partially supported types
|
||||
case MediaType.GDROM:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
return Result.Success($"{type.LongName()} partially supported for dumping");
|
||||
|
||||
// Special case for other supported tools
|
||||
case MediaType.UMD:
|
||||
return Result.Failure($"{type.LongName()} supported for submission info parsing");
|
||||
|
||||
// Specifically unknown type
|
||||
case MediaType.NONE:
|
||||
return Result.Failure($"Please select a valid media type");
|
||||
|
||||
// Undumpable but recognized types
|
||||
default:
|
||||
return Result.Failure($"{type.LongName()} media are not supported for dumping");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Versioning
|
||||
|
||||
/// <summary>
|
||||
@@ -82,14 +133,14 @@ namespace MPF.Utilities
|
||||
/// </returns>
|
||||
public static (bool different, string message, string url) CheckForNewVersion()
|
||||
{
|
||||
// Get current assembly version
|
||||
var assemblyVersion = Assembly.GetEntryAssembly().GetName().Version;
|
||||
string version = $"{assemblyVersion.Major}.{assemblyVersion.Minor}" + (assemblyVersion.Build != 0 ? $".{assemblyVersion.Build}" : string.Empty);
|
||||
|
||||
// Get the latest tag from GitHub
|
||||
using (var client = new RedumpWebClient())
|
||||
try
|
||||
{
|
||||
(string tag, string url) = client.GetRemoteVersionAndUrl();
|
||||
// Get current assembly version
|
||||
var assemblyVersion = Assembly.GetEntryAssembly().GetName().Version;
|
||||
string version = $"{assemblyVersion.Major}.{assemblyVersion.Minor}" + (assemblyVersion.Build != 0 ? $".{assemblyVersion.Build}" : string.Empty);
|
||||
|
||||
// Get the latest tag from GitHub
|
||||
(string tag, string url) = GetRemoteVersionAndUrl();
|
||||
bool different = version != tag;
|
||||
|
||||
string message = $"Local version: {version}"
|
||||
@@ -100,6 +151,10 @@ namespace MPF.Utilities
|
||||
|
||||
return (different, message, url);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (false, ex.ToString(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -111,6 +166,26 @@ namespace MPF.Utilities
|
||||
return assemblyVersion.InformationalVersion;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the latest version of MPF from GitHub and the release URL
|
||||
/// </summary>
|
||||
private static (string tag, string url) GetRemoteVersionAndUrl()
|
||||
{
|
||||
using (WebClient wc = new WebClient())
|
||||
{
|
||||
wc.Headers["User-Agent"] = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0";
|
||||
|
||||
// TODO: Figure out a better way than having this hardcoded...
|
||||
string url = "https://api.github.com/repos/SabreTools/MPF/releases/latest";
|
||||
string latestReleaseJsonString = wc.DownloadString(url);
|
||||
var latestReleaseJson = JObject.Parse(latestReleaseJsonString);
|
||||
string latestTag = latestReleaseJson["tag_name"].ToString();
|
||||
string releaseUrl = latestReleaseJson["html_url"].ToString();
|
||||
|
||||
return (latestTag, releaseUrl);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
30
MPF.CueSheets/MPF.CueSheets.csproj
Normal file
30
MPF.CueSheets/MPF.CueSheets.csproj
Normal file
@@ -0,0 +1,30 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net48;netcoreapp3.1;net5.0</TargetFrameworks>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
|
||||
<Copyright>Copyright (c)2019-2021</Copyright>
|
||||
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
|
||||
<Version>2.3</Version>
|
||||
<AssemblyVersion>$(Version)</AssemblyVersion>
|
||||
<FileVersion>$(Version)</FileVersion>
|
||||
<IncludeSource>true</IncludeSource>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<NrtRevisionFormat>$(Version)-{chash:8}</NrtRevisionFormat>
|
||||
<NrtResolveSimpleAttributes>true</NrtResolveSimpleAttributes>
|
||||
<NrtShowRevision>false</NrtShowRevision>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,106 +0,0 @@
|
||||
using System.IO;
|
||||
|
||||
namespace MPF.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents information for a single drive
|
||||
/// </summary>
|
||||
public class Drive
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents drive type
|
||||
/// </summary>
|
||||
public InternalDriveType? InternalDriveType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Drive partition format
|
||||
/// </summary>
|
||||
public string DriveFormat { get { return driveInfo.DriveFormat; } }
|
||||
|
||||
/// <summary>
|
||||
/// Windows drive letter
|
||||
/// </summary>
|
||||
public char Letter { get { return driveInfo?.Name[0] ?? '\0'; } }
|
||||
|
||||
/// <summary>
|
||||
/// Represents if Windows has marked the drive as active
|
||||
/// </summary>
|
||||
public bool MarkedActive { get { return driveInfo.IsReady; } }
|
||||
|
||||
/// <summary>
|
||||
/// Media label as read by Windows
|
||||
/// </summary>
|
||||
public string VolumeLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
string volumeLabel = Template.DiscNotDetected;
|
||||
if (driveInfo.IsReady)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(driveInfo.VolumeLabel))
|
||||
volumeLabel = "track";
|
||||
else
|
||||
volumeLabel = driveInfo.VolumeLabel;
|
||||
}
|
||||
|
||||
foreach (char c in Path.GetInvalidFileNameChars())
|
||||
volumeLabel = volumeLabel.Replace(c, '_');
|
||||
|
||||
return volumeLabel;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DriveInfo object representing the drive, if possible
|
||||
/// </summary>
|
||||
private readonly DriveInfo driveInfo;
|
||||
|
||||
public Drive(InternalDriveType? driveType, DriveInfo driveInfo)
|
||||
{
|
||||
this.InternalDriveType = driveType;
|
||||
this.driveInfo = driveInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a sector with a specified size from the drive
|
||||
/// </summary>
|
||||
/// <param name="num">Sector number, non-negative</param>
|
||||
/// <param name="size">Size of a sector in bytes</param>
|
||||
/// <returns>Byte array representing the sector, null on error</returns>
|
||||
public byte[] ReadSector(long num, int size = 2048)
|
||||
{
|
||||
// Missing drive leter is not supported
|
||||
if (string.IsNullOrEmpty(this.driveInfo?.Name))
|
||||
return null;
|
||||
|
||||
// We don't support negative sectors
|
||||
if (num < 0)
|
||||
return null;
|
||||
|
||||
// Wrap the following in case of device access errors
|
||||
Stream fs = null;
|
||||
try
|
||||
{
|
||||
// Open the drive as a device
|
||||
fs = File.OpenRead($"\\\\?\\{this.Letter}:");
|
||||
|
||||
// Seek to the start of the sector, if possible
|
||||
long start = num * size;
|
||||
fs.Seek(start, SeekOrigin.Begin);
|
||||
|
||||
// Read and return the sector
|
||||
byte[] buffer = new byte[size];
|
||||
fs.Read(buffer, 0, size);
|
||||
return buffer;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
fs?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,777 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace MPF.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Available hashing types
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum Hash
|
||||
{
|
||||
CRC = 1 << 0,
|
||||
MD5 = 1 << 1,
|
||||
SHA1 = 1 << 2,
|
||||
SHA256 = 1 << 3,
|
||||
SHA384 = 1 << 4,
|
||||
SHA512 = 1 << 5,
|
||||
|
||||
// Special combinations
|
||||
Standard = CRC | MD5 | SHA1,
|
||||
All = CRC | MD5 | SHA1 | SHA256 | SHA384 | SHA512,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drive type for dumping
|
||||
/// </summary>
|
||||
public enum InternalDriveType
|
||||
{
|
||||
Optical,
|
||||
Floppy,
|
||||
HardDisk,
|
||||
Removable,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Program that is being used to dump media
|
||||
/// </summary>
|
||||
public enum InternalProgram
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
// Dumping support
|
||||
Aaru,
|
||||
DD,
|
||||
DiscImageCreator,
|
||||
|
||||
// Verification support only
|
||||
CleanRip,
|
||||
DCDumper,
|
||||
UmdImageCreator,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Known systems
|
||||
/// </summary>
|
||||
public enum KnownSystem
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
#region Disc-Based Consoles
|
||||
|
||||
AtariJaguarCD,
|
||||
BandaiPlaydiaQuickInteractiveSystem,
|
||||
BandaiApplePippin,
|
||||
CommodoreAmigaCD32,
|
||||
CommodoreAmigaCDTV,
|
||||
EnvizionsEVOSmartConsole,
|
||||
FujitsuFMTownsMarty,
|
||||
HasbroVideoNow,
|
||||
HasbroVideoNowColor,
|
||||
HasbroVideoNowJr,
|
||||
HasbroVideoNowXP,
|
||||
MattelFisherPriceiXL,
|
||||
MattelHyperscan,
|
||||
MicrosoftXBOX,
|
||||
MicrosoftXBOX360,
|
||||
MicrosoftXBOXOne,
|
||||
MicrosoftXboxSeriesXS,
|
||||
NECPCEngineTurboGrafxCD,
|
||||
NECPCFX,
|
||||
NintendoGameCube,
|
||||
NintendoSonySuperNESCDROMSystem,
|
||||
NintendoWii,
|
||||
NintendoWiiU,
|
||||
Panasonic3DOInteractiveMultiplayer, // The 3DO Company 3DO Interactive Multiplayer
|
||||
PhilipsCDi,
|
||||
PioneerLaserActive,
|
||||
SegaCDMegaCD,
|
||||
SegaDreamcast,
|
||||
SegaSaturn,
|
||||
SNKNeoGeoCD,
|
||||
SonyPlayStation,
|
||||
SonyPlayStation2,
|
||||
SonyPlayStation3,
|
||||
SonyPlayStation4,
|
||||
SonyPlayStation5,
|
||||
SonyPlayStationPortable,
|
||||
TandyMemorexVisualInformationSystem,
|
||||
VMLabsNuon,
|
||||
VTechVFlashVSmilePro,
|
||||
ZAPiTGamesGameWaveFamilyEntertainmentSystem,
|
||||
|
||||
MarkerDiscBasedConsoleEnd,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cartridge-Based and Other Consoles
|
||||
|
||||
/*
|
||||
AmstradGX4000,
|
||||
APFMicrocomputerSystem,
|
||||
Atari2600VCS,
|
||||
Atari5200,
|
||||
Atari7800,
|
||||
AtariJaguar,
|
||||
AtariXEVideoGameSystem,
|
||||
Audiosonic1292AdvancedProgrammableVideoSystem,
|
||||
BallyAstrocade,
|
||||
BitCorporationDina,
|
||||
CasioLoopy,
|
||||
CasioPV1000,
|
||||
Commodore64GamesSystem,
|
||||
DaewooElectronicsZemmix,
|
||||
EmersonArcadia2001,
|
||||
EpochCassetteVision,
|
||||
EpochSuperCassetteVision,
|
||||
FairchildChannelF,
|
||||
FuntechSuperACan,
|
||||
GeneralConsumerElectricVectrex,
|
||||
HeberBBCBridgeCompanion,
|
||||
IntertonVC4000,
|
||||
JungleTacVii,
|
||||
LeapFrogClickStart,
|
||||
LJNVideoArt,
|
||||
MagnavoxOdyssey2,
|
||||
MattelIntellivision,
|
||||
NECPCEngineTurboGrafx16,
|
||||
NichibutsuMyVision,
|
||||
Nintendo64,
|
||||
Nintendo64DD,
|
||||
NintendoFamilyComputerNintendoEntertainmentSystem,
|
||||
NintendoFamilyComputerDiskSystem,
|
||||
NintendoSuperFamicomSuperNintendoEntertainmentSystem,
|
||||
NintendoSwitch,
|
||||
PhilipsVideopacPlusG7400,
|
||||
RCAStudioII,
|
||||
Sega32X,
|
||||
SegaMarkIIIMasterSystem,
|
||||
SegaMegaDriveGenesis,
|
||||
SegaSG1000,
|
||||
SNKNeoGeo,
|
||||
SSDCOMPANYLIMITEDXaviXPORT,
|
||||
ViewMasterInteractiveVision,
|
||||
VTechCreatiVision,
|
||||
VTechVSmile,
|
||||
VTechSocrates,
|
||||
WorldsOfWonderActionMax,
|
||||
|
||||
MarkerOtherConsoleEnd,
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#region Computers
|
||||
|
||||
AcornArchimedes,
|
||||
AppleMacintosh,
|
||||
CommodoreAmiga,
|
||||
FujitsuFMTowns,
|
||||
IBMPCCompatible,
|
||||
NECPC88,
|
||||
NECPC98,
|
||||
SharpX68000,
|
||||
|
||||
MarkerComputerEnd,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Arcade
|
||||
|
||||
AmigaCUBOCD32,
|
||||
AmericanLaserGames3DO,
|
||||
Atari3DO,
|
||||
Atronic,
|
||||
AUSCOMSystem1,
|
||||
BallyGameMagic,
|
||||
CapcomCPSystemIII,
|
||||
funworldPhotoPlay,
|
||||
GlobalVRVarious,
|
||||
GlobalVRVortek,
|
||||
GlobalVRVortekV3,
|
||||
ICEPCHardware,
|
||||
IncredibleTechnologiesEagle,
|
||||
IncredibleTechnologiesVarious,
|
||||
KonamieAmusement,
|
||||
KonamiFirebeat,
|
||||
KonamiGVSystem,
|
||||
KonamiM2,
|
||||
KonamiPython,
|
||||
KonamiPython2,
|
||||
KonamiSystem573,
|
||||
KonamiTwinkle,
|
||||
KonamiVarious,
|
||||
MeritIndustriesBoardwalk,
|
||||
MeritIndustriesMegaTouchForce,
|
||||
MeritIndustriesMegaTouchION,
|
||||
MeritIndustriesMegaTouchMaxx,
|
||||
MeritIndustriesMegaTouchXL,
|
||||
NamcoCapcomSystem256,
|
||||
NamcoCapcomTaitoSystem246,
|
||||
NamcoSegaNintendoTriforce,
|
||||
NamcoSystem12,
|
||||
NamcoSystem357,
|
||||
NewJatreCDi,
|
||||
NichibutsuHighRateSystem,
|
||||
NichibutsuSuperCD,
|
||||
NichibutsuXRateSystem,
|
||||
PanasonicM2,
|
||||
PhotoPlayVarious,
|
||||
RawThrillsVarious,
|
||||
SegaChihiro,
|
||||
SegaEuropaR,
|
||||
SegaLindbergh,
|
||||
SegaNaomi,
|
||||
SegaNaomi2,
|
||||
SegaNu,
|
||||
SegaRingEdge,
|
||||
SegaRingEdge2,
|
||||
SegaRingWide,
|
||||
SegaTitanVideo,
|
||||
SegaSystem32,
|
||||
SeibuCATSSystem,
|
||||
TABAustriaQuizard,
|
||||
TsunamiTsuMoMultiGameMotionSystem,
|
||||
|
||||
MarkerArcadeEnd,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Other
|
||||
|
||||
AudioCD,
|
||||
BDVideo,
|
||||
DVDAudio,
|
||||
DVDVideo,
|
||||
EnhancedCD,
|
||||
HDDVDVideo,
|
||||
NavisoftNaviken21,
|
||||
PalmOS,
|
||||
PhotoCD,
|
||||
PlayStationGameSharkUpdates,
|
||||
RainbowDisc,
|
||||
SegaPrologue21,
|
||||
SuperAudioCD,
|
||||
TaoiKTV,
|
||||
TomyKissSite,
|
||||
VideoCD,
|
||||
|
||||
MarkerOtherEnd,
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Known system category
|
||||
/// </summary>
|
||||
public enum KnownSystemCategory
|
||||
{
|
||||
DiscBasedConsole = 0,
|
||||
OtherConsole,
|
||||
Computer,
|
||||
Arcade,
|
||||
Other,
|
||||
Custom
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Known media types
|
||||
/// </summary>
|
||||
public enum MediaType
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
#region Punched Media
|
||||
|
||||
ApertureCard,
|
||||
JacquardLoomCard,
|
||||
MagneticStripeCard,
|
||||
OpticalPhonecard,
|
||||
PunchedCard,
|
||||
PunchedTape,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Tape
|
||||
|
||||
Cassette,
|
||||
DataCartridge,
|
||||
OpenReel,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Disc / Disc
|
||||
|
||||
BluRay,
|
||||
CDROM,
|
||||
DVD,
|
||||
FloppyDisk,
|
||||
Floptical,
|
||||
GDROM,
|
||||
HDDVD,
|
||||
HardDisk,
|
||||
IomegaBernoulliDisk,
|
||||
IomegaJaz,
|
||||
IomegaZip,
|
||||
LaserDisc, // LD-ROM and LV-ROM variants
|
||||
Nintendo64DD,
|
||||
NintendoFamicomDiskSystem,
|
||||
NintendoGameCubeGameDisc,
|
||||
NintendoWiiOpticalDisc,
|
||||
NintendoWiiUOpticalDisc,
|
||||
UMD,
|
||||
|
||||
#endregion
|
||||
|
||||
// Unsorted Formats
|
||||
Cartridge,
|
||||
CED,
|
||||
CompactFlash,
|
||||
MMC,
|
||||
SDCard,
|
||||
FlashDrive,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Physical media types
|
||||
/// </summary>
|
||||
/// <see cref="https://docs.microsoft.com/en-us/previous-versions/windows/desktop/cimwin32a/win32-physicalmedia"/>
|
||||
public enum PhysicalMediaType : ushort
|
||||
{
|
||||
Unknown = 0,
|
||||
Other = 1,
|
||||
TapeCartridge = 2,
|
||||
QICCartridge = 3,
|
||||
AITCartridge = 4,
|
||||
DTFCartridge = 5,
|
||||
DATCartridge = 6,
|
||||
EightMillimeterTapeCartridge = 7,
|
||||
NineteenMillimeterTapeCartridge = 8,
|
||||
DLTCartridge = 9,
|
||||
HalfInchMagneticTapeCartridge = 10,
|
||||
CartridgeDisk = 11,
|
||||
JAZDisk = 12,
|
||||
ZIPDisk = 13,
|
||||
SyQuestDisk = 14,
|
||||
WinchesterRemovableDisk = 15,
|
||||
CDROM = 16,
|
||||
CDROMXA = 17,
|
||||
CDI = 18,
|
||||
CDRecordable = 19,
|
||||
WORM = 20,
|
||||
MagnetoOptical = 21,
|
||||
DVD = 22,
|
||||
DVDPlusRW = 23,
|
||||
DVDRAM = 24,
|
||||
DVDROM = 25,
|
||||
DVDVideo = 26,
|
||||
Divx = 27,
|
||||
FloppyDiskette = 28,
|
||||
HardDisk = 29,
|
||||
MemoryCard = 30,
|
||||
HardCopy = 31,
|
||||
ClikDisk = 32,
|
||||
CDRW = 33,
|
||||
CDDA = 34,
|
||||
CDPlus = 35,
|
||||
DVDRecordable = 36,
|
||||
DVDMinusRW = 37,
|
||||
DVDAudio = 38,
|
||||
DVD5 = 39,
|
||||
DVD9 = 40,
|
||||
DVD10 = 41,
|
||||
DVD18 = 42,
|
||||
MagnetoOpticalRewriteable = 43,
|
||||
MagnetoOpticalWriteOnce = 44,
|
||||
MagnetoOpticalRewriteableLIMDOW = 45,
|
||||
PhaseChangeWriteOnce = 46,
|
||||
PhaseChangeRewriteable = 47,
|
||||
PhaseChangeDualRewriteable = 48,
|
||||
AblativeWriteOnce = 49,
|
||||
NearFieldRecording = 50,
|
||||
MiniQic = 51,
|
||||
Travan = 52,
|
||||
EightMillimeterMetalParticle = 53,
|
||||
EightMillimeterAdvancedMetalEvaporate = 54,
|
||||
NCTP = 55,
|
||||
LTOUltrium = 56,
|
||||
LTOAccelis = 57,
|
||||
NineTrackTape = 58,
|
||||
EighteenTrackTape = 59,
|
||||
ThirtySixTrackTape = 60,
|
||||
Magstar3590 = 61,
|
||||
MagstarMP = 62,
|
||||
D2Tape = 63,
|
||||
TapeDSTSmall = 64,
|
||||
TapeDSTMedium = 65,
|
||||
TapeDSTLarge = 66,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Redump disc category
|
||||
/// </summary>
|
||||
public enum RedumpDiscCategory
|
||||
{
|
||||
Games = 1,
|
||||
Demos = 2,
|
||||
Video = 3,
|
||||
Audio = 4,
|
||||
Multimedia = 5,
|
||||
Applications = 6,
|
||||
Coverdiscs = 7,
|
||||
Educational = 8,
|
||||
BonusDiscs = 9,
|
||||
Preproduction = 10,
|
||||
AddOns = 11,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Redump dump status
|
||||
/// </summary>
|
||||
public enum RedumpDumpStatus
|
||||
{
|
||||
BadDumpRed = 2,
|
||||
PossibleBadDumpYellow = 3,
|
||||
OriginalMediaBlue = 4,
|
||||
TwoOrMoreDumpsGreen = 5,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Redump supported langauge
|
||||
/// </summary>
|
||||
public enum RedumpLanguage
|
||||
{
|
||||
Afrikaans,
|
||||
Albanian,
|
||||
Arabic,
|
||||
Basque,
|
||||
Bulgarian,
|
||||
Catalan,
|
||||
Chinese,
|
||||
Croatian,
|
||||
Czech,
|
||||
Danish,
|
||||
Dutch,
|
||||
English,
|
||||
Estonian,
|
||||
Finnish,
|
||||
French,
|
||||
Gaelic,
|
||||
German,
|
||||
Greek,
|
||||
Hebrew,
|
||||
Hindi,
|
||||
Hungarian,
|
||||
Indonesian,
|
||||
Icelandic,
|
||||
Italian,
|
||||
Japanese,
|
||||
Korean,
|
||||
Latin,
|
||||
Latvian,
|
||||
Lithuanian,
|
||||
Macedonian,
|
||||
Norwegian,
|
||||
Polish,
|
||||
Portuguese,
|
||||
Punjabi,
|
||||
Romanian,
|
||||
Russian,
|
||||
Serbian,
|
||||
Slovak,
|
||||
Slovenian,
|
||||
Spanish,
|
||||
Swedish,
|
||||
Tamil,
|
||||
Thai,
|
||||
Turkish,
|
||||
Ukrainian,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Redump PS2 language selection via
|
||||
/// </summary>
|
||||
public enum RedumpLanguageSelection
|
||||
{
|
||||
BiosSettings,
|
||||
LanguageSelector,
|
||||
OptionsMenu,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supported Redump region
|
||||
/// </summary>
|
||||
public enum RedumpRegion
|
||||
{
|
||||
Argentina,
|
||||
Asia,
|
||||
AsiaEurope,
|
||||
AsiaUSA,
|
||||
Australia,
|
||||
AustraliaGermany,
|
||||
AustraliaNewZealand,
|
||||
Austria,
|
||||
AustriaSwitzerland,
|
||||
Belgium,
|
||||
BelgiumNetherlands,
|
||||
Brazil,
|
||||
Bulgaria,
|
||||
Canada,
|
||||
China,
|
||||
Croatia,
|
||||
Czech,
|
||||
Denmark,
|
||||
Estonia,
|
||||
Europe,
|
||||
EuropeAsia,
|
||||
EuropeAustralia,
|
||||
EuropeCanada,
|
||||
EuropeGermany,
|
||||
Export,
|
||||
Finland,
|
||||
France,
|
||||
FranceSpain,
|
||||
Germany,
|
||||
GreaterChina,
|
||||
Greece,
|
||||
Hungary,
|
||||
Iceland,
|
||||
India,
|
||||
Ireland,
|
||||
Israel,
|
||||
Italy,
|
||||
Japan,
|
||||
JapanAsia,
|
||||
JapanEurope,
|
||||
JapanKorea,
|
||||
JapanUSA,
|
||||
Korea,
|
||||
LatinAmerica,
|
||||
Lithuania,
|
||||
Netherlands,
|
||||
NewZealand,
|
||||
Norway,
|
||||
Poland,
|
||||
Portugal,
|
||||
Romania,
|
||||
Russia,
|
||||
Scandinavia,
|
||||
Serbia,
|
||||
Singapore,
|
||||
Slovakia,
|
||||
SouthAfrica,
|
||||
Spain,
|
||||
SpainPortugal,
|
||||
Sweden,
|
||||
Switzerland,
|
||||
Taiwan,
|
||||
Thailand,
|
||||
Turkey,
|
||||
UnitedArabEmirates,
|
||||
UK,
|
||||
UKAustralia,
|
||||
Ukraine,
|
||||
USA,
|
||||
USAAsia,
|
||||
USAAustralia,
|
||||
USABrazil,
|
||||
USACanada,
|
||||
USAEurope,
|
||||
USAGermany,
|
||||
USAJapan,
|
||||
USAKorea,
|
||||
World,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of all known Redump systems
|
||||
/// </summary>
|
||||
public enum RedumpSystem
|
||||
{
|
||||
// Special BIOS sets
|
||||
MicrosoftXboxBIOS,
|
||||
NintendoGameCubeBIOS,
|
||||
SonyPlayStationBIOS,
|
||||
SonyPlayStation2BIOS,
|
||||
|
||||
// Regular systems
|
||||
AcornArchimedes,
|
||||
AppleMacintosh,
|
||||
AtariJaguarCDInteractiveMultimediaSystem,
|
||||
AudioCD,
|
||||
BandaiPippin,
|
||||
BandaiPlaydiaQuickInteractiveSystem,
|
||||
BDVideo,
|
||||
CommodoreAmigaCD,
|
||||
CommodoreAmigaCD32,
|
||||
CommodoreAmigaCDTV,
|
||||
DVDVideo,
|
||||
EnhancedCD,
|
||||
FujitsuFMTownsseries,
|
||||
funworldPhotoPlay,
|
||||
HasbroVideoNow,
|
||||
HasbroVideoNowColor,
|
||||
HasbroVideoNowJr,
|
||||
HasbroVideoNowXP,
|
||||
IBMPCcompatible,
|
||||
IncredibleTechnologiesEagle,
|
||||
KonamieAmusement,
|
||||
KonamiFireBeat,
|
||||
KonamiM2,
|
||||
KonamiSystem573,
|
||||
KonamiSystemGV,
|
||||
KonamiTwinkle,
|
||||
MattelFisherPriceiXL,
|
||||
MattelHyperScan,
|
||||
MemorexVisualInformationSystem,
|
||||
MicrosoftXbox,
|
||||
MicrosoftXbox360,
|
||||
MicrosoftXboxOne,
|
||||
MicrosoftXboxSeriesXS,
|
||||
NamcoSegaNintendoTriforce,
|
||||
NamcoSystem12,
|
||||
NamcoSystem246,
|
||||
NavisoftNaviken21,
|
||||
NECPCEngineCDTurboGrafxCD,
|
||||
NECPC88series,
|
||||
NECPC98series,
|
||||
NECPCFXPCFXGA,
|
||||
NintendoGameCube,
|
||||
NintendoWii,
|
||||
NintendoWiiU,
|
||||
PalmOS,
|
||||
Panasonic3DOInteractiveMultiplayer,
|
||||
PanasonicM2,
|
||||
PhilipsCDi,
|
||||
PhotoCD,
|
||||
PlayStationGameSharkUpdates,
|
||||
SegaChihiro,
|
||||
SegaDreamcast,
|
||||
SegaLindbergh,
|
||||
SegaMegaCDSegaCD,
|
||||
SegaNaomi,
|
||||
SegaNaomi2,
|
||||
SegaPrologue21,
|
||||
SegaRingEdge,
|
||||
SegaRingEdge2,
|
||||
SegaSaturn,
|
||||
SegaTitanVideo,
|
||||
SharpX68000,
|
||||
SNKNeoGeoCD,
|
||||
SonyPlayStation,
|
||||
SonyPlayStation2,
|
||||
SonyPlayStation3,
|
||||
SonyPlayStation4,
|
||||
SonyPlayStation5,
|
||||
SonyPlayStationPortable,
|
||||
TABAustriaQuizard,
|
||||
TaoiKTV,
|
||||
TomyKissSite,
|
||||
VideoCD,
|
||||
VMLabsNUON,
|
||||
VTechVFlashVSmilePro,
|
||||
ZAPiTGamesGameWaveFamilyEntertainmentSystem,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generic yes/no values for Redump
|
||||
/// </summary>
|
||||
public enum YesNo
|
||||
{
|
||||
NULL = 0,
|
||||
No = 1,
|
||||
Yes = 2,
|
||||
}
|
||||
|
||||
#region Win32_CDROMDrive
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-cdromdrive
|
||||
|
||||
/// <summary>
|
||||
/// Availability and status of the device
|
||||
/// </summary>
|
||||
public enum Availability : ushort
|
||||
{
|
||||
Other = 1,
|
||||
Unknown = 2,
|
||||
RunningFullPower = 3,
|
||||
Warning = 4,
|
||||
InTest = 5,
|
||||
NotApplicable = 6,
|
||||
PowerOff = 7,
|
||||
OffLine = 8,
|
||||
OffDuty = 9,
|
||||
Degraded = 10,
|
||||
NotInstalled = 11,
|
||||
InstallError = 12,
|
||||
PowerSaveUnknown = 13,
|
||||
PowerSaveLowPowerMode = 14,
|
||||
PowerSaveStandby = 15,
|
||||
PowerCycle = 16,
|
||||
PowerSaveWarning = 17,
|
||||
Paused = 18,
|
||||
NotReady = 19,
|
||||
NotConfigured = 20,
|
||||
Quiesced = 21,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Optical drive capabilities
|
||||
/// </summary>
|
||||
public enum Capabilities : ushort
|
||||
{
|
||||
Unknown = 0,
|
||||
Other = 1,
|
||||
SequentialAccess = 2,
|
||||
RandomAccess = 3,
|
||||
SupportsWriting = 4,
|
||||
Encryption = 5,
|
||||
Compression = 6,
|
||||
SupportsRemoveableMedia = 7,
|
||||
ManualCleaning = 8,
|
||||
AutomaticCleaning = 9,
|
||||
SMARTNotification = 10,
|
||||
SupportsDualSidedMedia = 11,
|
||||
PredismountEjectNotRequired = 12,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// File system flags
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum FileSystemFlags : uint
|
||||
{
|
||||
None = 0,
|
||||
CaseSensitiveSearch = 1,
|
||||
CasePreservedNames = 2,
|
||||
UnicodeOnDisk = 4,
|
||||
PersistentACLs = 8,
|
||||
FileCompression = 16,
|
||||
VolumeQuotas = 32,
|
||||
SupportsSparseFiles = 64,
|
||||
SupportsReparsePoints = 128,
|
||||
SupportsRemoteStorage = 256,
|
||||
SupportsLongNames = 16384,
|
||||
VolumeIsCompressed = 32768,
|
||||
ReadOnlyVolume = 524288,
|
||||
SupportsObjectIDS = 65536,
|
||||
SupportsEncryption = 131072,
|
||||
SupportsNamedStreams = 262144,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specific power-related capabilities of a logical device
|
||||
/// </summary>
|
||||
public enum PowerManagementCapabilities : ushort
|
||||
{
|
||||
Unknown = 0,
|
||||
NotSupported = 1,
|
||||
Disabled = 2,
|
||||
Enabled = 3,
|
||||
PowerSavingModesEnteredAutomatically = 4,
|
||||
PowerStateSettable = 5,
|
||||
PowerCyclingSupported = 6,
|
||||
TimedPowerOnSupported = 7,
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
535
MPF.Library/DumpEnvironment.cs
Normal file
535
MPF.Library/DumpEnvironment.cs
Normal file
@@ -0,0 +1,535 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using BurnOutSharp;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.Utilities;
|
||||
using MPF.Modules;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.Library
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the state of all settings to be used during dumping
|
||||
/// </summary>
|
||||
public class DumpEnvironment
|
||||
{
|
||||
#region Output paths
|
||||
|
||||
/// <summary>
|
||||
/// Base output directory to write files to
|
||||
/// </summary>
|
||||
public string OutputDirectory { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Base output filename for output
|
||||
/// </summary>
|
||||
public string OutputFilename { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI information
|
||||
|
||||
/// <summary>
|
||||
/// Drive object representing the current drive
|
||||
/// </summary>
|
||||
public Drive Drive { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Currently selected system
|
||||
/// </summary>
|
||||
public RedumpSystem? System { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Currently selected media type
|
||||
/// </summary>
|
||||
public MediaType? Type { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Options object representing user-defined options
|
||||
/// </summary>
|
||||
public Options Options { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Parameters object representing what to send to the internal program
|
||||
/// </summary>
|
||||
public BaseParameters Parameters { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
/// <summary>
|
||||
/// Generic way of reporting a message
|
||||
/// </summary>
|
||||
public EventHandler<string> ReportStatus;
|
||||
|
||||
/// <summary>
|
||||
/// Queue of items that need to be logged
|
||||
/// </summary>
|
||||
private ProcessingQueue<string> outputQueue;
|
||||
|
||||
/// <summary>
|
||||
/// Event handler for data returned from a process
|
||||
/// </summary>
|
||||
private void OutputToLog(object proc, string args) => outputQueue.Enqueue(args);
|
||||
|
||||
/// <summary>
|
||||
/// Process the outputs in the queue
|
||||
/// </summary>
|
||||
private void ProcessOutputs(string nextOutput) => ReportStatus.Invoke(this, nextOutput);
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for a full DumpEnvironment object from user information
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="outputDirectory"></param>
|
||||
/// <param name="outputFilename"></param>
|
||||
/// <param name="drive"></param>
|
||||
/// <param name="system"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="parameters"></param>
|
||||
public DumpEnvironment(Options options,
|
||||
string outputDirectory,
|
||||
string outputFilename,
|
||||
Drive drive,
|
||||
RedumpSystem? system,
|
||||
MediaType? type,
|
||||
string parameters)
|
||||
{
|
||||
// Set options object
|
||||
this.Options = options;
|
||||
|
||||
// Output paths
|
||||
(this.OutputDirectory, this.OutputFilename) = InfoTool.NormalizeOutputPaths(outputDirectory, outputFilename);
|
||||
|
||||
// UI information
|
||||
this.Drive = drive;
|
||||
this.System = system ?? options.DefaultSystem;
|
||||
this.Type = type ?? MediaType.NONE;
|
||||
|
||||
// Dumping program
|
||||
SetParameters(parameters);
|
||||
}
|
||||
|
||||
#region Public Functionality
|
||||
|
||||
/// <summary>
|
||||
/// Adjust output paths if we're using DiscImageCreator
|
||||
/// </summary>
|
||||
public void AdjustPathsForDiscImageCreator()
|
||||
{
|
||||
// Only DiscImageCreator has issues with paths
|
||||
if (this.Parameters.InternalProgram != InternalProgram.DiscImageCreator)
|
||||
return;
|
||||
|
||||
// Replace all instances in the output directory
|
||||
this.OutputDirectory = this.OutputDirectory.Replace('.', '_');
|
||||
|
||||
// Currently, only periods in directories matter
|
||||
// Leave the following code commented in case filename handling breaks again
|
||||
|
||||
// Replace all instances in the output filename, except the extension
|
||||
//string tempFilename = Path.GetFileNameWithoutExtension(this.OutputFilename)
|
||||
// .Replace('.', '_');
|
||||
//string tempExtension = Path.GetExtension(this.OutputFilename)?.TrimStart('.');
|
||||
//this.OutputFilename = $"{tempFilename}.{tempExtension}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the parameters object based on the internal program and parameters string
|
||||
/// </summary>
|
||||
/// <param name="parameters">String representation of the parameters</param>
|
||||
public void SetParameters(string parameters)
|
||||
{
|
||||
switch (Options.InternalProgram)
|
||||
{
|
||||
// Dumping support
|
||||
case InternalProgram.Aaru:
|
||||
this.Parameters = new Modules.Aaru.Parameters(parameters) { ExecutablePath = Options.AaruPath };
|
||||
break;
|
||||
|
||||
case InternalProgram.DD:
|
||||
this.Parameters = new Modules.DD.Parameters(parameters) { ExecutablePath = Options.DDPath };
|
||||
break;
|
||||
|
||||
case InternalProgram.DiscImageCreator:
|
||||
this.Parameters = new Modules.DiscImageCreator.Parameters(parameters) { ExecutablePath = Options.DiscImageCreatorPath };
|
||||
break;
|
||||
|
||||
// Verification support only
|
||||
case InternalProgram.CleanRip:
|
||||
this.Parameters = new Modules.CleanRip.Parameters(parameters) { ExecutablePath = null };
|
||||
break;
|
||||
|
||||
case InternalProgram.DCDumper:
|
||||
this.Parameters = null; // TODO: Create correct parameter type when supported
|
||||
break;
|
||||
|
||||
case InternalProgram.UmdImageCreator:
|
||||
this.Parameters = new Modules.UmdImageCreator.Parameters(parameters) { ExecutablePath = null };
|
||||
break;
|
||||
|
||||
// This should never happen, but it needs a fallback
|
||||
default:
|
||||
this.Parameters = new Modules.DiscImageCreator.Parameters(parameters) { ExecutablePath = Options.DiscImageCreatorPath };
|
||||
break;
|
||||
}
|
||||
|
||||
// Set system and type
|
||||
this.Parameters.System = this.System;
|
||||
this.Parameters.Type = this.Type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the full parameter string for either DiscImageCreator or Aaru
|
||||
/// </summary>
|
||||
/// <param name="driveSpeed">Nullable int representing the drive speed</param>
|
||||
/// <returns>String representing the params, null on error</returns>
|
||||
public string GetFullParameters(int? driveSpeed)
|
||||
{
|
||||
// Populate with the correct params for inputs (if we're not on the default option)
|
||||
if (System != null && Type != MediaType.NONE)
|
||||
{
|
||||
// If drive letter is invalid, skip this
|
||||
if (Drive == null)
|
||||
return null;
|
||||
|
||||
// Set the proper parameters
|
||||
string filename = OutputDirectory + Path.DirectorySeparatorChar + OutputFilename;
|
||||
switch (Options.InternalProgram)
|
||||
{
|
||||
case InternalProgram.Aaru:
|
||||
Parameters = new Modules.Aaru.Parameters(System, Type, Drive.Letter, filename, driveSpeed, Options);
|
||||
break;
|
||||
|
||||
case InternalProgram.DD:
|
||||
Parameters = new Modules.DD.Parameters(System, Type, Drive.Letter, filename, driveSpeed, Options);
|
||||
break;
|
||||
|
||||
case InternalProgram.DiscImageCreator:
|
||||
Parameters = new Modules.DiscImageCreator.Parameters(System, Type, Drive.Letter, filename, driveSpeed, Options);
|
||||
break;
|
||||
|
||||
// This should never happen, but it needs a fallback
|
||||
default:
|
||||
Parameters = new Modules.DiscImageCreator.Parameters(System, Type, Drive.Letter, filename, driveSpeed, Options);
|
||||
break;
|
||||
}
|
||||
|
||||
// Generate and return the param string
|
||||
return Parameters.GenerateParameters();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dumping
|
||||
|
||||
/// <summary>
|
||||
/// Cancel an in-progress dumping process
|
||||
/// </summary>
|
||||
public void CancelDumping() => Parameters.KillInternalProgram();
|
||||
|
||||
/// <summary>
|
||||
/// Eject the disc using DiscImageCreator
|
||||
/// </summary>
|
||||
public async Task<string> EjectDisc() =>
|
||||
await RunStandaloneDiscImageCreatorCommand(Modules.DiscImageCreator.CommandStrings.Eject);
|
||||
|
||||
/// <summary>
|
||||
/// Reset the current drive using DiscImageCreator
|
||||
/// </summary>
|
||||
public async Task<string> ResetDrive() =>
|
||||
await RunStandaloneDiscImageCreatorCommand(Modules.DiscImageCreator.CommandStrings.Reset);
|
||||
|
||||
/// <summary>
|
||||
/// Execute the initial invocation of the dumping programs
|
||||
/// </summary>
|
||||
/// <param name="progress">Optional result progress callback</param>
|
||||
public async Task<Result> Run(IProgress<Result> progress = null)
|
||||
{
|
||||
// Check that we have the basics for dumping
|
||||
Result result = IsValidForDump();
|
||||
if (!result)
|
||||
return result;
|
||||
|
||||
// Invoke output processing, if needed
|
||||
if (!Options.ToolsInSeparateWindow)
|
||||
{
|
||||
outputQueue = new ProcessingQueue<string>(ProcessOutputs);
|
||||
Parameters.ReportStatus += OutputToLog;
|
||||
}
|
||||
|
||||
// Execute internal tool
|
||||
progress?.Report(Result.Success($"Executing {Options.InternalProgram}... {(Options.ToolsInSeparateWindow ? "please wait!" : "see log for output!")}"));
|
||||
Directory.CreateDirectory(OutputDirectory);
|
||||
await Task.Run(() => Parameters.ExecuteInternalProgram(Options.ToolsInSeparateWindow));
|
||||
progress?.Report(Result.Success($"{Options.InternalProgram} has finished!"));
|
||||
|
||||
// Execute additional tools
|
||||
progress?.Report(Result.Success("Running any additional tools... see log for output!"));
|
||||
result = await Task.Run(() => ExecuteAdditionalTools());
|
||||
progress?.Report(result);
|
||||
|
||||
// Remove event handler if needed
|
||||
if (!Options.ToolsInSeparateWindow)
|
||||
{
|
||||
outputQueue.Dispose();
|
||||
Parameters.ReportStatus -= OutputToLog;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that the current environment has a complete dump and create submission info is possible
|
||||
/// </summary>
|
||||
/// <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>
|
||||
/// <returns>Result instance with the outcome</returns>
|
||||
public async Task<Result> VerifyAndSaveDumpOutput(
|
||||
IProgress<Result> resultProgress = null,
|
||||
IProgress<ProtectionProgress> protectionProgress = null,
|
||||
Func<SubmissionInfo, (bool?, SubmissionInfo)> processUserInfo = null)
|
||||
{
|
||||
resultProgress?.Report(Result.Success("Gathering submission information... please wait!"));
|
||||
|
||||
// Check to make sure that the output had all the correct files
|
||||
(bool foundFiles, List<string> missingFiles) = InfoTool.FoundAllFiles(this.OutputDirectory, this.OutputFilename, this.Parameters, false);
|
||||
if (!foundFiles)
|
||||
{
|
||||
resultProgress?.Report(Result.Failure($"There were files missing from the output:\n{string.Join("\n", missingFiles)}"));
|
||||
return Result.Failure("Error! Please check output directory as dump may be incomplete!");
|
||||
}
|
||||
|
||||
// Extract the information from the output files
|
||||
resultProgress?.Report(Result.Success("Extracting output information from output files..."));
|
||||
SubmissionInfo submissionInfo = await InfoTool.ExtractOutputInformation(
|
||||
this.OutputDirectory,
|
||||
this.OutputFilename,
|
||||
this.Drive,
|
||||
this.System,
|
||||
this.Type,
|
||||
this.Options,
|
||||
this.Parameters,
|
||||
resultProgress,
|
||||
protectionProgress);
|
||||
resultProgress?.Report(Result.Success("Extracting information complete!"));
|
||||
|
||||
// Eject the disc automatically if configured to
|
||||
if (Options.EjectAfterDump == true)
|
||||
{
|
||||
resultProgress?.Report(Result.Success($"Ejecting disc in drive {Drive.Letter}"));
|
||||
await EjectDisc();
|
||||
}
|
||||
|
||||
// Reset the drive automatically if configured to
|
||||
if (Options.InternalProgram == InternalProgram.DiscImageCreator && Options.DICResetDriveAfterDump)
|
||||
{
|
||||
resultProgress?.Report(Result.Success($"Resetting drive {Drive.Letter}"));
|
||||
await ResetDrive();
|
||||
}
|
||||
|
||||
// Get user-modifiable information if confugured to
|
||||
if (Options.PromptForDiscInformation && processUserInfo != null)
|
||||
{
|
||||
resultProgress?.Report(Result.Success("Waiting for additional disc information..."));
|
||||
|
||||
bool? filledInfo;
|
||||
(filledInfo, submissionInfo) = processUserInfo(submissionInfo);
|
||||
|
||||
if (filledInfo == true)
|
||||
resultProgress?.Report(Result.Success("Additional disc information added!"));
|
||||
else
|
||||
resultProgress?.Report(Result.Success("Disc information skipped!"));
|
||||
}
|
||||
|
||||
// Process special fields for site codes
|
||||
resultProgress?.Report(Result.Success("Processing site codes..."));
|
||||
InfoTool.ProcessSpecialFields(submissionInfo);
|
||||
resultProgress?.Report(Result.Success("Processing complete!"));
|
||||
|
||||
// Format the information for the text output
|
||||
resultProgress?.Report(Result.Success("Formatting information..."));
|
||||
List<string> formattedValues = InfoTool.FormatOutputData(submissionInfo);
|
||||
resultProgress?.Report(Result.Success("Formatting complete!"));
|
||||
|
||||
// Write the text output
|
||||
resultProgress?.Report(Result.Success("Writing information to !submissionInfo.txt..."));
|
||||
bool success = InfoTool.WriteOutputData(this.OutputDirectory, formattedValues);
|
||||
if (success)
|
||||
resultProgress?.Report(Result.Success("Writing complete!"));
|
||||
else
|
||||
resultProgress?.Report(Result.Failure("Writing could not complete!"));
|
||||
|
||||
// Write the JSON output, if required
|
||||
if (Options.OutputSubmissionJSON)
|
||||
{
|
||||
resultProgress?.Report(Result.Success("Writing information to !submissionInfo.json.gz..."));
|
||||
success = InfoTool.WriteOutputData(this.OutputDirectory, submissionInfo);
|
||||
if (success)
|
||||
resultProgress?.Report(Result.Success("Writing complete!"));
|
||||
else
|
||||
resultProgress?.Report(Result.Failure("Writing could not complete!"));
|
||||
}
|
||||
|
||||
// Conpress the logs, if required
|
||||
if (Options.CompressLogFiles)
|
||||
{
|
||||
resultProgress?.Report(Result.Success("Compressing log files..."));
|
||||
success = InfoTool.CompressLogFiles(this.OutputDirectory, this.OutputFilename, this.Parameters);
|
||||
if (success)
|
||||
resultProgress?.Report(Result.Success("Compression complete!"));
|
||||
else
|
||||
resultProgress?.Report(Result.Failure("Compression could not complete!"));
|
||||
}
|
||||
|
||||
resultProgress?.Report(Result.Success("Submission information process complete!"));
|
||||
return Result.Success();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the parameters are valid
|
||||
/// </summary>
|
||||
/// <returns>True if the configuration is valid, false otherwise</returns>
|
||||
internal bool ParametersValid()
|
||||
{
|
||||
bool parametersValid = Parameters.IsValid();
|
||||
bool floppyValid = !(Drive.InternalDriveType == InternalDriveType.Floppy ^ Type == MediaType.FloppyDisk);
|
||||
|
||||
// TODO: HardDisk being in the Removable category is a hack, fix this later
|
||||
bool removableDiskValid = !((Drive.InternalDriveType == InternalDriveType.Removable || Drive.InternalDriveType == InternalDriveType.HardDisk)
|
||||
^ (Type == MediaType.CompactFlash || Type == MediaType.SDCard || Type == MediaType.FlashDrive || Type == MediaType.HardDisk));
|
||||
|
||||
return parametersValid && floppyValid && removableDiskValid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run any additional tools given a DumpEnvironment
|
||||
/// </summary>
|
||||
/// <returns>Result instance with the outcome</returns>
|
||||
private Result ExecuteAdditionalTools() => Result.Success("No external tools needed!");
|
||||
|
||||
/// <summary>
|
||||
/// Run internal program async with an input set of parameters
|
||||
/// </summary>
|
||||
/// <param name="parameters"></param>
|
||||
/// <returns>Standard output from commandline window</returns>
|
||||
private async Task<string> ExecuteInternalProgram(BaseParameters parameters)
|
||||
{
|
||||
Process childProcess;
|
||||
string output = await Task.Run(() =>
|
||||
{
|
||||
childProcess = new Process()
|
||||
{
|
||||
StartInfo = new ProcessStartInfo()
|
||||
{
|
||||
FileName = parameters.ExecutablePath,
|
||||
Arguments = parameters.GenerateParameters(),
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardOutput = true,
|
||||
},
|
||||
};
|
||||
childProcess.Start();
|
||||
childProcess.WaitForExit(1000);
|
||||
|
||||
// Just in case, we want to push a button 5 times to clear any errors
|
||||
for (int i = 0; i < 5; i++)
|
||||
childProcess.StandardInput.WriteLine("Y");
|
||||
|
||||
string stdout = childProcess.StandardOutput.ReadToEnd();
|
||||
childProcess.Dispose();
|
||||
return stdout;
|
||||
});
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate the current environment is ready for a dump
|
||||
/// </summary>
|
||||
/// <returns>Result instance with the outcome</returns>
|
||||
private Result IsValidForDump()
|
||||
{
|
||||
// Validate that everything is good
|
||||
if (!ParametersValid())
|
||||
return Result.Failure("Error! Current configuration is not supported!");
|
||||
|
||||
// Fix the output paths, just in case
|
||||
(OutputDirectory, OutputFilename) = InfoTool.NormalizeOutputPaths(OutputDirectory, OutputFilename);
|
||||
|
||||
// Validate that the output path isn't on the dumping drive
|
||||
string fullOutputPath = Path.GetFullPath(Path.Combine(OutputDirectory, OutputFilename));
|
||||
if (fullOutputPath[0] == Drive.Letter)
|
||||
return Result.Failure($"Error! Cannot output to same drive that is being dumped!");
|
||||
|
||||
// Validate that the required program exists
|
||||
if (!File.Exists(Parameters.ExecutablePath))
|
||||
return Result.Failure($"Error! {Parameters.ExecutablePath} does not exist!");
|
||||
|
||||
// Validate that the dumping drive doesn't contain the executable
|
||||
string fullExecutablePath = Path.GetFullPath(Parameters.ExecutablePath);
|
||||
if (fullExecutablePath[0] == Drive.Letter)
|
||||
return Result.Failure("$Error! Cannot dump same drive that executable resides on!");
|
||||
|
||||
// Validate that the current configuration is supported
|
||||
return Tools.GetSupportStatus(System, Type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate that DIscImageCreator is able to be found
|
||||
/// </summary>
|
||||
/// <returns>True if DiscImageCreator is found properly, false otherwise</returns>
|
||||
private bool RequiredProgramsExist()
|
||||
{
|
||||
// Validate that the path is configured
|
||||
if (string.IsNullOrWhiteSpace(Options.DiscImageCreatorPath))
|
||||
return false;
|
||||
|
||||
// Validate that the required program exists
|
||||
if (!File.Exists(Options.DiscImageCreatorPath))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run a standalone DiscImageCreator command
|
||||
/// </summary>
|
||||
/// <param name="command">Command string to run</param>
|
||||
/// <returns>The output of the command on success, null on error</returns>
|
||||
private async Task<string> RunStandaloneDiscImageCreatorCommand(string command)
|
||||
{
|
||||
// Validate that DiscImageCreator is all set
|
||||
if (!RequiredProgramsExist())
|
||||
return null;
|
||||
|
||||
// Validate we're not trying to eject a non-optical
|
||||
if (Drive.InternalDriveType != InternalDriveType.Optical)
|
||||
return null;
|
||||
|
||||
CancelDumping();
|
||||
|
||||
var parameters = new Modules.DiscImageCreator.Parameters(string.Empty)
|
||||
{
|
||||
BaseCommand = command,
|
||||
DriveLetter = Drive.Letter.ToString(),
|
||||
ExecutablePath = Options.DiscImageCreatorPath,
|
||||
};
|
||||
|
||||
return await ExecuteInternalProgram(parameters);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
2034
MPF.Library/InfoTool.cs
Normal file
2034
MPF.Library/InfoTool.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net48;netcoreapp3.1</TargetFrameworks>
|
||||
<TargetFrameworks>net48;netcoreapp3.1;net5.0</TargetFrameworks>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<Title>MPF Library</Title>
|
||||
<AssemblyName>MPF.Library</AssemblyName>
|
||||
<Description>Library code for MPF and MPF.Check</Description>
|
||||
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
|
||||
<Copyright>Copyright (c)2019-2021</Copyright>
|
||||
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
|
||||
<Version>2.1</Version>
|
||||
<Version>2.3</Version>
|
||||
<AssemblyVersion>$(Version)</AssemblyVersion>
|
||||
<FileVersion>$(Version)</FileVersion>
|
||||
<IncludeSource>true</IncludeSource>
|
||||
@@ -23,63 +21,22 @@
|
||||
<NrtShowRevision>false</NrtShowRevision>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)'!='netcoreapp3.1'">
|
||||
<PropertyGroup Condition="'$(TargetFramework)'=='net48'">
|
||||
<DefineConstants>NET_FRAMEWORK</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)'!='netcoreapp3.1'">
|
||||
<COMReference Include="IMAPI2">
|
||||
<Guid>{2735412F-7F64-5B0F-8F00-5D77AFBE261E}</Guid>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>0</VersionMinor>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<Isolated>False</Isolated>
|
||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
<COMReference Include="IMAPI2FS">
|
||||
<Guid>{2C941FD0-975B-59BE-A960-9A2A262853A5}</Guid>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>0</VersionMinor>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<Isolated>False</Isolated>
|
||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MPF.Core\MPF.Core.csproj" />
|
||||
<ProjectReference Include="..\MPF.Modules\MPF.Modules.csproj" />
|
||||
<ProjectReference Include="..\RedumpLib\RedumpLib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Aaru\CICMMetadata\CICMMetadataEditor\**" />
|
||||
<Compile Remove="Aaru\CICMMetadata\java\**" />
|
||||
<Compile Remove="Aaru\CICMMetadata\samples\**" />
|
||||
<EmbeddedResource Remove="Aaru\CICMMetadata\CICMMetadataEditor\**" />
|
||||
<EmbeddedResource Remove="Aaru\CICMMetadata\java\**" />
|
||||
<EmbeddedResource Remove="Aaru\CICMMetadata\samples\**" />
|
||||
<None Remove="Aaru\CICMMetadata\CICMMetadataEditor\**" />
|
||||
<None Remove="Aaru\CICMMetadata\java\**" />
|
||||
<None Remove="Aaru\CICMMetadata\samples\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Aaru\CICMMetadata\.editorconfig" />
|
||||
<None Remove="Aaru\CICMMetadata\.git" />
|
||||
<None Remove="Aaru\CICMMetadata\.gitignore" />
|
||||
<None Remove="Aaru\CICMMetadata\.project" />
|
||||
<None Remove="Aaru\CICMMetadata\build.sh" />
|
||||
<None Remove="Aaru\CICMMetadata\cicm.xml" />
|
||||
<None Remove="Aaru\CICMMetadata\cicm.xsd" />
|
||||
<None Remove="Aaru\CICMMetadata\CICMMetadata.iml" />
|
||||
<None Remove="Aaru\CICMMetadata\dotnet\cicm.vb" />
|
||||
<None Remove="Aaru\CICMMetadata\README.md" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="1.7.0" GeneratePathProperty="true">
|
||||
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="1.8.0" GeneratePathProperty="true">
|
||||
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
|
||||
<PackageReference Include="System.Management" Version="6.0.0-preview.6.21352.12" />
|
||||
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
@@ -90,8 +47,4 @@
|
||||
<Content Include="$(PkgBurnOutSharp)\content\**" PackagePath="contentFiles\any\any;content" CopyToOutputDirectory="Always" PackageCopyToOutput="true" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Management" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
304
MPF.Library/Protection.cs
Normal file
304
MPF.Library/Protection.cs
Normal file
@@ -0,0 +1,304 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using BurnOutSharp;
|
||||
using BurnOutSharp.External.psxt001z;
|
||||
using BurnOutSharp.ProtectionType;
|
||||
using MPF.Core.Data;
|
||||
|
||||
namespace MPF.Library
|
||||
{
|
||||
public static class Protection
|
||||
{
|
||||
/// <summary>
|
||||
/// Run protection scan on a given dump environment
|
||||
/// </summary>
|
||||
/// <param name="path">Path to scan for protection</param>
|
||||
/// <param name="options">Options object that determines what to scan</param>
|
||||
/// <param name="progress">Optional progress callback</param>
|
||||
/// <returns>TCopy protection detected in the envirionment, if any</returns>
|
||||
public static async Task<(bool, string)> RunProtectionScanOnPath(string path, Options options, IProgress<ProtectionProgress> progress = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var found = await Task.Run(() =>
|
||||
{
|
||||
var scanner = new Scanner(progress)
|
||||
{
|
||||
IncludeDebug = options.IncludeDebugProtectionInformation,
|
||||
ScanAllFiles = options.ForceScanningForProtection,
|
||||
ScanArchives = options.ScanArchivesForProtection,
|
||||
ScanPackers = options.ScanPackersForProtection,
|
||||
};
|
||||
return scanner.GetProtections(path);
|
||||
});
|
||||
|
||||
if (found == null || found.Count() == 0)
|
||||
return (true, "None found");
|
||||
|
||||
// Get an ordered list of distinct found protections
|
||||
var orderedDistinctProtections = found
|
||||
.Where(kvp => kvp.Value != null && kvp.Value.Any())
|
||||
.SelectMany(kvp => kvp.Value)
|
||||
.Distinct()
|
||||
.OrderBy(p => p);
|
||||
|
||||
// Sanitize and join protections for writing
|
||||
string protections = SanitizeFoundProtections(orderedDistinctProtections);
|
||||
return (true, protections);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (false, ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the existence of an anti-modchip string from a PlayStation disc, if possible
|
||||
/// </summary>
|
||||
/// <param name="path">Path to scan for anti-modchip strings</param>
|
||||
/// <returns>Anti-modchip existence if possible, false on error</returns>
|
||||
public static async Task<bool> GetPlayStationAntiModchipDetected(string path)
|
||||
{
|
||||
return await Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var antiModchip = new PSXAntiModchip();
|
||||
foreach (string file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories))
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] fileContent = File.ReadAllBytes(file);
|
||||
string protection = antiModchip.CheckContents(file, fileContent, false, null, null);
|
||||
if (!string.IsNullOrWhiteSpace(protection))
|
||||
return true;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get if LibCrypt data is detected in the subchannel file, if possible
|
||||
/// </summary>
|
||||
/// <param name="sub">.sub file location</param>
|
||||
/// <returns>Status of the LibCrypt data, if possible</returns>
|
||||
public static bool? GetLibCryptDetected(string sub)
|
||||
{
|
||||
// If the file doesn't exist, we can't get info from it
|
||||
if (!File.Exists(sub))
|
||||
return null;
|
||||
|
||||
return LibCrypt.CheckSubfile(sub);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sanitize unnecessary protection duplication from output
|
||||
/// </summary>
|
||||
/// <param name="foundProtections">Enumerable of found protections</param>
|
||||
public static string SanitizeFoundProtections(IEnumerable<string> foundProtections)
|
||||
{
|
||||
// ActiveMARK
|
||||
if (foundProtections.Any(p => p == "ActiveMARK 5") && foundProtections.Any(p => p == "ActiveMARK"))
|
||||
foundProtections = foundProtections.Where(p => p != "ActiveMARK");
|
||||
|
||||
// Cactus Data Shield
|
||||
if (foundProtections.Any(p => Regex.IsMatch(p, @"Cactus Data Shield [0-9]{3} .+")) && foundProtections.Any(p => p == "Cactus Data Shield 200"))
|
||||
foundProtections = foundProtections.Where(p => p != "Cactus Data Shield 200");
|
||||
|
||||
// CD-Check
|
||||
foundProtections = foundProtections.Where(p => p != "Executable-Based CD Check");
|
||||
|
||||
// CD-Cops
|
||||
if (foundProtections.Any(p => p == "CD-Cops") && foundProtections.Any(p => p.StartsWith("CD-Cops") && p.Length > "CD-Cops".Length))
|
||||
foundProtections = foundProtections.Where(p => p != "CD-Cops");
|
||||
|
||||
// CD-Key / Serial
|
||||
foundProtections = foundProtections.Where(p => p != "CD-Key / Serial");
|
||||
|
||||
// Electronic Arts
|
||||
if (foundProtections.Any(p => p == "EA CdKey Registration Module") && foundProtections.Any(p => p.StartsWith("EA CdKey Registration Module") && p.Length > "EA CdKey Registration Module".Length))
|
||||
foundProtections = foundProtections.Where(p => p != "EA CdKey Registration Module");
|
||||
if (foundProtections.Any(p => p == "EA DRM Protection") && foundProtections.Any(p => p.StartsWith("EA DRM Protection") && p.Length > "EA DRM Protection".Length))
|
||||
foundProtections = foundProtections.Where(p => p != "EA DRM Protection");
|
||||
|
||||
// Games for Windows LIVE
|
||||
if (foundProtections.Any(p => p == "Games for Windows LIVE") && foundProtections.Any(p => p.StartsWith("Games for Windows LIVE") && !p.Contains("Zero Day Piracy Protection") && p.Length > "Games for Windows LIVE".Length))
|
||||
foundProtections = foundProtections.Where(p => p != "Games for Windows LIVE");
|
||||
|
||||
// Impulse Reactor
|
||||
if (foundProtections.Any(p => p.StartsWith("Impulse Reactor Core Module")) && foundProtections.Any(p => p == "Impulse Reactor"))
|
||||
foundProtections = foundProtections.Where(p => p != "Impulse Reactor");
|
||||
|
||||
// JoWood X-Prot
|
||||
if (foundProtections.Any(p => p.StartsWith("JoWood X-Prot")))
|
||||
{
|
||||
if (foundProtections.Any(p => Regex.IsMatch(p, @"JoWood X-Prot [0-9]\.[0-9]\.[0-9]\.[0-9]{2}")))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "JoWood X-Prot")
|
||||
.Where(p => p != "JoWood X-Prot v1.0-v1.3")
|
||||
.Where(p => p != "JoWood X-Prot v1.4+")
|
||||
.Where(p => p != "JoWood X-Prot v2");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "JoWood X-Prot v2"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "JoWood X-Prot")
|
||||
.Where(p => p != "JoWood X-Prot v1.0-v1.3")
|
||||
.Where(p => p != "JoWood X-Prot v1.4+");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "JoWood X-Prot v1.4+"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "JoWood X-Prot")
|
||||
.Where(p => p != "JoWood X-Prot v1.0-v1.3");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "JoWood X-Prot v1.0-v1.3"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "JoWood X-Prot");
|
||||
}
|
||||
}
|
||||
|
||||
// LaserLok
|
||||
// TODO: Figure this one out
|
||||
|
||||
// Online Registration
|
||||
foundProtections = foundProtections.Where(p => !p.StartsWith("Executable-Based Online Registration"));
|
||||
|
||||
// ProtectDISC / VOB ProtectCD/DVD
|
||||
// TODO: Figure this one out
|
||||
|
||||
// SafeCast
|
||||
// TODO: Figure this one out
|
||||
|
||||
// SafeDisc
|
||||
if (foundProtections.Any(p => p.StartsWith("SafeDisc")))
|
||||
{
|
||||
if (foundProtections.Any(p => Regex.IsMatch(p, @"SafeDisc [0-9]\.[0-9]{2}\.[0-9]{3}")))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "SafeDisc")
|
||||
.Where(p => p != "SafeDisc 1/Lite")
|
||||
.Where(p => p != "SafeDisc 1-3")
|
||||
.Where(p => p != "SafeDisc 2")
|
||||
.Where(p => p != "SafeDisc 3.20-4.xx (version removed)")
|
||||
.Where(p => !p.StartsWith("SafeDisc (dplayerx.dll)"))
|
||||
.Where(p => !p.StartsWith("SafeDisc (drvmgt.dll)"))
|
||||
.Where(p => !p.StartsWith("SafeDisc (secdrv.sys)"))
|
||||
.Where(p => p != "SafeDisc Lite");
|
||||
}
|
||||
else if (foundProtections.Any(p => p.StartsWith("SafeDisc (drvmgt.dll)")))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "SafeDisc")
|
||||
.Where(p => p != "SafeDisc 1/Lite")
|
||||
.Where(p => p != "SafeDisc 1-3")
|
||||
.Where(p => p != "SafeDisc 2")
|
||||
.Where(p => p != "SafeDisc 3.20-4.xx (version removed)")
|
||||
.Where(p => !p.StartsWith("SafeDisc (dplayerx.dll)"))
|
||||
.Where(p => !p.StartsWith("SafeDisc (secdrv.sys)"))
|
||||
.Where(p => p != "SafeDisc Lite");
|
||||
}
|
||||
else if (foundProtections.Any(p => p.StartsWith("SafeDisc (secdrv.sys)")))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "SafeDisc")
|
||||
.Where(p => p != "SafeDisc 1/Lite")
|
||||
.Where(p => p != "SafeDisc 1-3")
|
||||
.Where(p => p != "SafeDisc 2")
|
||||
.Where(p => p != "SafeDisc 3.20-4.xx (version removed)")
|
||||
.Where(p => !p.StartsWith("SafeDisc (dplayerx.dll)"))
|
||||
.Where(p => p != "SafeDisc Lite");
|
||||
}
|
||||
else if (foundProtections.Any(p => p.StartsWith("SafeDisc (dplayerx.dll)")))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "SafeDisc")
|
||||
.Where(p => p != "SafeDisc 1/Lite")
|
||||
.Where(p => p != "SafeDisc 1-3")
|
||||
.Where(p => p != "SafeDisc 2")
|
||||
.Where(p => p != "SafeDisc 3.20-4.xx (version removed)")
|
||||
.Where(p => p != "SafeDisc Lite");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "SafeDisc 3.20-4.xx (version removed)"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "SafeDisc")
|
||||
.Where(p => p != "SafeDisc 1/Lite")
|
||||
.Where(p => p != "SafeDisc 1-3")
|
||||
.Where(p => p != "SafeDisc 2")
|
||||
.Where(p => p != "SafeDisc Lite");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "SafeDisc 2"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "SafeDisc")
|
||||
.Where(p => p != "SafeDisc 1/Lite")
|
||||
.Where(p => p != "SafeDisc 1-3")
|
||||
.Where(p => p != "SafeDisc Lite");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "SafeDisc 1/Lite"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "SafeDisc")
|
||||
.Where(p => p != "SafeDisc 1-3")
|
||||
.Where(p => p != "SafeDisc Lite");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "SafeDisc Lite"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "SafeDisc")
|
||||
.Where(p => p != "SafeDisc 1-3");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "SafeDisc 1-3"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "SafeDisc");
|
||||
}
|
||||
}
|
||||
|
||||
// SecuROM
|
||||
// TODO: Figure this one out
|
||||
|
||||
// SolidShield
|
||||
// TODO: Figure this one out
|
||||
|
||||
// StarForce
|
||||
if (foundProtections.Any(p => p.StartsWith("StarForce")))
|
||||
{
|
||||
if (foundProtections.Any(p => Regex.IsMatch(p, @"StarForce [0-9]+\..+")))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "StarForce")
|
||||
.Where(p => p != "StarForce 3-5")
|
||||
.Where(p => p != "StarForce 5")
|
||||
.Where(p => p != "StarForce 5 [Protected Module]");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "StarForce 5 [Protected Module]"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "StarForce")
|
||||
.Where(p => p != "StarForce 3-5")
|
||||
.Where(p => p != "StarForce 5");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "StarForce 5"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "StarForce")
|
||||
.Where(p => p != "StarForce 3-5");
|
||||
}
|
||||
else if (foundProtections.Any(p => p == "StarForce 3-5"))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => p != "StarForce");
|
||||
}
|
||||
}
|
||||
|
||||
// Sysiphus
|
||||
if (foundProtections.Any(p => p == "Sysiphus") && foundProtections.Any(p => p.StartsWith("Sysiphus") && p.Length > "Sysiphus".Length))
|
||||
foundProtections = foundProtections.Where(p => p != "Sysiphus");
|
||||
|
||||
// TAGES
|
||||
// TODO: Figure this one out
|
||||
|
||||
// XCP
|
||||
if (foundProtections.Any(p => p == "XCP") && foundProtections.Any(p => p.StartsWith("XCP") && p.Length > "XCP".Length))
|
||||
foundProtections = foundProtections.Where(p => p != "XCP");
|
||||
|
||||
return string.Join(", ", foundProtections);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
using MPF.Data;
|
||||
|
||||
namespace MPF.Redump
|
||||
{
|
||||
/// <summary>
|
||||
/// Information pertaining to Redump systems
|
||||
/// </summary>
|
||||
public static class Extras
|
||||
{
|
||||
#region Special lists
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that are not publically accessible
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem?[] BannedSystems = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.AudioCD,
|
||||
RedumpSystem.BDVideo,
|
||||
RedumpSystem.DVDVideo,
|
||||
RedumpSystem.HasbroVideoNow,
|
||||
RedumpSystem.HasbroVideoNowColor,
|
||||
RedumpSystem.HasbroVideoNowJr,
|
||||
RedumpSystem.HasbroVideoNowXP,
|
||||
RedumpSystem.KonamiM2,
|
||||
RedumpSystem.MicrosoftXbox360,
|
||||
RedumpSystem.MicrosoftXboxOne,
|
||||
//RedumpSystem.MicrosoftXboxSeriesXS,
|
||||
RedumpSystem.NavisoftNaviken21,
|
||||
RedumpSystem.NintendoWii,
|
||||
RedumpSystem.NintendoWiiU,
|
||||
RedumpSystem.PanasonicM2,
|
||||
RedumpSystem.SegaPrologue21,
|
||||
RedumpSystem.SegaRingEdge,
|
||||
RedumpSystem.SegaRingEdge2,
|
||||
RedumpSystem.SonyPlayStation3,
|
||||
RedumpSystem.SonyPlayStation4,
|
||||
//RedumpSystem.SonyPlayStation5,
|
||||
RedumpSystem.VideoCD,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that have a Cues pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem?[] HasCues = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.AppleMacintosh,
|
||||
RedumpSystem.AtariJaguarCDInteractiveMultimediaSystem,
|
||||
RedumpSystem.AudioCD,
|
||||
RedumpSystem.BandaiPippin,
|
||||
RedumpSystem.BandaiPlaydiaQuickInteractiveSystem,
|
||||
RedumpSystem.CommodoreAmigaCD,
|
||||
RedumpSystem.CommodoreAmigaCD32,
|
||||
RedumpSystem.CommodoreAmigaCDTV,
|
||||
RedumpSystem.FujitsuFMTownsseries,
|
||||
RedumpSystem.funworldPhotoPlay,
|
||||
RedumpSystem.HasbroVideoNow,
|
||||
RedumpSystem.HasbroVideoNowColor,
|
||||
RedumpSystem.HasbroVideoNowJr,
|
||||
RedumpSystem.HasbroVideoNowXP,
|
||||
RedumpSystem.IBMPCcompatible,
|
||||
RedumpSystem.IncredibleTechnologiesEagle,
|
||||
RedumpSystem.KonamieAmusement,
|
||||
RedumpSystem.KonamiFireBeat,
|
||||
RedumpSystem.KonamiM2,
|
||||
RedumpSystem.KonamiSystemGV,
|
||||
RedumpSystem.MattelFisherPriceiXL,
|
||||
RedumpSystem.MattelHyperScan,
|
||||
RedumpSystem.MemorexVisualInformationSystem,
|
||||
RedumpSystem.MicrosoftXbox,
|
||||
RedumpSystem.MicrosoftXbox360,
|
||||
RedumpSystem.NamcoSegaNintendoTriforce,
|
||||
RedumpSystem.NamcoSystem246,
|
||||
RedumpSystem.NavisoftNaviken21,
|
||||
RedumpSystem.NECPCEngineCDTurboGrafxCD,
|
||||
RedumpSystem.NECPC88series,
|
||||
RedumpSystem.NECPC98series,
|
||||
RedumpSystem.NECPCFXPCFXGA,
|
||||
RedumpSystem.PalmOS,
|
||||
RedumpSystem.Panasonic3DOInteractiveMultiplayer,
|
||||
RedumpSystem.PanasonicM2,
|
||||
RedumpSystem.PhilipsCDi,
|
||||
RedumpSystem.PhotoCD,
|
||||
RedumpSystem.PlayStationGameSharkUpdates,
|
||||
RedumpSystem.SegaChihiro,
|
||||
RedumpSystem.SegaDreamcast,
|
||||
RedumpSystem.SegaMegaCDSegaCD,
|
||||
RedumpSystem.SegaNaomi,
|
||||
RedumpSystem.SegaNaomi2,
|
||||
RedumpSystem.SegaPrologue21,
|
||||
RedumpSystem.SegaSaturn,
|
||||
RedumpSystem.SNKNeoGeoCD,
|
||||
RedumpSystem.SonyPlayStation,
|
||||
RedumpSystem.SonyPlayStation2,
|
||||
RedumpSystem.SonyPlayStation3,
|
||||
RedumpSystem.TABAustriaQuizard,
|
||||
RedumpSystem.TomyKissSite,
|
||||
RedumpSystem.VideoCD,
|
||||
RedumpSystem.VTechVFlashVSmilePro,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that has a Dat pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem?[] HasDat = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.MicrosoftXboxBIOS,
|
||||
RedumpSystem.NintendoGameCubeBIOS,
|
||||
RedumpSystem.SonyPlayStationBIOS,
|
||||
RedumpSystem.SonyPlayStation2BIOS,
|
||||
|
||||
RedumpSystem.AppleMacintosh,
|
||||
RedumpSystem.AtariJaguarCDInteractiveMultimediaSystem,
|
||||
RedumpSystem.AudioCD,
|
||||
RedumpSystem.BandaiPippin,
|
||||
RedumpSystem.BandaiPlaydiaQuickInteractiveSystem,
|
||||
RedumpSystem.BDVideo,
|
||||
RedumpSystem.CommodoreAmigaCD,
|
||||
RedumpSystem.CommodoreAmigaCD32,
|
||||
RedumpSystem.CommodoreAmigaCDTV,
|
||||
RedumpSystem.DVDVideo,
|
||||
RedumpSystem.FujitsuFMTownsseries,
|
||||
RedumpSystem.funworldPhotoPlay,
|
||||
RedumpSystem.HasbroVideoNow,
|
||||
RedumpSystem.HasbroVideoNowColor,
|
||||
RedumpSystem.HasbroVideoNowJr,
|
||||
RedumpSystem.HasbroVideoNowXP,
|
||||
RedumpSystem.IBMPCcompatible,
|
||||
RedumpSystem.IncredibleTechnologiesEagle,
|
||||
RedumpSystem.KonamieAmusement,
|
||||
RedumpSystem.KonamiFireBeat,
|
||||
RedumpSystem.KonamiM2,
|
||||
RedumpSystem.KonamiSystemGV,
|
||||
RedumpSystem.MattelFisherPriceiXL,
|
||||
RedumpSystem.MattelHyperScan,
|
||||
RedumpSystem.MemorexVisualInformationSystem,
|
||||
RedumpSystem.MicrosoftXbox,
|
||||
RedumpSystem.MicrosoftXbox360,
|
||||
RedumpSystem.MicrosoftXboxOne,
|
||||
//RedumpSystem.MicrosoftXboxSeriesXS,
|
||||
RedumpSystem.NamcoSegaNintendoTriforce,
|
||||
RedumpSystem.NamcoSystem246,
|
||||
RedumpSystem.NavisoftNaviken21,
|
||||
RedumpSystem.NECPCEngineCDTurboGrafxCD,
|
||||
RedumpSystem.NECPC88series,
|
||||
RedumpSystem.NECPC98series,
|
||||
RedumpSystem.NECPCFXPCFXGA,
|
||||
RedumpSystem.NintendoGameCube,
|
||||
RedumpSystem.NintendoWii,
|
||||
RedumpSystem.NintendoWiiU,
|
||||
RedumpSystem.PalmOS,
|
||||
RedumpSystem.Panasonic3DOInteractiveMultiplayer,
|
||||
RedumpSystem.PanasonicM2,
|
||||
RedumpSystem.PhilipsCDi,
|
||||
RedumpSystem.PhotoCD,
|
||||
RedumpSystem.PlayStationGameSharkUpdates,
|
||||
RedumpSystem.SegaChihiro,
|
||||
RedumpSystem.SegaDreamcast,
|
||||
RedumpSystem.SegaLindbergh,
|
||||
RedumpSystem.SegaMegaCDSegaCD,
|
||||
RedumpSystem.SegaNaomi,
|
||||
RedumpSystem.SegaNaomi2,
|
||||
RedumpSystem.SegaRingEdge,
|
||||
RedumpSystem.SegaRingEdge2,
|
||||
RedumpSystem.SegaSaturn,
|
||||
RedumpSystem.SNKNeoGeoCD,
|
||||
RedumpSystem.SonyPlayStation,
|
||||
RedumpSystem.SonyPlayStation2,
|
||||
RedumpSystem.SonyPlayStation3,
|
||||
RedumpSystem.SonyPlayStation4,
|
||||
//RedumpSystem.SonyPlayStation5,
|
||||
RedumpSystem.SonyPlayStationPortable,
|
||||
RedumpSystem.TABAustriaQuizard,
|
||||
RedumpSystem.TomyKissSite,
|
||||
RedumpSystem.VideoCD,
|
||||
RedumpSystem.VMLabsNUON,
|
||||
RedumpSystem.VTechVFlashVSmilePro,
|
||||
RedumpSystem.ZAPiTGamesGameWaveFamilyEntertainmentSystem,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that has a Decrypted Keys pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem?[] HasDkeys = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.SonyPlayStation3,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that has a GDI pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem?[] HasGdi = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.NamcoSegaNintendoTriforce,
|
||||
RedumpSystem.SegaChihiro,
|
||||
RedumpSystem.SegaDreamcast,
|
||||
RedumpSystem.SegaNaomi,
|
||||
RedumpSystem.SegaNaomi2,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that has a Keys pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem?[] HasKeys = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.NintendoWiiU,
|
||||
RedumpSystem.SonyPlayStation3,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that has an LSD pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem?[] HasLsd = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.IBMPCcompatible,
|
||||
RedumpSystem.SonyPlayStation,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of systems that has an SBI pack
|
||||
/// </summary>
|
||||
public static readonly RedumpSystem?[] HasSbi = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.IBMPCcompatible,
|
||||
RedumpSystem.SonyPlayStation,
|
||||
};
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,119 +0,0 @@
|
||||
using MPF.Data;
|
||||
|
||||
namespace MPF.Utilities
|
||||
{
|
||||
public static class EnumExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Determine the category based on the system
|
||||
/// </summary>
|
||||
/// <param name="system">KnownSystem value to check</param>
|
||||
/// <returns>KnownSystemCategory related to the system</returns>
|
||||
public static KnownSystemCategory Category(this KnownSystem? system)
|
||||
{
|
||||
if (system < KnownSystem.MarkerDiscBasedConsoleEnd)
|
||||
return KnownSystemCategory.DiscBasedConsole;
|
||||
/*
|
||||
else if (system < KnownSystem.MarkerOtherConsoleEnd)
|
||||
return KnownSystemCategory.OtherConsole;
|
||||
*/
|
||||
else if (system < KnownSystem.MarkerComputerEnd)
|
||||
return KnownSystemCategory.Computer;
|
||||
else if (system < KnownSystem.MarkerArcadeEnd)
|
||||
return KnownSystemCategory.Arcade;
|
||||
else if (system < KnownSystem.MarkerOtherEnd)
|
||||
return KnownSystemCategory.Other;
|
||||
else
|
||||
return KnownSystemCategory.Custom;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if the media supports drive speeds
|
||||
/// </summary>
|
||||
/// <param name="type">MediaType value to check</param>
|
||||
/// <returns>True if the media has variable dumping speeds, false otherwise</returns>
|
||||
public static bool DoesSupportDriveSpeed(this MediaType? type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
case MediaType.DVD:
|
||||
case MediaType.GDROM:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.BluRay:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if a system is considered audio-only
|
||||
/// </summary>
|
||||
/// <param name="system">KnownSystem value to check</param>
|
||||
/// <returns>True if the system is audio-only, false otherwise</returns>
|
||||
/// <remarks>
|
||||
/// Philips CD-i should NOT be in this list. It's being included until there's a
|
||||
/// reasonable distinction between CD-i and CD-i ready on the database side.
|
||||
/// </remarks>
|
||||
public static bool IsAudio(this KnownSystem? system)
|
||||
{
|
||||
switch (system)
|
||||
{
|
||||
case KnownSystem.AtariJaguarCD:
|
||||
case KnownSystem.AudioCD:
|
||||
case KnownSystem.DVDAudio:
|
||||
case KnownSystem.HasbroVideoNow:
|
||||
case KnownSystem.HasbroVideoNowColor:
|
||||
case KnownSystem.HasbroVideoNowJr:
|
||||
case KnownSystem.HasbroVideoNowXP:
|
||||
case KnownSystem.PhilipsCDi:
|
||||
case KnownSystem.SuperAudioCD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if a system is a marker value
|
||||
/// </summary>
|
||||
/// <param name="system">KnownSystem value to check</param>
|
||||
/// <returns>True if the system is a marker value, false otherwise</returns>
|
||||
public static bool IsMarker(this KnownSystem? system)
|
||||
{
|
||||
switch (system)
|
||||
{
|
||||
case KnownSystem.MarkerArcadeEnd:
|
||||
case KnownSystem.MarkerComputerEnd:
|
||||
case KnownSystem.MarkerDiscBasedConsoleEnd:
|
||||
// case KnownSystem.MarkerOtherConsoleEnd:
|
||||
case KnownSystem.MarkerOtherEnd:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if a system is considered XGD
|
||||
/// </summary>
|
||||
/// <param name="system">KnownSystem value to check</param>
|
||||
/// <returns>True if the system is XGD, false otherwise</returns>
|
||||
public static bool IsXGD(this KnownSystem? system)
|
||||
{
|
||||
switch (system)
|
||||
{
|
||||
case KnownSystem.MicrosoftXBOX:
|
||||
case KnownSystem.MicrosoftXBOX360:
|
||||
case KnownSystem.MicrosoftXBOXOne:
|
||||
case KnownSystem.MicrosoftXboxSeriesXS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
namespace MPF.Aaru
|
||||
namespace MPF.Modules.Aaru
|
||||
{
|
||||
/// <summary>
|
||||
/// Top-level commands for Aaru
|
||||
@@ -7,6 +7,11 @@ namespace MPF.Aaru
|
||||
{
|
||||
public const string NONE = "";
|
||||
|
||||
// Archive Family
|
||||
public const string ArchivePrefixShort = "arc";
|
||||
public const string ArchivePrefixLong = "archive";
|
||||
public const string ArchiveInfo = "info";
|
||||
|
||||
// Database Family
|
||||
public const string DatabasePrefixShort = "db";
|
||||
public const string DatabasePrefixLong = "database";
|
||||
@@ -25,6 +30,7 @@ namespace MPF.Aaru
|
||||
public const string FilesystemPrefixShortAlt = "fs";
|
||||
public const string FilesystemPrefixLong = "filesystem";
|
||||
public const string FilesystemExtract = "extract";
|
||||
public const string FilesystemInfo = "info";
|
||||
public const string FilesystemListShort = "ls";
|
||||
public const string FilesystemListLong = "list";
|
||||
public const string FilesystemOptions = "options";
|
||||
@@ -32,7 +38,6 @@ namespace MPF.Aaru
|
||||
// Image Family
|
||||
public const string ImagePrefixShort = "i";
|
||||
public const string ImagePrefixLong = "image";
|
||||
public const string ImageAnalyze = "analyze";
|
||||
public const string ImageChecksumShort = "chk";
|
||||
public const string ImageChecksumLong = "checksum";
|
||||
public const string ImageCompareShort = "cmp";
|
||||
@@ -149,6 +154,7 @@ namespace MPF.Aaru
|
||||
public const string MetadataLong = "--metadata";
|
||||
public const string PartitionsShort = "-p";
|
||||
public const string PartitionsLong = "--partitions";
|
||||
public const string PauseLong = "--pause";
|
||||
public const string PersistentLong = "--persistent";
|
||||
public const string PrivateLong = "--private";
|
||||
public const string ResumeShort = "-r";
|
||||
@@ -168,9 +174,14 @@ namespace MPF.Aaru
|
||||
public const string SpamSumLong = "--spamsum";
|
||||
public const string StopOnErrorShort = "-s";
|
||||
public const string StopOnErrorLong = "--stop-on-error";
|
||||
public const string StoreEncryptedLong = "--store-encrypted";
|
||||
public const string TapeShort = "-t";
|
||||
public const string TapeLong = "--tape";
|
||||
public const string TitleKeysLong = "--title-keys";
|
||||
public const string TrapDiscShort = "-t";
|
||||
public const string TrapDiscLong = "--trap-disc";
|
||||
public const string TrimLong = "--trim";
|
||||
public const string UseBufferedReadsLong = "--use-buffered-reads";
|
||||
public const string VerboseShort = "-v";
|
||||
public const string VerboseLong = "--verbose";
|
||||
public const string VerifyDiscShort = "-w";
|
||||
@@ -195,6 +206,7 @@ namespace MPF.Aaru
|
||||
public const string BlockSizeLong = "--block-size";
|
||||
public const string CountShort = "-c";
|
||||
public const string CountLong = "--count";
|
||||
public const string MaxBlocksLong = "--max-blocks";
|
||||
public const string MediaLastSequenceLong = "--media-lastsequence";
|
||||
public const string MediaSequenceLong = "--media-sequence";
|
||||
public const string SkipShort = "-k";
|
||||
@@ -219,6 +231,8 @@ namespace MPF.Aaru
|
||||
public const string FormatConvertLong = "--format";
|
||||
public const string FormatDumpShort = "-t";
|
||||
public const string FormatDumpLong = "--format";
|
||||
public const string GeometryShort = "-g";
|
||||
public const string GeometryLong = "--geometry";
|
||||
public const string ImgBurnLogShort = "-b";
|
||||
public const string ImgBurnLogLong = "--ibg-log";
|
||||
public const string MediaBarcodeLong = "--media-barcode";
|
||||
@@ -1,6 +1,6 @@
|
||||
using MPF.Data;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.Aaru
|
||||
namespace MPF.Modules.Aaru
|
||||
{
|
||||
public static class Converters
|
||||
{
|
||||
File diff suppressed because it is too large
Load Diff
4
MPF.Modules/AssemblyInfo.cs
Normal file
4
MPF.Modules/AssemblyInfo.cs
Normal file
@@ -0,0 +1,4 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// Anything marked as internal can be used by the test methods
|
||||
[assembly: InternalsVisibleTo("MPF.Test")]
|
||||
@@ -6,12 +6,12 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using BurnOutSharp.ProtectionType;
|
||||
using Compress.ThreadReaders;
|
||||
using MPF.Hashing;
|
||||
using MPF.Utilities;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.Hashing;
|
||||
using MPF.Core.Utilities;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.Data
|
||||
namespace MPF.Modules
|
||||
{
|
||||
public abstract class BaseParameters
|
||||
{
|
||||
@@ -103,7 +103,7 @@ namespace MPF.Data
|
||||
/// <summary>
|
||||
/// Currently represented system
|
||||
/// </summary>
|
||||
public KnownSystem? System { get; set; }
|
||||
public RedumpSystem? System { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Currently represented media type
|
||||
@@ -126,13 +126,13 @@ namespace MPF.Data
|
||||
/// <summary>
|
||||
/// Generate parameters based on a set of known inputs
|
||||
/// </summary>
|
||||
/// <param name="system">KnownSystem value to use</param>
|
||||
/// <param name="system">RedumpSystem value to use</param>
|
||||
/// <param name="type">MediaType value to use</param>
|
||||
/// <param name="driveLetter">Drive letter to use</param>
|
||||
/// <param name="filename">Filename to use</param>
|
||||
/// <param name="driveSpeed">Drive speed to use</param>
|
||||
/// <param name="options">Options object containing all settings that may be used for setting parameters</param>
|
||||
public BaseParameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
public BaseParameters(RedumpSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
{
|
||||
this.System = system;
|
||||
this.Type = type;
|
||||
@@ -308,12 +308,7 @@ namespace MPF.Data
|
||||
/// <param name="index">Current index</param>
|
||||
/// <returns>True if the next item exists, false otherwise</returns>
|
||||
protected static bool DoesExist(List<string> parameters, int index)
|
||||
{
|
||||
if (index >= parameters.Count)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
=> index < parameters.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Get the Base64 representation of a string
|
||||
@@ -355,14 +350,9 @@ namespace MPF.Data
|
||||
/// Returns whether a string is a valid drive letter
|
||||
/// </summary>
|
||||
/// <param name="parameter">String value to check</param>
|
||||
/// <returns>True if it's a valid drive letter, false otherwise</returns>
|
||||
/// <returns>True if it's a valid drive letter, false otherwise</W>
|
||||
protected static bool IsValidDriveLetter(string parameter)
|
||||
{
|
||||
if (!Regex.IsMatch(parameter, @"^[A-Z]:?\\?$"))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
=> Regex.IsMatch(parameter, @"^[A-Z]:?\\?$");
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether a string is a valid bool
|
||||
@@ -370,9 +360,7 @@ namespace MPF.Data
|
||||
/// <param name="parameter">String value to check</param>
|
||||
/// <returns>True if it's a valid bool, false otherwise</returns>
|
||||
protected static bool IsValidBool(string parameter)
|
||||
{
|
||||
return bool.TryParse(parameter, out bool _);
|
||||
}
|
||||
=> bool.TryParse(parameter, out bool _);
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether a string is a valid byte
|
||||
@@ -462,9 +450,7 @@ namespace MPF.Data
|
||||
/// <param name="i">Reference to the position in the parts</param>
|
||||
/// <returns>True if the parameter was processed successfully or skipped, false otherwise</returns>
|
||||
protected bool ProcessFlagParameter(List<string> parts, string flagString, ref int i)
|
||||
{
|
||||
return ProcessFlagParameter(parts, null, flagString, ref i);
|
||||
}
|
||||
=> ProcessFlagParameter(parts, null, flagString, ref i);
|
||||
|
||||
/// <summary>
|
||||
/// Process a flag parameter
|
||||
@@ -499,9 +485,7 @@ namespace MPF.Data
|
||||
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
|
||||
/// <returns>True if the parameter was processed successfully or skipped, false otherwise</returns>
|
||||
protected bool ProcessBooleanParameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
|
||||
{
|
||||
return ProcessBooleanParameter(parts, null, flagString, ref i, missingAllowed);
|
||||
}
|
||||
=> ProcessBooleanParameter(parts, null, flagString, ref i, missingAllowed);
|
||||
|
||||
/// <summary>
|
||||
/// Process a boolean parameter
|
||||
@@ -576,9 +560,7 @@ namespace MPF.Data
|
||||
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
|
||||
/// <returns>SByte value if success, SByte.MinValue if skipped, null on error/returns>
|
||||
protected sbyte? ProcessInt8Parameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
|
||||
{
|
||||
return ProcessInt8Parameter(parts, null, flagString, ref i, missingAllowed);
|
||||
}
|
||||
=> ProcessInt8Parameter(parts, null, flagString, ref i, missingAllowed);
|
||||
|
||||
/// <summary>
|
||||
/// Process an sbyte parameter
|
||||
@@ -655,9 +637,7 @@ namespace MPF.Data
|
||||
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
|
||||
/// <returns>Int16 value if success, Int16.MinValue if skipped, null on error/returns>
|
||||
protected short? ProcessInt16Parameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
|
||||
{
|
||||
return ProcessInt16Parameter(parts, null, flagString, ref i, missingAllowed);
|
||||
}
|
||||
=> ProcessInt16Parameter(parts, null, flagString, ref i, missingAllowed);
|
||||
|
||||
/// <summary>
|
||||
/// Process an Int16 parameter
|
||||
@@ -733,9 +713,7 @@ namespace MPF.Data
|
||||
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
|
||||
/// <returns>Int32 value if success, Int32.MinValue if skipped, null on error/returns>
|
||||
protected int? ProcessInt32Parameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
|
||||
{
|
||||
return ProcessInt32Parameter(parts, null, flagString, ref i, missingAllowed);
|
||||
}
|
||||
=> ProcessInt32Parameter(parts, null, flagString, ref i, missingAllowed);
|
||||
|
||||
/// <summary>
|
||||
/// Process an Int32 parameter
|
||||
@@ -811,9 +789,7 @@ namespace MPF.Data
|
||||
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
|
||||
/// <returns>Int64 value if success, Int64.MinValue if skipped, null on error/returns>
|
||||
protected long? ProcessInt64Parameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
|
||||
{
|
||||
return ProcessInt64Parameter(parts, null, flagString, ref i, missingAllowed);
|
||||
}
|
||||
=> ProcessInt64Parameter(parts, null, flagString, ref i, missingAllowed);
|
||||
|
||||
/// <summary>
|
||||
/// Process an Int64 parameter
|
||||
@@ -881,7 +857,7 @@ namespace MPF.Data
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process an Int64 parameter
|
||||
/// Process an string parameter
|
||||
/// </summary>
|
||||
/// <param name="parts">List of parts to be referenced</param>
|
||||
/// <param name="flagString">Flag string, if available</param>
|
||||
@@ -889,9 +865,7 @@ namespace MPF.Data
|
||||
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
|
||||
/// <returns>String value if possible, string.Empty on missing, null on error</returns>
|
||||
protected string ProcessStringParameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
|
||||
{
|
||||
return ProcessStringParameter(parts, null, flagString, ref i, missingAllowed);
|
||||
}
|
||||
=> ProcessStringParameter(parts, null, flagString, ref i, missingAllowed);
|
||||
|
||||
/// <summary>
|
||||
/// Process a string parameter
|
||||
@@ -1158,42 +1132,6 @@ namespace MPF.Data
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the existance of an anti-modchip string from a PlayStation disc, if possible
|
||||
/// </summary>
|
||||
/// <param name="driveLetter">Drive letter to use to check</param>
|
||||
/// <returns>Anti-modchip existance if possible, false on error</returns>
|
||||
protected static bool GetPlayStationAntiModchipDetected(char? driveLetter)
|
||||
{
|
||||
// If there's no drive letter, we can't do this part
|
||||
if (driveLetter == null)
|
||||
return false;
|
||||
|
||||
// If the folder no longer exists, we can't do this part
|
||||
string drivePath = driveLetter + ":\\";
|
||||
if (!Directory.Exists(drivePath))
|
||||
return false;
|
||||
|
||||
// Scan through each file to check for the anti-modchip strings
|
||||
var antiModchip = new PSXAntiModchip();
|
||||
foreach (string path in Directory.EnumerateFiles(drivePath, "*", SearchOption.AllDirectories))
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] fileContent = File.ReadAllBytes(path);
|
||||
string protection = antiModchip.CheckContents(path, fileContent, includePosition: false);
|
||||
if (!string.IsNullOrWhiteSpace(protection))
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// No-op, we don't care what the error was
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the EXE date from a PlayStation disc, if possible
|
||||
/// </summary>
|
||||
@@ -1202,7 +1140,7 @@ namespace MPF.Data
|
||||
/// <param name="region">Output region, if possible</param>
|
||||
/// <param name="date">Output EXE date in "yyyy-mm-dd" format if possible, null on error</param>
|
||||
/// <returns></returns>
|
||||
protected static bool GetPlayStationExecutableInfo(char? driveLetter, out string serial, out RedumpRegion? region, out string date)
|
||||
protected static bool GetPlayStationExecutableInfo(char? driveLetter, out string serial, out Region? region, out string date)
|
||||
{
|
||||
serial = null; region = null; date = null;
|
||||
|
||||
@@ -1238,11 +1176,18 @@ namespace MPF.Data
|
||||
if (!string.IsNullOrEmpty(bootValue))
|
||||
{
|
||||
var match = Regex.Match(bootValue, @"cdrom.?:\\?(.*)");
|
||||
if (match != null && match.Groups.Count > 1)
|
||||
if (match.Groups.Count > 1)
|
||||
{
|
||||
exeName = match.Groups[1].Value;
|
||||
exeName = exeName.Split(';')[0];
|
||||
serial = exeName.Replace('_', '-').Replace(".", string.Empty);
|
||||
// EXE name may have a trailing `;` after
|
||||
// EXE name should always be in all caps
|
||||
exeName = match.Groups[1].Value
|
||||
.Split(';')[0]
|
||||
.ToUpperInvariant();
|
||||
|
||||
// Serial is most of the EXE name normalized
|
||||
serial = exeName
|
||||
.Replace('_', '-')
|
||||
.Replace(".", string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1382,18 +1327,14 @@ namespace MPF.Data
|
||||
/// </summary>
|
||||
/// <param name="region">String representing the category</param>
|
||||
/// <returns>Category, if possible</returns>
|
||||
protected static RedumpDiscCategory? GetUMDCategory(string category)
|
||||
protected static DiscCategory? GetUMDCategory(string category)
|
||||
{
|
||||
switch (category)
|
||||
{
|
||||
case "GAME":
|
||||
return RedumpDiscCategory.Games;
|
||||
case "VIDEO":
|
||||
return RedumpDiscCategory.Video;
|
||||
case "AUDIO":
|
||||
return RedumpDiscCategory.Audio;
|
||||
default:
|
||||
return null;
|
||||
case "GAME": return DiscCategory.Games;
|
||||
case "VIDEO": return DiscCategory.Video;
|
||||
case "AUDIO": return DiscCategory.Audio;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1406,7 +1347,7 @@ namespace MPF.Data
|
||||
/// </summary>
|
||||
/// <param name="serial">PlayStation serial code</param>
|
||||
/// <returns>Region mapped from name, if possible</returns>
|
||||
protected static RedumpRegion? GetPlayStationRegion(string serial)
|
||||
protected static Region? GetPlayStationRegion(string serial)
|
||||
{
|
||||
// Standardized "S" serials
|
||||
if (serial.StartsWith("S"))
|
||||
@@ -1415,26 +1356,19 @@ namespace MPF.Data
|
||||
// char secondRegion = serial[3];
|
||||
switch (serial[2])
|
||||
{
|
||||
case 'A':
|
||||
return RedumpRegion.Asia;
|
||||
case 'C':
|
||||
return RedumpRegion.China;
|
||||
case 'E':
|
||||
return RedumpRegion.Europe;
|
||||
case 'J':
|
||||
return RedumpRegion.JapanKorea;
|
||||
case 'K':
|
||||
return RedumpRegion.Korea;
|
||||
case 'P':
|
||||
return RedumpRegion.Japan;
|
||||
case 'U':
|
||||
return RedumpRegion.USA;
|
||||
case 'A': return Region.Asia;
|
||||
case 'C': return Region.China;
|
||||
case 'E': return Region.Europe;
|
||||
case 'J': return Region.JapanKorea;
|
||||
case 'K': return Region.SouthKorea;
|
||||
case 'P': return Region.Japan;
|
||||
case 'U': return Region.UnitedStatesOfAmerica;
|
||||
}
|
||||
}
|
||||
|
||||
// Japan-only special serial
|
||||
else if (serial.StartsWith("PAPX"))
|
||||
return RedumpRegion.Japan;
|
||||
return Region.Japan;
|
||||
|
||||
// Region appears entirely random
|
||||
else if (serial.StartsWith("PABX"))
|
||||
@@ -1442,47 +1376,19 @@ namespace MPF.Data
|
||||
|
||||
// Japan-only special serial
|
||||
else if (serial.StartsWith("PCBX"))
|
||||
return RedumpRegion.Japan;
|
||||
return Region.Japan;
|
||||
|
||||
// Single disc known, Japan
|
||||
else if (serial.StartsWith("PDBX"))
|
||||
return RedumpRegion.Japan;
|
||||
return Region.Japan;
|
||||
|
||||
// Single disc known, Europe
|
||||
else if (serial.StartsWith("PEBX"))
|
||||
return RedumpRegion.Europe;
|
||||
return Region.Europe;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine the region based on the XGD serial character
|
||||
/// </summary>
|
||||
/// <param name="region">Character denoting the region</param>
|
||||
/// <returns>Region, if possible</returns>
|
||||
protected static RedumpRegion? GetXgdRegion(char region)
|
||||
{
|
||||
switch (region)
|
||||
{
|
||||
case 'W':
|
||||
return RedumpRegion.World;
|
||||
case 'A':
|
||||
return RedumpRegion.USA;
|
||||
case 'J':
|
||||
return RedumpRegion.JapanAsia;
|
||||
case 'E':
|
||||
return RedumpRegion.Europe;
|
||||
case 'K':
|
||||
return RedumpRegion.USAJapan;
|
||||
case 'L':
|
||||
return RedumpRegion.USAEurope;
|
||||
case 'H':
|
||||
return RedumpRegion.JapanEurope;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,10 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using MPF.Data;
|
||||
using MPF.Core.Data;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.CleanRip
|
||||
namespace MPF.Modules.CleanRip
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a generic set of CleanRip parameters
|
||||
@@ -22,7 +23,7 @@ namespace MPF.CleanRip
|
||||
public Parameters(string parameters) : base(parameters) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
public Parameters(RedumpSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
: base(system, type, driveLetter, filename, driveSpeed, options)
|
||||
{
|
||||
}
|
||||
@@ -49,7 +50,8 @@ namespace MPF.CleanRip
|
||||
break;
|
||||
|
||||
default:
|
||||
return (false, missingFiles);
|
||||
missingFiles.Add("Media and system combination not supported for CleanRip");
|
||||
break;
|
||||
}
|
||||
|
||||
return (!missingFiles.Any(), missingFiles);
|
||||
@@ -82,7 +84,7 @@ namespace MPF.CleanRip
|
||||
if (File.Exists(basePath + ".bca"))
|
||||
info.Extras.BCA = GetBCA(basePath + ".bca");
|
||||
|
||||
if (GetGameCubeWiiInformation(basePath + "-dumpinfo.txt", out RedumpRegion? gcRegion, out string gcVersion))
|
||||
if (GetGameCubeWiiInformation(basePath + "-dumpinfo.txt", out Region? gcRegion, out string gcVersion))
|
||||
{
|
||||
info.CommonDiscInfo.Region = gcRegion ?? info.CommonDiscInfo.Region;
|
||||
info.VersionAndEditions.Version = gcVersion ?? info.VersionAndEditions.Version;
|
||||
@@ -203,7 +205,7 @@ namespace MPF.CleanRip
|
||||
/// <param name="region">Output region, if possible</param>
|
||||
/// <param name="version">Output internal version of the game</param>
|
||||
/// <returns></returns>
|
||||
private static bool GetGameCubeWiiInformation(string dumpinfo, out RedumpRegion? region, out string version)
|
||||
private static bool GetGameCubeWiiInformation(string dumpinfo, out Region? region, out string version)
|
||||
{
|
||||
region = null; version = null;
|
||||
|
||||
@@ -238,49 +240,49 @@ namespace MPF.CleanRip
|
||||
switch (serial[3])
|
||||
{
|
||||
case 'A':
|
||||
region = RedumpRegion.World;
|
||||
region = Region.World;
|
||||
break;
|
||||
case 'D':
|
||||
region = RedumpRegion.Germany;
|
||||
region = Region.Germany;
|
||||
break;
|
||||
case 'E':
|
||||
region = RedumpRegion.USA;
|
||||
region = Region.UnitedStatesOfAmerica;
|
||||
break;
|
||||
case 'F':
|
||||
region = RedumpRegion.France;
|
||||
region = Region.France;
|
||||
break;
|
||||
case 'I':
|
||||
region = RedumpRegion.Italy;
|
||||
region = Region.Italy;
|
||||
break;
|
||||
case 'J':
|
||||
region = RedumpRegion.Japan;
|
||||
region = Region.Japan;
|
||||
break;
|
||||
case 'K':
|
||||
region = RedumpRegion.Korea;
|
||||
region = Region.SouthKorea;
|
||||
break;
|
||||
case 'L':
|
||||
region = RedumpRegion.Europe; // Japanese import to Europe
|
||||
region = Region.Europe; // Japanese import to Europe
|
||||
break;
|
||||
case 'M':
|
||||
region = RedumpRegion.Europe; // American import to Europe
|
||||
region = Region.Europe; // American import to Europe
|
||||
break;
|
||||
case 'N':
|
||||
region = RedumpRegion.USA; // Japanese import to USA
|
||||
region = Region.UnitedStatesOfAmerica; // Japanese import to USA
|
||||
break;
|
||||
case 'P':
|
||||
region = RedumpRegion.Europe;
|
||||
region = Region.Europe;
|
||||
break;
|
||||
case 'R':
|
||||
region = RedumpRegion.Russia;
|
||||
region = Region.RussianFederation;
|
||||
break;
|
||||
case 'S':
|
||||
region = RedumpRegion.Spain;
|
||||
region = Region.Spain;
|
||||
break;
|
||||
case 'Q':
|
||||
region = RedumpRegion.Korea; // Korea with Japanese language
|
||||
region = Region.SouthKorea; // Korea with Japanese language
|
||||
break;
|
||||
case 'T':
|
||||
region = RedumpRegion.Korea; // Korea with English language
|
||||
region = Region.SouthKorea; // Korea with English language
|
||||
break;
|
||||
case 'X':
|
||||
region = null; // Not a real region code
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace MPF.DD
|
||||
namespace MPF.Modules.DD
|
||||
{
|
||||
/// <summary>
|
||||
/// Top-level commands for DD
|
||||
@@ -1,6 +1,6 @@
|
||||
using MPF.Data;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.DD
|
||||
namespace MPF.Modules.DD
|
||||
{
|
||||
public static class Converters
|
||||
{
|
||||
@@ -2,9 +2,10 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using MPF.Data;
|
||||
using MPF.Core.Data;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.DD
|
||||
namespace MPF.Modules.DD
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a generic set of DD parameters
|
||||
@@ -59,7 +60,7 @@ namespace MPF.DD
|
||||
public Parameters(string parameters) : base(parameters) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
public Parameters(RedumpSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
: base(system, type, driveLetter, filename, driveSpeed, options)
|
||||
{
|
||||
}
|
||||
@@ -86,10 +87,11 @@ namespace MPF.DD
|
||||
|
||||
switch (this.System)
|
||||
{
|
||||
case KnownSystem.KonamiPython2:
|
||||
if (GetPlayStationExecutableInfo(drive?.Letter, out string pythonTwoSerial, out RedumpRegion? pythonTwoRegion, out string pythonTwoDate))
|
||||
case RedumpSystem.KonamiPython2:
|
||||
if (GetPlayStationExecutableInfo(drive?.Letter, out string pythonTwoSerial, out Region? pythonTwoRegion, out string pythonTwoDate))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"Internal Disc Serial: {pythonTwoSerial}\n";
|
||||
// Ensure internal serial is pulled from local data
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = pythonTwoSerial ?? string.Empty;
|
||||
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? pythonTwoRegion;
|
||||
info.CommonDiscInfo.EXEDateBuildDate = pythonTwoDate;
|
||||
}
|
||||
@@ -97,21 +99,22 @@ namespace MPF.DD
|
||||
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? "";
|
||||
break;
|
||||
|
||||
case KnownSystem.SonyPlayStation:
|
||||
if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationSerial, out RedumpRegion? playstationRegion, out string playstationDate))
|
||||
case RedumpSystem.SonyPlayStation:
|
||||
if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationSerial, out Region? playstationRegion, out string playstationDate))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"Internal Disc Serial: {playstationSerial}\n";
|
||||
// Ensure internal serial is pulled from local data
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = playstationSerial ?? string.Empty;
|
||||
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationRegion;
|
||||
info.CommonDiscInfo.EXEDateBuildDate = playstationDate;
|
||||
}
|
||||
|
||||
info.CopyProtection.AntiModchip = GetPlayStationAntiModchipDetected(drive?.Letter) ? YesNo.Yes : YesNo.No;
|
||||
break;
|
||||
|
||||
case KnownSystem.SonyPlayStation2:
|
||||
if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationTwoSerial, out RedumpRegion? playstationTwoRegion, out string playstationTwoDate))
|
||||
case RedumpSystem.SonyPlayStation2:
|
||||
if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationTwoSerial, out Region? playstationTwoRegion, out string playstationTwoDate))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"Internal Disc Serial: {playstationTwoSerial}\n";
|
||||
// Ensure internal serial is pulled from local data
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = playstationTwoSerial ?? string.Empty;
|
||||
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationTwoRegion;
|
||||
info.CommonDiscInfo.EXEDateBuildDate = playstationTwoDate;
|
||||
}
|
||||
@@ -119,11 +122,11 @@ namespace MPF.DD
|
||||
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? "";
|
||||
break;
|
||||
|
||||
case KnownSystem.SonyPlayStation4:
|
||||
case RedumpSystem.SonyPlayStation4:
|
||||
info.VersionAndEditions.Version = GetPlayStation4Version(drive?.Letter) ?? "";
|
||||
break;
|
||||
|
||||
case KnownSystem.SonyPlayStation5:
|
||||
case RedumpSystem.SonyPlayStation5:
|
||||
info.VersionAndEditions.Version = GetPlayStation5Version(drive?.Letter) ?? "";
|
||||
break;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace MPF.DiscImageCreator
|
||||
namespace MPF.Modules.DiscImageCreator
|
||||
{
|
||||
/// <summary>
|
||||
/// Top-level commands for DiscImageCreator
|
||||
@@ -1,6 +1,6 @@
|
||||
using MPF.Data;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.DiscImageCreator
|
||||
namespace MPF.Modules.DiscImageCreator
|
||||
{
|
||||
public static class Converters
|
||||
{
|
||||
@@ -10,33 +10,33 @@ namespace MPF.DiscImageCreator
|
||||
/// Get the most common known system for a given MediaType
|
||||
/// </summary>
|
||||
/// <param name="baseCommand">Command value to check</param>
|
||||
/// <returns>KnownSystem if possible, null on error</returns>
|
||||
public static KnownSystem? ToKnownSystem(string baseCommand)
|
||||
/// <returns>RedumpSystem if possible, null on error</returns>
|
||||
public static RedumpSystem? ToRedumpSystem(string baseCommand)
|
||||
{
|
||||
switch (baseCommand)
|
||||
{
|
||||
case CommandStrings.Audio:
|
||||
return KnownSystem.AudioCD;
|
||||
return RedumpSystem.AudioCD;
|
||||
case CommandStrings.CompactDisc:
|
||||
case CommandStrings.Data:
|
||||
case CommandStrings.DigitalVideoDisc:
|
||||
case CommandStrings.Disk:
|
||||
case CommandStrings.Floppy:
|
||||
case CommandStrings.Tape:
|
||||
return KnownSystem.IBMPCCompatible;
|
||||
return RedumpSystem.IBMPCcompatible;
|
||||
case CommandStrings.GDROM:
|
||||
case CommandStrings.Swap:
|
||||
return KnownSystem.SegaDreamcast;
|
||||
return RedumpSystem.SegaDreamcast;
|
||||
case CommandStrings.BluRay:
|
||||
return KnownSystem.SonyPlayStation3;
|
||||
return RedumpSystem.SonyPlayStation3;
|
||||
case CommandStrings.SACD:
|
||||
return KnownSystem.SuperAudioCD;
|
||||
return RedumpSystem.SuperAudioCD;
|
||||
case CommandStrings.XBOX:
|
||||
case CommandStrings.XBOXSwap:
|
||||
return KnownSystem.MicrosoftXBOX;
|
||||
return RedumpSystem.MicrosoftXbox;
|
||||
case CommandStrings.XGD2Swap:
|
||||
case CommandStrings.XGD3Swap:
|
||||
return KnownSystem.MicrosoftXBOX360;
|
||||
return RedumpSystem.MicrosoftXbox360;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -3,12 +3,12 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using BurnOutSharp.External.psxt001z;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.Utilities;
|
||||
using MPF.CueSheets;
|
||||
using MPF.Data;
|
||||
using MPF.Utilities;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.DiscImageCreator
|
||||
namespace MPF.Modules.DiscImageCreator
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a generic set of DiscImageCreator parameters
|
||||
@@ -159,7 +159,7 @@ namespace MPF.DiscImageCreator
|
||||
public Parameters(string parameters) : base(parameters) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
public Parameters(RedumpSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
: base(system, type, driveLetter, filename, driveSpeed, options)
|
||||
{
|
||||
}
|
||||
@@ -346,7 +346,8 @@ namespace MPF.DiscImageCreator
|
||||
break;
|
||||
|
||||
default:
|
||||
return (false, missingFiles);
|
||||
missingFiles.Add("Media and system combination not supported for DiscImageCreator");
|
||||
break;
|
||||
}
|
||||
|
||||
return (!missingFiles.Any(), missingFiles);
|
||||
@@ -384,11 +385,15 @@ namespace MPF.DiscImageCreator
|
||||
}
|
||||
|
||||
info.TracksAndWriteOffsets.Cuesheet = GetFullFile(basePath + ".cue") ?? "";
|
||||
var cueSheet = new CueSheet(basePath + ".cue"); // TODO: Do something with this
|
||||
//var cueSheet = new CueSheet(basePath + ".cue"); // TODO: Do something with this
|
||||
|
||||
string cdWriteOffset = GetWriteOffset(basePath + "_disc.txt") ?? "";
|
||||
info.CommonDiscInfo.RingWriteOffset = cdWriteOffset;
|
||||
info.TracksAndWriteOffsets.OtherWriteOffsets = cdWriteOffset;
|
||||
// Audio CDs "all have an offset of 0" and should not be included
|
||||
if (System != RedumpSystem.AudioCD)
|
||||
{
|
||||
string cdWriteOffset = GetWriteOffset(basePath + "_disc.txt") ?? "";
|
||||
info.CommonDiscInfo.RingWriteOffset = cdWriteOffset;
|
||||
info.TracksAndWriteOffsets.OtherWriteOffsets = cdWriteOffset;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -435,13 +440,13 @@ namespace MPF.DiscImageCreator
|
||||
break;
|
||||
}
|
||||
|
||||
// Extract info based specifically on KnownSystem
|
||||
// Extract info based specifically on RedumpSystem
|
||||
switch (this.System)
|
||||
{
|
||||
case KnownSystem.AppleMacintosh:
|
||||
case KnownSystem.EnhancedCD:
|
||||
case KnownSystem.IBMPCCompatible:
|
||||
case KnownSystem.RainbowDisc:
|
||||
case RedumpSystem.AppleMacintosh:
|
||||
case RedumpSystem.EnhancedCD:
|
||||
case RedumpSystem.IBMPCcompatible:
|
||||
case RedumpSystem.RainbowDisc:
|
||||
if (File.Exists(basePath + "_subIntention.txt"))
|
||||
{
|
||||
FileInfo fi = new FileInfo(basePath + "_subIntention.txt");
|
||||
@@ -451,15 +456,16 @@ namespace MPF.DiscImageCreator
|
||||
|
||||
break;
|
||||
|
||||
case KnownSystem.DVDAudio:
|
||||
case KnownSystem.DVDVideo:
|
||||
case RedumpSystem.DVDAudio:
|
||||
case RedumpSystem.DVDVideo:
|
||||
info.CopyProtection.Protection = GetDVDProtection(basePath + "_CSSKey.txt", basePath + "_disc.txt") ?? "";
|
||||
break;
|
||||
|
||||
case KnownSystem.KonamiPython2:
|
||||
if (GetPlayStationExecutableInfo(drive?.Letter, out string pythonTwoSerial, out RedumpRegion? pythonTwoRegion, out string pythonTwoDate))
|
||||
case RedumpSystem.KonamiPython2:
|
||||
if (GetPlayStationExecutableInfo(drive?.Letter, out string pythonTwoSerial, out Region? pythonTwoRegion, out string pythonTwoDate))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"Internal Disc Serial: {pythonTwoSerial}\n";
|
||||
// Ensure internal serial is pulled from local data
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = pythonTwoSerial ?? string.Empty;
|
||||
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? pythonTwoRegion;
|
||||
info.CommonDiscInfo.EXEDateBuildDate = pythonTwoDate;
|
||||
}
|
||||
@@ -467,44 +473,51 @@ namespace MPF.DiscImageCreator
|
||||
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? "";
|
||||
break;
|
||||
|
||||
case KnownSystem.MicrosoftXBOX:
|
||||
if (GetXgdAuxInfo(basePath + "_disc.txt", out string dmihash, out string pfihash, out string sshash, out string ss, out string ssver))
|
||||
case RedumpSystem.MicrosoftXbox:
|
||||
string xgd1XMID = GetXGD1XMID(Path.Combine(outputDirectory, "DMI.bin"));
|
||||
XgdInfo xgd1Info = new XgdInfo(xgd1XMID);
|
||||
if (xgd1Info?.Initialized == true)
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"{Template.XBOXDMIHash}: {dmihash ?? ""}\n" +
|
||||
$"{Template.XBOXPFIHash}: {pfihash ?? ""}\n" +
|
||||
$"{Template.XBOXSSHash}: {sshash ?? ""}\n" +
|
||||
$"{Template.XBOXSSVersion}: {ssver ?? ""}\n";
|
||||
info.Extras.SecuritySectorRanges = ss ?? "";
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.XMID] = xgd1Info.XMID;
|
||||
info.CommonDiscInfo.Serial = xgd1Info.GetSerial() ?? "";
|
||||
info.VersionAndEditions.Version = xgd1Info.GetVersion() ?? "";
|
||||
info.CommonDiscInfo.Region = xgd1Info.InternalRegion;
|
||||
}
|
||||
|
||||
if (GetXboxDMIInfo(Path.Combine(outputDirectory, "DMI.bin"), out string serial, out string version, out RedumpRegion? region))
|
||||
if (GetXGDAuxInfo(basePath + "_disc.txt", out string xgd1DMIHash, out string xgd1PFIHash, out string xgd1SSHash, out string xgd1SS, out string xgd1SSVer))
|
||||
{
|
||||
info.CommonDiscInfo.Serial = serial ?? "";
|
||||
info.VersionAndEditions.Version = version ?? "";
|
||||
info.CommonDiscInfo.Region = region;
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.DMIHash] = xgd1DMIHash;
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.PFIHash] = xgd1PFIHash;
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSHash] = xgd1SSHash;
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSVersion] = xgd1SSVer;
|
||||
info.Extras.SecuritySectorRanges = xgd1SS ?? "";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case KnownSystem.MicrosoftXBOX360:
|
||||
if (GetXgdAuxInfo(basePath + "_disc.txt", out string dmi360hash, out string pfi360hash, out string ss360hash, out string ss360, out string ssver360))
|
||||
case RedumpSystem.MicrosoftXbox360:
|
||||
string xgd23XeMID = GetXGD23XeMID(Path.Combine(outputDirectory, "DMI.bin"));
|
||||
XgdInfo xgd23Info = new XgdInfo(xgd23XeMID);
|
||||
if (xgd23Info?.Initialized == true)
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"{Template.XBOXDMIHash}: {dmi360hash ?? ""}\n" +
|
||||
$"{Template.XBOXPFIHash}: {pfi360hash ?? ""}\n" +
|
||||
$"{Template.XBOXSSHash}: {ss360hash ?? ""}\n" +
|
||||
$"{Template.XBOXSSVersion}: {ssver360 ?? ""}\n";
|
||||
info.Extras.SecuritySectorRanges = ss360 ?? "";
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.XeMID] = xgd23Info.XMID;
|
||||
info.CommonDiscInfo.Serial = xgd23Info.GetSerial() ?? "";
|
||||
info.VersionAndEditions.Version = xgd23Info.GetVersion() ?? "";
|
||||
info.CommonDiscInfo.Region = xgd23Info.InternalRegion;
|
||||
}
|
||||
|
||||
if (GetXbox360DMIInfo(Path.Combine(outputDirectory, "DMI.bin"), out string serial360, out string version360, out RedumpRegion? region360))
|
||||
if (GetXGDAuxInfo(basePath + "_disc.txt", out string xgd23DMIHash, out string xgd23PFIHash, out string xgd23SSHash, out string xgd23SS, out string xgd23SSVer))
|
||||
{
|
||||
info.CommonDiscInfo.Serial = serial360 ?? "";
|
||||
info.VersionAndEditions.Version = version360 ?? "";
|
||||
info.CommonDiscInfo.Region = region360;
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.DMIHash] = xgd23DMIHash;
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.PFIHash] = xgd23PFIHash;
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSHash] = xgd23SSHash;
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSVersion] = xgd23SSVer;
|
||||
info.Extras.SecuritySectorRanges = xgd23SS ?? "";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case KnownSystem.NamcoSegaNintendoTriforce:
|
||||
case RedumpSystem.NamcoSegaNintendoTriforce:
|
||||
if (this.Type == MediaType.CDROM)
|
||||
{
|
||||
info.Extras.Header = GetSegaHeader(basePath + "_mainInfo.txt") ?? "";
|
||||
@@ -515,7 +528,8 @@ namespace MPF.DiscImageCreator
|
||||
|
||||
if (GetGDROMBuildInfo(info.Extras.Header, out string gdSerial, out string gdVersion, out string gdDate))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"Internal Serial: {gdSerial ?? ""}";
|
||||
// Ensure internal serial is pulled from local data
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = gdSerial ?? string.Empty;
|
||||
info.VersionAndEditions.Version = gdVersion ?? "";
|
||||
info.CommonDiscInfo.EXEDateBuildDate = gdDate ?? "";
|
||||
}
|
||||
@@ -523,7 +537,7 @@ namespace MPF.DiscImageCreator
|
||||
|
||||
break;
|
||||
|
||||
case KnownSystem.SegaCDMegaCD:
|
||||
case RedumpSystem.SegaMegaCDSegaCD:
|
||||
info.Extras.Header = GetSegaHeader(basePath + "_mainInfo.txt") ?? "";
|
||||
|
||||
// Take only the last 16 lines for Sega CD
|
||||
@@ -532,13 +546,14 @@ namespace MPF.DiscImageCreator
|
||||
|
||||
if (GetSegaCDBuildInfo(info.Extras.Header, out string scdSerial, out string fixedDate))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"Internal Serial: {scdSerial ?? ""}";
|
||||
// Ensure internal serial is pulled from local data
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = scdSerial ?? string.Empty;
|
||||
info.CommonDiscInfo.EXEDateBuildDate = fixedDate ?? "";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case KnownSystem.SegaChihiro:
|
||||
case RedumpSystem.SegaChihiro:
|
||||
if (this.Type == MediaType.CDROM)
|
||||
{
|
||||
info.Extras.Header = GetSegaHeader(basePath + "_mainInfo.txt") ?? "";
|
||||
@@ -549,7 +564,8 @@ namespace MPF.DiscImageCreator
|
||||
|
||||
if (GetGDROMBuildInfo(info.Extras.Header, out string gdSerial, out string gdVersion, out string gdDate))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"Internal Serial: {gdSerial ?? ""}";
|
||||
// Ensure internal serial is pulled from local data
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = gdSerial ?? string.Empty;
|
||||
info.VersionAndEditions.Version = gdVersion ?? "";
|
||||
info.CommonDiscInfo.EXEDateBuildDate = gdDate ?? "";
|
||||
}
|
||||
@@ -557,7 +573,7 @@ namespace MPF.DiscImageCreator
|
||||
|
||||
break;
|
||||
|
||||
case KnownSystem.SegaDreamcast:
|
||||
case RedumpSystem.SegaDreamcast:
|
||||
if (this.Type == MediaType.CDROM)
|
||||
{
|
||||
info.Extras.Header = GetSegaHeader(basePath + "_mainInfo.txt") ?? "";
|
||||
@@ -568,7 +584,8 @@ namespace MPF.DiscImageCreator
|
||||
|
||||
if (GetGDROMBuildInfo(info.Extras.Header, out string gdSerial, out string gdVersion, out string gdDate))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"Internal Serial: {gdSerial ?? ""}";
|
||||
// Ensure internal serial is pulled from local data
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = gdSerial ?? string.Empty;
|
||||
info.VersionAndEditions.Version = gdVersion ?? "";
|
||||
info.CommonDiscInfo.EXEDateBuildDate = gdDate ?? "";
|
||||
}
|
||||
@@ -576,7 +593,7 @@ namespace MPF.DiscImageCreator
|
||||
|
||||
break;
|
||||
|
||||
case KnownSystem.SegaNaomi:
|
||||
case RedumpSystem.SegaNaomi:
|
||||
if (this.Type == MediaType.CDROM)
|
||||
{
|
||||
info.Extras.Header = GetSegaHeader(basePath + "_mainInfo.txt") ?? "";
|
||||
@@ -587,7 +604,8 @@ namespace MPF.DiscImageCreator
|
||||
|
||||
if (GetGDROMBuildInfo(info.Extras.Header, out string gdSerial, out string gdVersion, out string gdDate))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"Internal Serial: {gdSerial ?? ""}";
|
||||
// Ensure internal serial is pulled from local data
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = gdSerial ?? string.Empty;
|
||||
info.VersionAndEditions.Version = gdVersion ?? "";
|
||||
info.CommonDiscInfo.EXEDateBuildDate = gdDate ?? "";
|
||||
}
|
||||
@@ -595,7 +613,7 @@ namespace MPF.DiscImageCreator
|
||||
|
||||
break;
|
||||
|
||||
case KnownSystem.SegaNaomi2:
|
||||
case RedumpSystem.SegaNaomi2:
|
||||
if (this.Type == MediaType.CDROM)
|
||||
{
|
||||
info.Extras.Header = GetSegaHeader(basePath + "_mainInfo.txt") ?? "";
|
||||
@@ -606,7 +624,8 @@ namespace MPF.DiscImageCreator
|
||||
|
||||
if (GetGDROMBuildInfo(info.Extras.Header, out string gdSerial, out string gdVersion, out string gdDate))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"Internal Serial: {gdSerial ?? ""}";
|
||||
// Ensure internal serial is pulled from local data
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = gdSerial ?? string.Empty;
|
||||
info.VersionAndEditions.Version = gdVersion ?? "";
|
||||
info.CommonDiscInfo.EXEDateBuildDate = gdDate ?? "";
|
||||
}
|
||||
@@ -614,7 +633,7 @@ namespace MPF.DiscImageCreator
|
||||
|
||||
break;
|
||||
|
||||
case KnownSystem.SegaSaturn:
|
||||
case RedumpSystem.SegaSaturn:
|
||||
info.Extras.Header = GetSegaHeader(basePath + "_mainInfo.txt") ?? "";
|
||||
|
||||
// Take only the first 16 lines for Saturn
|
||||
@@ -623,17 +642,19 @@ namespace MPF.DiscImageCreator
|
||||
|
||||
if (GetSaturnBuildInfo(info.Extras.Header, out string saturnSerial, out string saturnVersion, out string buildDate))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"Internal Serial: {saturnSerial ?? ""}";
|
||||
// Ensure internal serial is pulled from local data
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = saturnSerial ?? string.Empty;
|
||||
info.VersionAndEditions.Version = saturnVersion ?? "";
|
||||
info.CommonDiscInfo.EXEDateBuildDate = buildDate ?? "";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case KnownSystem.SonyPlayStation:
|
||||
if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationSerial, out RedumpRegion? playstationRegion, out string playstationDate))
|
||||
case RedumpSystem.SonyPlayStation:
|
||||
if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationSerial, out Region? playstationRegion, out string playstationDate))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"Internal Serial: {playstationSerial ?? ""}\n";
|
||||
// Ensure internal serial is pulled from local data
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = playstationSerial ?? string.Empty;
|
||||
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationRegion;
|
||||
info.CommonDiscInfo.EXEDateBuildDate = playstationDate;
|
||||
}
|
||||
@@ -652,45 +673,13 @@ namespace MPF.DiscImageCreator
|
||||
info.EDC.EDC = YesNo.NULL;
|
||||
|
||||
info.CopyProtection.AntiModchip = GetPlayStationAntiModchipDetected(basePath + "_disc.txt") ? YesNo.Yes : YesNo.No;
|
||||
|
||||
bool? psLibCryptStatus = GetLibCryptDetected(basePath + ".sub");
|
||||
if (psLibCryptStatus == true)
|
||||
{
|
||||
// Guard against false positives
|
||||
if (File.Exists(basePath + "_subIntention.txt"))
|
||||
{
|
||||
string libCryptData = GetFullFile(basePath + "_subIntention.txt") ?? "";
|
||||
if (string.IsNullOrEmpty(libCryptData))
|
||||
{
|
||||
info.CopyProtection.LibCrypt = YesNo.No;
|
||||
}
|
||||
else
|
||||
{
|
||||
info.CopyProtection.LibCrypt = YesNo.Yes;
|
||||
info.CopyProtection.LibCryptData = libCryptData;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
info.CopyProtection.LibCrypt = YesNo.No;
|
||||
}
|
||||
}
|
||||
else if (psLibCryptStatus == false)
|
||||
{
|
||||
info.CopyProtection.LibCrypt = YesNo.No;
|
||||
}
|
||||
else
|
||||
{
|
||||
info.CopyProtection.LibCrypt = YesNo.NULL;
|
||||
info.CopyProtection.LibCryptData = "LibCrypt could not be detected because subchannel file is missing";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case KnownSystem.SonyPlayStation2:
|
||||
if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationTwoSerial, out RedumpRegion? playstationTwoRegion, out string playstationTwoDate))
|
||||
case RedumpSystem.SonyPlayStation2:
|
||||
if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationTwoSerial, out Region? playstationTwoRegion, out string playstationTwoDate))
|
||||
{
|
||||
info.CommonDiscInfo.Comments += $"Internal Disc Serial: {playstationTwoSerial}\n";
|
||||
// Ensure internal serial is pulled from local data
|
||||
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = playstationTwoSerial ?? string.Empty;
|
||||
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationTwoRegion;
|
||||
info.CommonDiscInfo.EXEDateBuildDate = playstationTwoDate;
|
||||
}
|
||||
@@ -698,11 +687,11 @@ namespace MPF.DiscImageCreator
|
||||
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? "";
|
||||
break;
|
||||
|
||||
case KnownSystem.SonyPlayStation4:
|
||||
case RedumpSystem.SonyPlayStation4:
|
||||
info.VersionAndEditions.Version = GetPlayStation4Version(drive?.Letter) ?? "";
|
||||
break;
|
||||
|
||||
case KnownSystem.SonyPlayStation5:
|
||||
case RedumpSystem.SonyPlayStation5:
|
||||
info.VersionAndEditions.Version = GetPlayStation5Version(drive?.Letter) ?? "";
|
||||
break;
|
||||
}
|
||||
@@ -718,6 +707,8 @@ namespace MPF.DiscImageCreator
|
||||
info.Artifacts["ccd"] = GetBase64(GetFullFile(basePath + ".ccd"));
|
||||
if (File.Exists(basePath + "_cmd.txt")) // TODO: Figure out how to read in the timestamp-named file
|
||||
info.Artifacts["cmd"] = GetBase64(GetFullFile(basePath + "_cmd.txt"));
|
||||
if (File.Exists(basePath + "_CSSKey.txt"))
|
||||
info.Artifacts["csskey"] = GetBase64(GetFullFile(basePath + "_CSSKey.txt"));
|
||||
if (File.Exists(basePath + ".cue"))
|
||||
info.Artifacts["cue"] = GetBase64(GetFullFile(basePath + ".cue"));
|
||||
if (File.Exists(basePath + ".dat"))
|
||||
@@ -859,8 +850,7 @@ namespace MPF.DiscImageCreator
|
||||
if (BaseCommand == CommandStrings.Audio
|
||||
|| BaseCommand == CommandStrings.Data)
|
||||
{
|
||||
if (StartLBAValue != null && StartLBAValue > 0
|
||||
&& EndLBAValue != null && EndLBAValue > 0)
|
||||
if (StartLBAValue != null && EndLBAValue != null)
|
||||
{
|
||||
parameters.Add(StartLBAValue.ToString());
|
||||
parameters.Add(EndLBAValue.ToString());
|
||||
@@ -1311,6 +1301,7 @@ namespace MPF.DiscImageCreator
|
||||
FlagStrings.DisableBeep,
|
||||
FlagStrings.Fix,
|
||||
FlagStrings.ForceUnitAccess,
|
||||
FlagStrings.NoSkipSS,
|
||||
FlagStrings.PadSector,
|
||||
FlagStrings.Raw,
|
||||
FlagStrings.Resume,
|
||||
@@ -1462,8 +1453,6 @@ namespace MPF.DiscImageCreator
|
||||
logFiles.Add(cmdPath);
|
||||
if (File.Exists($"{basePath}_cmd.txt"))
|
||||
logFiles.Add($"{basePath}_cmd.txt");
|
||||
if (File.Exists($"{basePath}_CSSKey.txt"))
|
||||
logFiles.Add($"{basePath}_CSSKey.txt");
|
||||
if (File.Exists($"{basePath}.dat"))
|
||||
logFiles.Add($"{basePath}.dat");
|
||||
if (File.Exists($"{basePath}.sub"))
|
||||
@@ -1508,6 +1497,8 @@ namespace MPF.DiscImageCreator
|
||||
logFiles.Add(cmdPath);
|
||||
if (File.Exists($"{basePath}_cmd.txt"))
|
||||
logFiles.Add($"{basePath}_cmd.txt");
|
||||
if (File.Exists($"{basePath}_CSSKey.txt"))
|
||||
logFiles.Add($"{basePath}_CSSKey.txt");
|
||||
if (File.Exists($"{basePath}.dat"))
|
||||
logFiles.Add($"{basePath}.dat");
|
||||
if (File.Exists($"{basePath}_disc.txt"))
|
||||
@@ -1614,7 +1605,7 @@ namespace MPF.DiscImageCreator
|
||||
Filename = filename;
|
||||
|
||||
// First check to see if the combination of system and MediaType is valid
|
||||
var validTypes = Validators.GetValidMediaTypes(this.System);
|
||||
var validTypes = this.System.MediaTypes();
|
||||
if (!validTypes.Contains(this.Type))
|
||||
return;
|
||||
|
||||
@@ -1644,8 +1635,8 @@ namespace MPF.DiscImageCreator
|
||||
|
||||
switch (this.System)
|
||||
{
|
||||
case KnownSystem.AppleMacintosh:
|
||||
case KnownSystem.IBMPCCompatible:
|
||||
case RedumpSystem.AppleMacintosh:
|
||||
case RedumpSystem.IBMPCcompatible:
|
||||
this[FlagStrings.NoFixSubQSecuROM] = true;
|
||||
this[FlagStrings.ScanFileProtect] = true;
|
||||
this[FlagStrings.ScanSectorProtect] = options.DICParanoidMode;
|
||||
@@ -1654,17 +1645,17 @@ namespace MPF.DiscImageCreator
|
||||
SubchannelReadLevelValue = 2;
|
||||
|
||||
break;
|
||||
case KnownSystem.AtariJaguarCD:
|
||||
case RedumpSystem.AtariJaguarCDInteractiveMultimediaSystem:
|
||||
this[FlagStrings.AtariJaguar] = true;
|
||||
break;
|
||||
case KnownSystem.HasbroVideoNow:
|
||||
case KnownSystem.HasbroVideoNowColor:
|
||||
case KnownSystem.HasbroVideoNowJr:
|
||||
case KnownSystem.HasbroVideoNowXP:
|
||||
case RedumpSystem.HasbroVideoNow:
|
||||
case RedumpSystem.HasbroVideoNowColor:
|
||||
case RedumpSystem.HasbroVideoNowJr:
|
||||
case RedumpSystem.HasbroVideoNowXP:
|
||||
this[FlagStrings.AddOffset] = true;
|
||||
this.AddOffsetValue = 0; // Value needed for first run and placeholder after
|
||||
break;
|
||||
case KnownSystem.SonyPlayStation:
|
||||
case RedumpSystem.SonyPlayStation:
|
||||
this[FlagStrings.ScanAntiMod] = true;
|
||||
this[FlagStrings.NoFixSubQLibCrypt] = true;
|
||||
break;
|
||||
@@ -1742,12 +1733,12 @@ namespace MPF.DiscImageCreator
|
||||
else
|
||||
DriveSpeed = Int32.Parse(parts[3]);
|
||||
|
||||
if (!IsValidInt32(parts[4], lowerBound: 0))
|
||||
if (!IsValidInt32(parts[4]))
|
||||
return false;
|
||||
else
|
||||
StartLBAValue = Int32.Parse(parts[4]);
|
||||
|
||||
if (!IsValidInt32(parts[5], lowerBound: 0))
|
||||
if (!IsValidInt32(parts[5]))
|
||||
return false;
|
||||
else
|
||||
EndLBAValue = Int32.Parse(parts[5]);
|
||||
@@ -1829,12 +1820,12 @@ namespace MPF.DiscImageCreator
|
||||
else
|
||||
DriveSpeed = Int32.Parse(parts[3]);
|
||||
|
||||
if (!IsValidInt32(parts[4], lowerBound: 0))
|
||||
if (!IsValidInt32(parts[4]))
|
||||
return false;
|
||||
else
|
||||
StartLBAValue = Int32.Parse(parts[4]);
|
||||
|
||||
if (!IsValidInt32(parts[5], lowerBound: 0))
|
||||
if (!IsValidInt32(parts[5]))
|
||||
return false;
|
||||
else
|
||||
EndLBAValue = Int32.Parse(parts[5]);
|
||||
@@ -2120,7 +2111,7 @@ namespace MPF.DiscImageCreator
|
||||
return false;
|
||||
}
|
||||
|
||||
// Loop through all auxilary flags, if necessary
|
||||
// Loop through all auxiliary flags, if necessary
|
||||
if (index > 0)
|
||||
{
|
||||
for (int i = index; i < parts.Count; i++)
|
||||
@@ -2331,12 +2322,12 @@ namespace MPF.DiscImageCreator
|
||||
/// <summary>
|
||||
/// Set the DIC command to be used for a given system and media type
|
||||
/// </summary>
|
||||
/// <param name="system">KnownSystem value to check</param>
|
||||
/// <param name="system">RedumpSystem value to check</param>
|
||||
/// <param name="type">MediaType value to check</param>
|
||||
private void SetBaseCommand(KnownSystem? system, MediaType? type)
|
||||
private void SetBaseCommand(RedumpSystem? system, MediaType? type)
|
||||
{
|
||||
// If we have an invalid combination, we should BaseCommand = null
|
||||
if (!Validators.GetValidMediaTypes(system).Contains(type))
|
||||
if (!system.MediaTypes().Contains(type))
|
||||
{
|
||||
BaseCommand = null;
|
||||
return;
|
||||
@@ -2345,14 +2336,14 @@ namespace MPF.DiscImageCreator
|
||||
switch (type)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
if (system == KnownSystem.SuperAudioCD)
|
||||
if (system == RedumpSystem.SuperAudioCD)
|
||||
BaseCommand = CommandStrings.SACD;
|
||||
else
|
||||
BaseCommand = CommandStrings.CompactDisc;
|
||||
return;
|
||||
case MediaType.DVD:
|
||||
if (system == KnownSystem.MicrosoftXBOX
|
||||
|| system == KnownSystem.MicrosoftXBOX360)
|
||||
if (system == RedumpSystem.MicrosoftXbox
|
||||
|| system == RedumpSystem.MicrosoftXbox360)
|
||||
{
|
||||
BaseCommand = CommandStrings.XBOX;
|
||||
return;
|
||||
@@ -2502,12 +2493,20 @@ namespace MPF.DiscImageCreator
|
||||
if (line.Contains("No TitleKey"))
|
||||
{
|
||||
var match = Regex.Match(line, @"^LBA:\s*[0-9]+, Filename: (.*?), No TitleKey$");
|
||||
vobKeys += $"{match.Groups[1].Value} Title Key: No TitleKey\n";
|
||||
string matchedFilename = match.Groups[1].Value;
|
||||
if (matchedFilename.EndsWith(";1"))
|
||||
matchedFilename = matchedFilename.Substring(0, matchedFilename.Length - 2);
|
||||
|
||||
vobKeys += $"{matchedFilename} Title Key: No Title Key\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
var match = Regex.Match(line, @"^LBA:\s*[0-9]+, Filename: (.*?), EncryptedTitleKey: .*?, DecryptedTitleKey: (.*?)$");
|
||||
vobKeys += $"{match.Groups[1].Value} Title Key: {match.Groups[2].Value}\n";
|
||||
string matchedFilename = match.Groups[1].Value;
|
||||
if (matchedFilename.EndsWith(";1"))
|
||||
matchedFilename = matchedFilename.Substring(0, matchedFilename.Length - 2);
|
||||
|
||||
vobKeys += $"{matchedFilename} Title Key: {match.Groups[2].Value}\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2736,20 +2735,6 @@ namespace MPF.DiscImageCreator
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get if LibCrypt data is detected in the subchannel file, if possible
|
||||
/// </summary>
|
||||
/// <param name="sub">.sub file location</param>
|
||||
/// <returns>Status of the LibCrypt data, if possible</returns>
|
||||
private static bool? GetLibCryptDetected(string sub)
|
||||
{
|
||||
// If the file doesn't exist, we can't get info from it
|
||||
if (!File.Exists(sub))
|
||||
return null;
|
||||
|
||||
return LibCrypt.CheckSubfile(sub);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the hex contents of the PIC file
|
||||
/// </summary>
|
||||
@@ -2943,9 +2928,10 @@ namespace MPF.DiscImageCreator
|
||||
string[] header = segaHeader.Split('\n');
|
||||
string serialVersionLine = header[2].Substring(58);
|
||||
string dateLine = header[3].Substring(58);
|
||||
serial = serialVersionLine.Substring(0, 8);
|
||||
serial = serialVersionLine.Substring(0, 10).Trim();
|
||||
version = serialVersionLine.Substring(10, 6).TrimStart('V', 'v');
|
||||
date = dateLine.Substring(0, 8);
|
||||
date = $"{date[0]}{date[1]}{date[2]}{date[3]}-{date[4]}{date[5]}-{date[6]}{date[7]}";
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
@@ -2975,7 +2961,7 @@ namespace MPF.DiscImageCreator
|
||||
string[] header = segaHeader.Split('\n');
|
||||
string serialVersionLine = header[8].Substring(58);
|
||||
string dateLine = header[1].Substring(58);
|
||||
serial = serialVersionLine.Substring(3, 7);
|
||||
serial = serialVersionLine.Substring(3, 8).TrimEnd('-', ' ');
|
||||
date = dateLine.Substring(8).Trim();
|
||||
|
||||
// Properly format the date string, if possible
|
||||
@@ -3056,10 +3042,12 @@ namespace MPF.DiscImageCreator
|
||||
{
|
||||
// If we're in a new mainInfo, the location of the header changed
|
||||
string line = sr.ReadLine();
|
||||
if (line.StartsWith("========== OpCode") || line.StartsWith("========== TOC (Binary)"))
|
||||
if (line.StartsWith("========== OpCode")
|
||||
|| line.StartsWith("========== TOC (Binary)")
|
||||
|| line.StartsWith("========== FULL TOC (Binary)"))
|
||||
{
|
||||
// Seek to unscrambled data
|
||||
while (!(line = sr.ReadLine()).StartsWith("========== Check Volume Descriptor ==========")) ;
|
||||
while (!(line = sr.ReadLine()).Contains("Check MCN and/or ISRC")) ;
|
||||
|
||||
// Read the next line so the search goes properly
|
||||
line = sr.ReadLine();
|
||||
@@ -3127,8 +3115,13 @@ namespace MPF.DiscImageCreator
|
||||
/// Get the XGD auxiliary info from the outputted files, if possible
|
||||
/// </summary>
|
||||
/// <param name="disc">_disc.txt file location</param>
|
||||
/// <param name="dmihash">Extracted DMI.bin CRC32 hash (upper-cased)</param>
|
||||
/// <param name="pfihash">Extracted PFI.bin CRC32 hash (upper-cased)</param>
|
||||
/// <param name="sshash">Extracted SS.bin CRC32 hash (upper-cased)</param>
|
||||
/// <param name="ss">Extracted security sector data</param>
|
||||
/// <param name="ssver">Extracted security sector version</param>
|
||||
/// <returns>True on successful extraction of info, false otherwise</returns>
|
||||
private static bool GetXgdAuxInfo(string disc, out string dmihash, out string pfihash, out string sshash, out string ss, out string ssver)
|
||||
private static bool GetXGDAuxInfo(string disc, out string dmihash, out string pfihash, out string sshash, out string ss, out string ssver)
|
||||
{
|
||||
dmihash = null; pfihash = null; sshash = null; ss = null; ssver = null;
|
||||
|
||||
@@ -3179,12 +3172,15 @@ namespace MPF.DiscImageCreator
|
||||
// Special File Hashes
|
||||
else if (line.StartsWith("<rom"))
|
||||
{
|
||||
if (line.Contains("SS.bin"))
|
||||
sshash = line;
|
||||
else if (line.Contains("PFI.bin"))
|
||||
pfihash = line;
|
||||
else if (line.Contains("DMI.bin"))
|
||||
dmihash = line;
|
||||
if (GetISOHashValues(line, out long _, out string crc32, out string _, out string _))
|
||||
{
|
||||
if (line.Contains("SS.bin"))
|
||||
sshash = crc32.ToUpperInvariant();
|
||||
else if (line.Contains("PFI.bin"))
|
||||
pfihash = crc32.ToUpperInvariant();
|
||||
else if (line.Contains("DMI.bin"))
|
||||
dmihash = crc32.ToUpperInvariant();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3199,65 +3195,49 @@ namespace MPF.DiscImageCreator
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the Xbox serial info from the DMI.bin file, if possible
|
||||
/// Get the XGD1 Master ID (XMID) information
|
||||
/// </summary>
|
||||
/// <param name="dmi">DMI.bin file location</param>
|
||||
/// <returns>True on successful extraction of info, false otherwise</returns>
|
||||
private static bool GetXboxDMIInfo(string dmi, out string serial, out string version, out RedumpRegion? region)
|
||||
/// <returns>String representation of the XGD1 DMI information, empty string on error</returns>
|
||||
private static string GetXGD1XMID(string dmi)
|
||||
{
|
||||
serial = null; version = null; region = RedumpRegion.World;
|
||||
|
||||
if (!File.Exists(dmi))
|
||||
return false;
|
||||
return string.Empty;
|
||||
|
||||
using (BinaryReader br = new BinaryReader(File.OpenRead(dmi)))
|
||||
{
|
||||
try
|
||||
{
|
||||
br.BaseStream.Seek(8, SeekOrigin.Begin);
|
||||
char[] str = br.ReadChars(8);
|
||||
|
||||
serial = $"{str[0]}{str[1]}-{str[2]}{str[3]}{str[4]}";
|
||||
version = $"1.{str[5]}{str[6]}";
|
||||
region = GetXgdRegion(str[7]);
|
||||
return true;
|
||||
return new string(br.ReadChars(8));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the Xbox 360 serial info from the DMI.bin file, if possible
|
||||
/// Get the XGD2/3 Master ID (XeMID) information
|
||||
/// </summary>
|
||||
/// <param name="dmi">DMI.bin file location</param>
|
||||
/// <returns>True on successful extraction of info, false otherwise</returns>
|
||||
private static bool GetXbox360DMIInfo(string dmi, out string serial, out string version, out RedumpRegion? region)
|
||||
/// <returns>String representation of the XGD2/3 DMI information, empty string on error</returns>
|
||||
private static string GetXGD23XeMID(string dmi)
|
||||
{
|
||||
serial = null; version = null; region = RedumpRegion.World;
|
||||
|
||||
if (!File.Exists(dmi))
|
||||
return false;
|
||||
return string.Empty;
|
||||
|
||||
using (BinaryReader br = new BinaryReader(File.OpenRead(dmi)))
|
||||
{
|
||||
try
|
||||
{
|
||||
br.BaseStream.Seek(64, SeekOrigin.Begin);
|
||||
char[] str = br.ReadChars(14);
|
||||
|
||||
serial = $"{str[0]}{str[1]}-{str[2]}{str[3]}{str[4]}{str[5]}";
|
||||
version = $"1.{str[6]}{str[7]}";
|
||||
region = GetXgdRegion(str[8]);
|
||||
// str[9], str[10], str[11] - unknown purpose
|
||||
// str[12], str[13] - disc <12> of <13>
|
||||
return true;
|
||||
return new string(br.ReadChars(14));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
46
MPF.Modules/MPF.Modules.csproj
Normal file
46
MPF.Modules/MPF.Modules.csproj
Normal file
@@ -0,0 +1,46 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net48;netcoreapp3.1;net5.0</TargetFrameworks>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
|
||||
<Copyright>Copyright (c)2019-2021</Copyright>
|
||||
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
|
||||
<Version>2.3</Version>
|
||||
<AssemblyVersion>$(Version)</AssemblyVersion>
|
||||
<FileVersion>$(Version)</FileVersion>
|
||||
<IncludeSource>true</IncludeSource>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<NrtRevisionFormat>$(Version)-{chash:8}</NrtRevisionFormat>
|
||||
<NrtResolveSimpleAttributes>true</NrtResolveSimpleAttributes>
|
||||
<NrtShowRevision>false</NrtShowRevision>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)'=='net48'">
|
||||
<DefineConstants>NET_FRAMEWORK</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MPF.Core\MPF.Core.csproj" />
|
||||
<ProjectReference Include="..\MPF.CueSheets\MPF.CueSheets.csproj" />
|
||||
<ProjectReference Include="..\RedumpLib\RedumpLib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)'=='net48'">
|
||||
<ProjectReference Include="..\CICMMetadata\CICMMetadataEditor\CICMMetadataEditor\CICMMetadataEditor.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Memory" Version="4.5.4" />
|
||||
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
</Project>
|
||||
@@ -2,9 +2,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using MPF.Data;
|
||||
using MPF.Core.Data;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.UmdImageCreator
|
||||
namespace MPF.Modules.UmdImageCreator
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a generic set of UmdImageCreator parameters
|
||||
@@ -22,7 +23,7 @@ namespace MPF.UmdImageCreator
|
||||
public Parameters(string parameters) : base(parameters) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
public Parameters(RedumpSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options)
|
||||
: base(system, type, driveLetter, filename, driveSpeed, options)
|
||||
{
|
||||
}
|
||||
@@ -51,7 +52,8 @@ namespace MPF.UmdImageCreator
|
||||
break;
|
||||
|
||||
default:
|
||||
return (false, missingFiles);
|
||||
missingFiles.Add("Media and system combination not supported for UmdImageCreator");
|
||||
break;
|
||||
}
|
||||
|
||||
return (!missingFiles.Any(), missingFiles);
|
||||
@@ -74,10 +76,10 @@ namespace MPF.UmdImageCreator
|
||||
info.SizeAndChecksums.SHA1 = sha1;
|
||||
}
|
||||
|
||||
if (GetUMDAuxInfo(basePath + "_disc.txt", out string title, out RedumpDiscCategory? umdcat, out string umdversion, out string umdlayer, out long umdsize))
|
||||
if (GetUMDAuxInfo(basePath + "_disc.txt", out string title, out DiscCategory? umdcat, out string umdversion, out string umdlayer, out long umdsize))
|
||||
{
|
||||
info.CommonDiscInfo.Title = title ?? "";
|
||||
info.CommonDiscInfo.Category = umdcat ?? RedumpDiscCategory.Games;
|
||||
info.CommonDiscInfo.Category = umdcat ?? DiscCategory.Games;
|
||||
info.VersionAndEditions.Version = umdversion ?? "";
|
||||
info.SizeAndChecksums.Size = umdsize;
|
||||
|
||||
@@ -169,7 +171,7 @@ namespace MPF.UmdImageCreator
|
||||
/// </summary>
|
||||
/// <param name="disc">_disc.txt file location</param>
|
||||
/// <returns>True on successful extraction of info, false otherwise</returns>
|
||||
private static bool GetUMDAuxInfo(string disc, out string title, out RedumpDiscCategory? umdcat, out string umdversion, out string umdlayer, out long umdsize)
|
||||
private static bool GetUMDAuxInfo(string disc, out string title, out DiscCategory? umdcat, out string umdversion, out string umdlayer, out long umdsize)
|
||||
{
|
||||
title = null; umdcat = null; umdversion = null; umdlayer = null; umdsize = -1;
|
||||
|
||||
168
MPF.Test/Core/Converters/EnumConverterTests.cs
Normal file
168
MPF.Test/Core/Converters/EnumConverterTests.cs
Normal file
@@ -0,0 +1,168 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
#if NET_FRAMEWORK
|
||||
using IMAPI2;
|
||||
#endif
|
||||
using MPF.Core.Converters;
|
||||
using MPF.Core.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Core.Converters
|
||||
{
|
||||
public class EnumConverterTests
|
||||
{
|
||||
#region Cross-enumeration conversions
|
||||
|
||||
/// <summary>
|
||||
/// DiscType values that map to InternalDriveType
|
||||
/// </summary>
|
||||
private static readonly DriveType[] _mappableDriveTypes = new DriveType[]
|
||||
{
|
||||
DriveType.CDRom,
|
||||
DriveType.Fixed,
|
||||
DriveType.Removable,
|
||||
};
|
||||
|
||||
#if NET_FRAMEWORK
|
||||
/// <summary>
|
||||
/// IMAPI_MEDIA_PHYSICAL_TYPE values that map to MediaType
|
||||
/// </summary>
|
||||
private static readonly IMAPI_MEDIA_PHYSICAL_TYPE[] _mappableImapiTypes = new IMAPI_MEDIA_PHYSICAL_TYPE[]
|
||||
{
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_UNKNOWN,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_CDROM,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_CDR,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_CDRW,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDROM,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDRAM,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDPLUSR,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDPLUSRW,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDPLUSR_DUALLAYER,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDDASHR,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDDASHRW,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDDASHR_DUALLAYER,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DISK,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DVDPLUSRW_DUALLAYER,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_HDDVDROM,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_HDDVDR,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_HDDVDRAM,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_BDROM,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_BDR,
|
||||
IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_BDRE,
|
||||
};
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Check that every supported DriveType maps to an InternalDriveType
|
||||
/// </summary>
|
||||
/// <param name="driveType">DriveType value to check</param>
|
||||
/// <param name="expectNull">True to expect a null mapping, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateDriveTypeMappingTestData))]
|
||||
public void ToInternalDriveTypeTest(DriveType driveType, bool expectNull)
|
||||
{
|
||||
var actual = driveType.ToInternalDriveType();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
#if NET_FRAMEWORK
|
||||
/// <summary>
|
||||
/// Check that every supported IMAPI_MEDIA_PHYSICAL_TYPE maps to an MediaType
|
||||
/// </summary>
|
||||
/// <param name="imapiType">IMAPI_MEDIA_PHYSICAL_TYPE value to check</param>
|
||||
/// <param name="expectNull">True to expect a null mapping, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateImapiTypeMappingTestData))]
|
||||
public void IMAPIToMediaTypeTest(IMAPI_MEDIA_PHYSICAL_TYPE imapiType, bool expectNull)
|
||||
{
|
||||
var actual = imapiType.IMAPIToMediaType();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of DriveType values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of DriveType values</returns>
|
||||
public static List<object[]> GenerateDriveTypeMappingTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
foreach (DriveType driveType in Enum.GetValues(typeof(DriveType)))
|
||||
{
|
||||
if (_mappableDriveTypes.Contains(driveType))
|
||||
testData.Add(new object[] { driveType, false });
|
||||
else
|
||||
testData.Add(new object[] { driveType, true });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#if NET_FRAMEWORK
|
||||
/// <summary>
|
||||
/// Generate a test set of IMAPI_MEDIA_PHYSICAL_TYPE values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of IMAPI_MEDIA_PHYSICAL_TYPE values</returns>
|
||||
public static List<object[]> GenerateImapiTypeMappingTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, false } };
|
||||
foreach (IMAPI_MEDIA_PHYSICAL_TYPE imapiType in Enum.GetValues(typeof(IMAPI_MEDIA_PHYSICAL_TYPE)))
|
||||
{
|
||||
if (_mappableImapiTypes.Contains(imapiType))
|
||||
testData.Add(new object[] { imapiType, false });
|
||||
else
|
||||
testData.Add(new object[] { imapiType, true });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
#region Convert to Long Name
|
||||
|
||||
// TODO: Maybe add a test for the generic "GetLongName" method
|
||||
|
||||
/// <summary>
|
||||
/// Check that every InternalProgram has a long name provided
|
||||
/// </summary>
|
||||
/// <param name="internalProgram">InternalProgram value to check</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateInternalProgramTestData))]
|
||||
public void InternalProgramLongNameTest(InternalProgram? internalProgram)
|
||||
{
|
||||
string actual = internalProgram.LongName();
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of InternalProgram values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of InternalProgram values</returns>
|
||||
public static List<object[]> GenerateInternalProgramTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null } };
|
||||
foreach (InternalProgram? internalProgram in Enum.GetValues(typeof(InternalProgram)))
|
||||
{
|
||||
testData.Add(new object[] { internalProgram });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// TODO: Add from-string tests
|
||||
}
|
||||
}
|
||||
42
MPF.Test/Core/Data/ResultTests.cs
Normal file
42
MPF.Test/Core/Data/ResultTests.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using MPF.Core.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Core.Data
|
||||
{
|
||||
public class ResultTests
|
||||
{
|
||||
[Fact]
|
||||
public void EmptySuccessTest()
|
||||
{
|
||||
var actual = Result.Success();
|
||||
Assert.True(actual);
|
||||
Assert.Empty(actual.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CustomMessageSuccessTest()
|
||||
{
|
||||
string message = "Success!";
|
||||
var actual = Result.Success(message);
|
||||
Assert.True(actual);
|
||||
Assert.Equal(message, actual.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EmptyFailureTest()
|
||||
{
|
||||
var actual = Result.Failure();
|
||||
Assert.False(actual);
|
||||
Assert.Empty(actual.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CustomMessageFailureTest()
|
||||
{
|
||||
string message = "Failure!";
|
||||
var actual = Result.Failure(message);
|
||||
Assert.False(actual);
|
||||
Assert.Equal(message, actual.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
115
MPF.Test/Core/Data/XgdInfoTests.cs
Normal file
115
MPF.Test/Core/Data/XgdInfoTests.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using MPF.Core.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Core.Data
|
||||
{
|
||||
public class XgdInfoTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("")]
|
||||
[InlineData("1234567")]
|
||||
[InlineData("1234567\0")]
|
||||
[InlineData("123456789")]
|
||||
public void UnmatchedStringTests(string invalidString)
|
||||
{
|
||||
XgdInfo xgdInfo = new XgdInfo(invalidString);
|
||||
Assert.False(xgdInfo.Initialized);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("AV00100W", "AV", "001", "00", 'W')]
|
||||
[InlineData("AV00100W\0", "AV", "001", "00", 'W')]
|
||||
public void XGD1ValidTests(string validString, string publisher, string gameId, string version, char regionIdentifier)
|
||||
{
|
||||
XgdInfo xgdInfo = new XgdInfo(validString, validate: true);
|
||||
|
||||
Assert.True(xgdInfo.Initialized);
|
||||
Assert.Equal(publisher, xgdInfo.PublisherIdentifier);
|
||||
Assert.Equal(gameId, xgdInfo.GameID);
|
||||
Assert.Equal(version, xgdInfo.SKU);
|
||||
Assert.Equal(regionIdentifier, xgdInfo.RegionIdentifier);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
// Invalid publisher identifier
|
||||
[InlineData("ZZ000000")]
|
||||
[InlineData("ZZ000000\0")]
|
||||
// Invalid region identifier
|
||||
[InlineData("AV00000Z")]
|
||||
[InlineData("AV00000Z\0")]
|
||||
public void XGD1InvalidTests(string invalidString)
|
||||
{
|
||||
XgdInfo xgdInfo = new XgdInfo(invalidString, validate: true);
|
||||
Assert.False(xgdInfo.Initialized);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("AV200100W0F11", "AV", "001", "00", 'W', "0", 'F', "11", null)]
|
||||
[InlineData("AV200100W0F11\0", "AV", "001", "00", 'W', "0", 'F', "11", null)]
|
||||
[InlineData("AV200100W01F11", "AV", "001", "00", 'W', "01", 'F', "11", null)]
|
||||
[InlineData("AV200100W01F11\0", "AV", "001", "00", 'W', "01", 'F', "11", null)]
|
||||
[InlineData("AV200100W0F11DEADBEEF", "AV", "001", "00", 'W', "0", 'F', "11", "DEADBEEF")]
|
||||
[InlineData("AV200100W0F11DEADBEEF\0", "AV", "001", "00", 'W', "0", 'F', "11", "DEADBEEF")]
|
||||
[InlineData("AV200100W01F11DEADBEEF", "AV", "001", "00", 'W', "01", 'F', "11", "DEADBEEF")]
|
||||
[InlineData("AV200100W01F11DEADBEEF\0", "AV", "001", "00", 'W', "01", 'F', "11", "DEADBEEF")]
|
||||
public void XGD23ValidTests(string validString, string publisher, string gameId, string sku, char regionIdentifier, string baseVersion, char mediaSubtype, string discNumber, string cert)
|
||||
{
|
||||
XgdInfo xgdInfo = new XgdInfo(validString, validate: true);
|
||||
|
||||
Assert.True(xgdInfo.Initialized);
|
||||
Assert.Equal(publisher, xgdInfo.PublisherIdentifier);
|
||||
Assert.Equal('2', xgdInfo.PlatformIdentifier);
|
||||
Assert.Equal(gameId, xgdInfo.GameID);
|
||||
Assert.Equal(sku, xgdInfo.SKU);
|
||||
Assert.Equal(regionIdentifier, xgdInfo.RegionIdentifier);
|
||||
Assert.Equal(baseVersion, xgdInfo.BaseVersion);
|
||||
Assert.Equal(mediaSubtype, xgdInfo.MediaSubtypeIdentifier);
|
||||
Assert.Equal(discNumber, xgdInfo.DiscNumberIdentifier);
|
||||
Assert.Equal(cert, xgdInfo.CertificationSubmissionIdentifier);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
// Invalid publisher identifier
|
||||
[InlineData("ZZ00000000000")]
|
||||
[InlineData("ZZ00000000000\0")]
|
||||
[InlineData("ZZ000000000000")]
|
||||
[InlineData("ZZ000000000000\0")]
|
||||
[InlineData("ZZ0000000000000000000")]
|
||||
[InlineData("ZZ0000000000000000000\0")]
|
||||
[InlineData("ZZ00000000000000000000")]
|
||||
[InlineData("ZZ00000000000000000000\0")]
|
||||
// Invalid platform identifier
|
||||
[InlineData("AV90000000000")]
|
||||
[InlineData("AV90000000000\0")]
|
||||
[InlineData("AV900000000000")]
|
||||
[InlineData("AV900000000000\0")]
|
||||
[InlineData("AV9000000000000000000")]
|
||||
[InlineData("AV9000000000000000000\0")]
|
||||
[InlineData("AV90000000000000000000")]
|
||||
[InlineData("AV90000000000000000000\0")]
|
||||
// Invalid region identifier
|
||||
[InlineData("AV200000Z0000")]
|
||||
[InlineData("AV200000Z0000\0")]
|
||||
[InlineData("AV200000Z00000")]
|
||||
[InlineData("AV200000Z00000\0")]
|
||||
[InlineData("AV200000Z000000000000")]
|
||||
[InlineData("AV200000Z000000000000\0")]
|
||||
[InlineData("AV200000Z0000000000000")]
|
||||
[InlineData("AV200000Z0000000000000\0")]
|
||||
// Invalid media subtype identifier
|
||||
[InlineData("AV200000W0A00")]
|
||||
[InlineData("AV200000W0A00\0")]
|
||||
[InlineData("AV200000W00A00")]
|
||||
[InlineData("AV200000W00A00\0")]
|
||||
[InlineData("AV200000W00A000000000")]
|
||||
[InlineData("AV200000W00A000000000\0")]
|
||||
[InlineData("AV200000W00A0000000000")]
|
||||
[InlineData("AV200000W00A0000000000\0")]
|
||||
public void XGD23InvalidTests(string invalidString)
|
||||
{
|
||||
XgdInfo xgdInfo = new XgdInfo(invalidString, validate: true);
|
||||
Assert.False(xgdInfo.Initialized);
|
||||
}
|
||||
}
|
||||
}
|
||||
229
MPF.Test/Core/Utilities/EnumExtensionsTests.cs
Normal file
229
MPF.Test/Core/Utilities/EnumExtensionsTests.cs
Normal file
@@ -0,0 +1,229 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MPF.Core.Utilities;
|
||||
using RedumpLib.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Core.Utilities
|
||||
{
|
||||
public class EnumExtensionsTests
|
||||
{
|
||||
/// <summary>
|
||||
/// MediaType values that support drive speeds
|
||||
/// </summary>
|
||||
private static readonly MediaType?[] _supportDriveSpeeds = new MediaType?[]
|
||||
{
|
||||
MediaType.CDROM,
|
||||
MediaType.DVD,
|
||||
MediaType.GDROM,
|
||||
MediaType.HDDVD,
|
||||
MediaType.BluRay,
|
||||
MediaType.NintendoGameCubeGameDisc,
|
||||
MediaType.NintendoWiiOpticalDisc,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// RedumpSystem values that are considered Audio
|
||||
/// </summary>
|
||||
private static readonly RedumpSystem?[] _audioSystems = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.AtariJaguarCDInteractiveMultimediaSystem,
|
||||
RedumpSystem.AudioCD,
|
||||
RedumpSystem.DVDAudio,
|
||||
RedumpSystem.HasbroVideoNow,
|
||||
RedumpSystem.HasbroVideoNowColor,
|
||||
RedumpSystem.HasbroVideoNowJr,
|
||||
RedumpSystem.HasbroVideoNowXP,
|
||||
RedumpSystem.PhilipsCDi,
|
||||
RedumpSystem.SuperAudioCD,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// RedumpSystem values that are considered markers
|
||||
/// </summary>
|
||||
private static readonly RedumpSystem?[] _markerSystems = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.MarkerArcadeEnd,
|
||||
RedumpSystem.MarkerComputerEnd,
|
||||
RedumpSystem.MarkerDiscBasedConsoleEnd,
|
||||
RedumpSystem.MarkerOtherEnd,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// RedumpSystem values that are have reversed ringcodes
|
||||
/// </summary>
|
||||
private static readonly RedumpSystem?[] _reverseRingcodeSystems = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.SonyPlayStation2,
|
||||
RedumpSystem.SonyPlayStation3,
|
||||
RedumpSystem.SonyPlayStation4,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// RedumpSystem values that are considered XGD
|
||||
/// </summary>
|
||||
private static readonly RedumpSystem?[] _xgdSystems = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.MicrosoftXbox,
|
||||
RedumpSystem.MicrosoftXbox360,
|
||||
RedumpSystem.MicrosoftXboxOne,
|
||||
RedumpSystem.MicrosoftXboxSeriesXS,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Check that all optical media support drive speeds
|
||||
/// </summary>
|
||||
/// <param name="mediaType">DriveType value to check</param>
|
||||
/// <param name="expected">The expected value to come from the check</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateSupportDriveSpeedsTestData))]
|
||||
public void DoesSupportDriveSpeedTest(MediaType? mediaType, bool expected)
|
||||
{
|
||||
bool actual = mediaType.DoesSupportDriveSpeed();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that all systems with reversed ringcodes are marked properly
|
||||
/// </summary>
|
||||
/// <param name="redumpSystem">RedumpSystem value to check</param>
|
||||
/// <param name="expected">The expected value to come from the check</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateReversedRingcodeSystemsTestData))]
|
||||
public void HasReversedRingcodesTest(RedumpSystem? redumpSystem, bool expected)
|
||||
{
|
||||
bool actual = redumpSystem.HasReversedRingcodes();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that all audio systems are marked properly
|
||||
/// </summary>
|
||||
/// <param name="redumpSystem">RedumpSystem value to check</param>
|
||||
/// <param name="expected">The expected value to come from the check</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateAudioSystemsTestData))]
|
||||
public void IsAudioTest(RedumpSystem? redumpSystem, bool expected)
|
||||
{
|
||||
bool actual = redumpSystem.IsAudio();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that all marker systems are marked properly
|
||||
/// </summary>
|
||||
/// <param name="redumpSystem">RedumpSystem value to check</param>
|
||||
/// <param name="expected">The expected value to come from the check</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateMarkerSystemsTestData))]
|
||||
public void IsMarkerTest(RedumpSystem? redumpSystem, bool expected)
|
||||
{
|
||||
bool actual = redumpSystem.IsMarker();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that all XGD systems are marked properly
|
||||
/// </summary>
|
||||
/// <param name="redumpSystem">RedumpSystem value to check</param>
|
||||
/// <param name="expected">The expected value to come from the check</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateXGDSystemsTestData))]
|
||||
public void IsXGDTest(RedumpSystem? redumpSystem, bool expected)
|
||||
{
|
||||
bool actual = redumpSystem.IsXGD();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of MediaType values that support drive speeds
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of MediaType values</returns>
|
||||
public static List<object[]> GenerateSupportDriveSpeedsTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, false } };
|
||||
foreach (MediaType mediaType in Enum.GetValues(typeof(MediaType)))
|
||||
{
|
||||
if (_supportDriveSpeeds.Contains(mediaType))
|
||||
testData.Add(new object[] { mediaType, true });
|
||||
else
|
||||
testData.Add(new object[] { mediaType, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of RedumpSystem values that are considered Audio
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of RedumpSystem values</returns>
|
||||
public static List<object[]> GenerateAudioSystemsTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, false } };
|
||||
foreach (RedumpSystem redumpSystem in Enum.GetValues(typeof(RedumpSystem)))
|
||||
{
|
||||
if (_audioSystems.Contains(redumpSystem))
|
||||
testData.Add(new object[] { redumpSystem, true });
|
||||
else
|
||||
testData.Add(new object[] { redumpSystem, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of RedumpSystem values that are considered markers
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of RedumpSystem values</returns>
|
||||
public static List<object[]> GenerateMarkerSystemsTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, false } };
|
||||
foreach (RedumpSystem redumpSystem in Enum.GetValues(typeof(RedumpSystem)))
|
||||
{
|
||||
if (_markerSystems.Contains(redumpSystem))
|
||||
testData.Add(new object[] { redumpSystem, true });
|
||||
else
|
||||
testData.Add(new object[] { redumpSystem, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of RedumpSystem values that are considered markers
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of RedumpSystem values</returns>
|
||||
public static List<object[]> GenerateReversedRingcodeSystemsTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, false } };
|
||||
foreach (RedumpSystem redumpSystem in Enum.GetValues(typeof(RedumpSystem)))
|
||||
{
|
||||
if (_reverseRingcodeSystems.Contains(redumpSystem))
|
||||
testData.Add(new object[] { redumpSystem, true });
|
||||
else
|
||||
testData.Add(new object[] { redumpSystem, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of RedumpSystem values that are considered XGD
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of RedumpSystem values</returns>
|
||||
public static List<object[]> GenerateXGDSystemsTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, false } };
|
||||
foreach (RedumpSystem redumpSystem in Enum.GetValues(typeof(RedumpSystem)))
|
||||
{
|
||||
if (_xgdSystems.Contains(redumpSystem))
|
||||
testData.Add(new object[] { redumpSystem, true });
|
||||
else
|
||||
testData.Add(new object[] { redumpSystem, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
}
|
||||
}
|
||||
31
MPF.Test/Library/DumpEnvironmentTests.cs
Normal file
31
MPF.Test/Library/DumpEnvironmentTests.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System.IO;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Library;
|
||||
using RedumpLib.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Library
|
||||
{
|
||||
public class DumpEnvironmentTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(null, 'D', false, MediaType.NONE, false)]
|
||||
[InlineData("", 'D', false, MediaType.NONE, false)]
|
||||
[InlineData("cd F test.bin 8 /c2 20", 'F', false, MediaType.CDROM, true)]
|
||||
[InlineData("fd A test.img", 'A', true, MediaType.FloppyDisk, true)]
|
||||
[InlineData("dvd X test.iso 8 /raw", 'X', false, MediaType.FloppyDisk, false)]
|
||||
[InlineData("stop D", 'D', false, MediaType.DVD, true)]
|
||||
public void ParametersValidTest(string parameters, char letter, bool isFloppy, MediaType? mediaType, bool expected)
|
||||
{
|
||||
var options = new Options() { InternalProgram = InternalProgram.DiscImageCreator };
|
||||
var drive = isFloppy
|
||||
? new Drive(InternalDriveType.Floppy, new DriveInfo(letter.ToString()))
|
||||
: new Drive(InternalDriveType.Optical, new DriveInfo(letter.ToString()));
|
||||
|
||||
var env = new DumpEnvironment(options, string.Empty, string.Empty, drive, RedumpSystem.IBMPCcompatible, mediaType, parameters);
|
||||
|
||||
bool actual = env.ParametersValid();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
196
MPF.Test/Library/InfoToolTests.cs
Normal file
196
MPF.Test/Library/InfoToolTests.cs
Normal file
@@ -0,0 +1,196 @@
|
||||
using System.Collections.Generic;
|
||||
using MPF.Library;
|
||||
using RedumpLib.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Library
|
||||
{
|
||||
public class InfoToolTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(null, 0, 0, 0, 0, null)]
|
||||
[InlineData(null, 12345, 0, 0, 0, null)]
|
||||
[InlineData(null, 12345, 1, 0, 0, null)]
|
||||
[InlineData(null, 12345, 1, 2, 0, null)]
|
||||
[InlineData(null, 12345, 1, 2, 3, null)]
|
||||
[InlineData(MediaType.CDROM, 0, 0, 0, 0, "CD-ROM")]
|
||||
[InlineData(MediaType.CDROM, 12345, 0, 0, 0, "CD-ROM")]
|
||||
[InlineData(MediaType.CDROM, 12345, 1, 0, 0, "CD-ROM")]
|
||||
[InlineData(MediaType.CDROM, 12345, 1, 2, 0, "CD-ROM")]
|
||||
[InlineData(MediaType.CDROM, 12345, 1, 2, 3, "CD-ROM")]
|
||||
[InlineData(MediaType.DVD, 0, 0, 0, 0, "DVD-ROM-5")]
|
||||
[InlineData(MediaType.DVD, 12345, 0, 0, 0, "DVD-ROM-5")]
|
||||
[InlineData(MediaType.DVD, 12345, 1, 0, 0, "DVD-ROM-9")]
|
||||
[InlineData(MediaType.DVD, 12345, 1, 2, 0, "DVD-ROM-9")]
|
||||
[InlineData(MediaType.DVD, 12345, 1, 2, 3, "DVD-ROM-9")]
|
||||
[InlineData(MediaType.BluRay, 0, 0, 0, 0, "BD-ROM-25")]
|
||||
[InlineData(MediaType.BluRay, 12345, 0, 0, 0, "BD-ROM-25")]
|
||||
[InlineData(MediaType.BluRay, 26_843_531_857, 0, 0, 0, "BD-ROM-33")]
|
||||
[InlineData(MediaType.BluRay, 12345, 1, 0, 0, "BD-ROM-50")]
|
||||
[InlineData(MediaType.BluRay, 53_687_063_713, 1, 0, 0, "BD-ROM-66")]
|
||||
[InlineData(MediaType.BluRay, 12345, 1, 2, 0, "BD-ROM-100")]
|
||||
[InlineData(MediaType.BluRay, 12345, 1, 2, 3, "BD-ROM-128")]
|
||||
[InlineData(MediaType.UMD, 0, 0, 0, 0, "UMD-SL")]
|
||||
[InlineData(MediaType.UMD, 12345, 0, 0, 0, "UMD-SL")]
|
||||
[InlineData(MediaType.UMD, 12345, 1, 0, 0, "UMD-DL")]
|
||||
[InlineData(MediaType.UMD, 12345, 1, 2, 0, "UMD-DL")]
|
||||
[InlineData(MediaType.UMD, 12345, 1, 2, 3, "UMD-DL")]
|
||||
public void GetFixedMediaTypeTest(
|
||||
MediaType? mediaType,
|
||||
long size,
|
||||
long layerbreak,
|
||||
long layerbreak2,
|
||||
long layerbreak3,
|
||||
string expected)
|
||||
{
|
||||
string actual = InfoTool.GetFixedMediaType(mediaType, size, layerbreak, layerbreak2, layerbreak3);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null, null, null)]
|
||||
[InlineData(" ", "", " ", "")]
|
||||
[InlineData("super", "blah.bin", "super", "blah.bin")]
|
||||
[InlineData("super\\hero", "blah.bin", "super\\hero", "blah.bin")]
|
||||
[InlineData("super.hero", "blah.bin", "super.hero", "blah.bin")]
|
||||
[InlineData("superhero", "blah.rev.bin", "superhero", "blah.rev.bin")]
|
||||
[InlineData("super&hero", "blah.bin", "super&hero", "blah.bin")]
|
||||
[InlineData("superhero", "blah&foo.bin", "superhero", "blah&foo.bin")]
|
||||
public void NormalizeOutputPathsTest(string outputDirectory, string outputFilename, string expectedOutputDirectory, string expectedOutputFilename)
|
||||
{
|
||||
(string actualOutputDirectory, string actualOutputFilename) = InfoTool.NormalizeOutputPaths(outputDirectory, outputFilename);
|
||||
Assert.Equal(expectedOutputDirectory, actualOutputDirectory);
|
||||
Assert.Equal(expectedOutputFilename, actualOutputFilename);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcessSpecialFieldsCompleteTest()
|
||||
{
|
||||
// Create a new SubmissionInfo object
|
||||
SubmissionInfo info = new SubmissionInfo()
|
||||
{
|
||||
CommonDiscInfo = new CommonDiscInfoSection()
|
||||
{
|
||||
Comments = "This is a comments line\n[T:ISBN] ISBN Value",
|
||||
CommentsSpecialFields = new Dictionary<SiteCode?, string>()
|
||||
{
|
||||
[SiteCode.VolumeLabel] = "VOLUME_LABEL",
|
||||
},
|
||||
|
||||
Contents = "This is a contents line\n[T:GF] Game Footage",
|
||||
ContentsSpecialFields = new Dictionary<SiteCode?, string>()
|
||||
{
|
||||
[SiteCode.Patches] = "1.04 patch",
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
// Process the special fields
|
||||
InfoTool.ProcessSpecialFields(info);
|
||||
|
||||
// Validate the basics
|
||||
Assert.NotNull(info.CommonDiscInfo.Comments);
|
||||
Assert.Null(info.CommonDiscInfo.CommentsSpecialFields);
|
||||
Assert.NotNull(info.CommonDiscInfo.Contents);
|
||||
Assert.Null(info.CommonDiscInfo.ContentsSpecialFields);
|
||||
|
||||
// Split the values
|
||||
string[] splitComments = info.CommonDiscInfo.Comments.Split('\n');
|
||||
string[] splitContents = info.CommonDiscInfo.Contents.Split('\n');
|
||||
|
||||
// Validate the lines
|
||||
Assert.Equal(3, splitComments.Length);
|
||||
Assert.Equal(5, splitContents.Length);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcessSpecialFieldsNullObjectTest()
|
||||
{
|
||||
// Create a new SubmissionInfo object
|
||||
SubmissionInfo info = new SubmissionInfo()
|
||||
{
|
||||
CommonDiscInfo = null,
|
||||
};
|
||||
|
||||
// Process the special fields
|
||||
InfoTool.ProcessSpecialFields(info);
|
||||
|
||||
// Validate
|
||||
Assert.Null(info.CommonDiscInfo);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcessSpecialFieldsNullCommentsContentsTest()
|
||||
{
|
||||
// Create a new SubmissionInfo object
|
||||
SubmissionInfo info = new SubmissionInfo()
|
||||
{
|
||||
CommonDiscInfo = new CommonDiscInfoSection()
|
||||
{
|
||||
Comments = null,
|
||||
CommentsSpecialFields = new Dictionary<SiteCode?, string>()
|
||||
{
|
||||
[SiteCode.VolumeLabel] = "VOLUME_LABEL",
|
||||
},
|
||||
|
||||
Contents = null,
|
||||
ContentsSpecialFields = new Dictionary<SiteCode?, string>()
|
||||
{
|
||||
[SiteCode.Patches] = "1.04 patch",
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
// Process the special fields
|
||||
InfoTool.ProcessSpecialFields(info);
|
||||
|
||||
// Validate the basics
|
||||
Assert.NotNull(info.CommonDiscInfo.Comments);
|
||||
Assert.Null(info.CommonDiscInfo.CommentsSpecialFields);
|
||||
Assert.NotNull(info.CommonDiscInfo.Contents);
|
||||
Assert.Null(info.CommonDiscInfo.ContentsSpecialFields);
|
||||
|
||||
// Split the values
|
||||
string[] splitComments = info.CommonDiscInfo.Comments.Split('\n');
|
||||
string[] splitContents = info.CommonDiscInfo.Contents.Split('\n');
|
||||
|
||||
// Validate the lines
|
||||
Assert.Single(splitComments);
|
||||
Assert.Equal(2, splitContents.Length);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcessSpecialFieldsNullDictionariesTest()
|
||||
{
|
||||
// Create a new SubmissionInfo object
|
||||
SubmissionInfo info = new SubmissionInfo()
|
||||
{
|
||||
CommonDiscInfo = new CommonDiscInfoSection()
|
||||
{
|
||||
Comments = "This is a comments line\n[T:ISBN] ISBN Value",
|
||||
CommentsSpecialFields = null,
|
||||
|
||||
Contents = "This is a contents line\n[T:GF] Game Footage",
|
||||
ContentsSpecialFields = null,
|
||||
}
|
||||
};
|
||||
|
||||
// Process the special fields
|
||||
InfoTool.ProcessSpecialFields(info);
|
||||
|
||||
// Validate the basics
|
||||
Assert.NotNull(info.CommonDiscInfo.Comments);
|
||||
Assert.Null(info.CommonDiscInfo.CommentsSpecialFields);
|
||||
Assert.NotNull(info.CommonDiscInfo.Contents);
|
||||
Assert.Null(info.CommonDiscInfo.ContentsSpecialFields);
|
||||
|
||||
// Split the values
|
||||
string[] splitComments = info.CommonDiscInfo.Comments.Split('\n');
|
||||
string[] splitContents = info.CommonDiscInfo.Contents.Split('\n');
|
||||
|
||||
// Validate the lines
|
||||
Assert.Equal(2, splitComments.Length);
|
||||
Assert.Equal(2, splitContents.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
271
MPF.Test/Library/ProtectionTests.cs
Normal file
271
MPF.Test/Library/ProtectionTests.cs
Normal file
@@ -0,0 +1,271 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MPF.Library;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Library
|
||||
{
|
||||
public class ProtectionTests
|
||||
{
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsActiveMARKTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"ActiveMARK",
|
||||
"ActiveMARK 5",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("ActiveMARK 5", sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsCactusDataShieldTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"Cactus Data Shield 200",
|
||||
"Cactus Data Shield 200 (Build 3.0.100a)",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("Cactus Data Shield 200 (Build 3.0.100a)", sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsCDCheckTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"Anything Else Protection",
|
||||
"Executable-Based CD Check",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("Anything Else Protection", sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsCDCopsTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"CD-Cops",
|
||||
"CD-Cops v1.2.0",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("CD-Cops v1.2.0", sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsCDKeyTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"Anything Else Protection",
|
||||
"CD-Key / Serial",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("Anything Else Protection", sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsEACdKeyTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"EA CdKey Registration Module",
|
||||
"EA CdKey Registration Module v1.2.0",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("EA CdKey Registration Module v1.2.0", sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsEADRMTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"EA DRM Protection",
|
||||
"EA DRM Protection v1.2.0",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("EA DRM Protection v1.2.0", sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsGFWLTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"Games for Windows LIVE",
|
||||
"Games for Windows LIVE v1.2.0",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("Games for Windows LIVE v1.2.0", sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsGFWLZDPPTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"Games for Windows LIVE",
|
||||
"Games for Windows LIVE Zero Day Piracy Protection",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("Games for Windows LIVE, Games for Windows LIVE Zero Day Piracy Protection", sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsImpulseReactorTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"Impulse Reactor",
|
||||
"Impulse Reactor Core Module v1.2.0",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("Impulse Reactor Core Module v1.2.0", sanitized);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0)]
|
||||
[InlineData(1)]
|
||||
[InlineData(2)]
|
||||
[InlineData(3)]
|
||||
public void SanitizeFoundProtectionsJoWoodXProtTest(int skip)
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"JoWood X-Prot 1.2.0.00",
|
||||
"JoWood X-Prot v2",
|
||||
"JoWood X-Prot v1.4+",
|
||||
"JoWood X-Prot v1.0-v1.3",
|
||||
"JoWood X-Prot",
|
||||
};
|
||||
|
||||
// Safeguard for the future
|
||||
if (skip >= protections.Count)
|
||||
throw new ArgumentException("Invalid skip value", nameof(skip));
|
||||
|
||||
// The list is in order of preference
|
||||
protections = protections.Skip(skip).ToList();
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal(protections[0], sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsOnlineRegistrationTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"Anything Else Protection",
|
||||
"Executable-Based Online Registration",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("Anything Else Protection", sanitized);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0)]
|
||||
[InlineData(1)]
|
||||
[InlineData(2)]
|
||||
[InlineData(3)]
|
||||
[InlineData(4)]
|
||||
[InlineData(5)]
|
||||
[InlineData(6)]
|
||||
[InlineData(7)]
|
||||
[InlineData(8)]
|
||||
public void SanitizeFoundProtectionsSafeDiscTest(int skip)
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"SafeDisc 1.20.000",
|
||||
"SafeDisc (drvmgt.dll) 1.2.0",
|
||||
"SafeDisc (secdrv.sys) 1.2.0",
|
||||
"SafeDisc (dplayerx.dll) 1.2.0",
|
||||
"SafeDisc 3.20-4.xx (version removed)",
|
||||
"SafeDisc 2",
|
||||
"SafeDisc 1/Lite",
|
||||
"SafeDisc Lite",
|
||||
"SafeDisc 1-3",
|
||||
"SafeDisc",
|
||||
};
|
||||
|
||||
// Safeguard for the future
|
||||
if (skip >= protections.Count)
|
||||
throw new ArgumentException("Invalid skip value", nameof(skip));
|
||||
|
||||
// The list is in order of preference
|
||||
protections = protections.Skip(skip).ToList();
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal(protections[0], sanitized);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0)]
|
||||
[InlineData(1)]
|
||||
[InlineData(2)]
|
||||
[InlineData(3)]
|
||||
public void SanitizeFoundProtectionStarForceTest(int skip)
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"StarForce 1.20.000.000",
|
||||
"StarForce 5 [Protected Module]",
|
||||
"StarForce 5",
|
||||
"StarForce 3-5",
|
||||
"StarForce",
|
||||
};
|
||||
|
||||
// Safeguard for the future
|
||||
if (skip >= protections.Count)
|
||||
throw new ArgumentException("Invalid skip value", nameof(skip));
|
||||
|
||||
// The list is in order of preference
|
||||
protections = protections.Skip(skip).ToList();
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal(protections[0], sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsSysiphusTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"Sysiphus",
|
||||
"Sysiphus v1.2.0",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("Sysiphus v1.2.0", sanitized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeFoundProtectionsXCPTest()
|
||||
{
|
||||
List<string> protections = new List<string>()
|
||||
{
|
||||
"XCP",
|
||||
"XCP v1.2.0",
|
||||
};
|
||||
|
||||
string sanitized = Protection.SanitizeFoundProtections(protections);
|
||||
Assert.Equal("XCP v1.2.0", sanitized);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,47 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net48;netcoreapp3.1</TargetFrameworks>
|
||||
<TargetFrameworks>net48;netcoreapp3.1;net5.0-windows</TargetFrameworks>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MPF.Library\MPF.Library.csproj">
|
||||
<Project>{51ab0928-13f9-44bf-a407-b6957a43a056}</Project>
|
||||
<Name>MPF.Library</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MPF\MPF.csproj">
|
||||
<Project>{7b1b75eb-8940-466f-bd51-76471a57f9be}</Project>
|
||||
<Name>MPF</Name>
|
||||
</ProjectReference>
|
||||
<PropertyGroup Condition="'$(TargetFramework)'=='net48'">
|
||||
<DefineConstants>NET_FRAMEWORK</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)'=='net48'">
|
||||
<COMReference Include="IMAPI2">
|
||||
<Guid>{2735412F-7F64-5B0F-8F00-5D77AFBE261E}</Guid>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>0</VersionMinor>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<Isolated>False</Isolated>
|
||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
<COMReference Include="IMAPI2FS">
|
||||
<Guid>{2C941FD0-975B-59BE-A960-9A2A262853A5}</Guid>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>0</VersionMinor>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<Isolated>False</Isolated>
|
||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeCoverage" Version="16.11.0-release-20210626-04" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0-release-20210626-04" />
|
||||
<ProjectReference Include="..\MPF\MPF.csproj" />
|
||||
<ProjectReference Include="..\MPF.Library\MPF.Library.csproj" />
|
||||
<ProjectReference Include="..\MPF.Modules\MPF.Modules.csproj" />
|
||||
<ProjectReference Include="..\RedumpLib\RedumpLib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeCoverage" Version="16.11.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.abstractions" Version="2.0.3" />
|
||||
<PackageReference Include="xunit.analyzers" Version="0.10.0" />
|
||||
|
||||
165
MPF.Test/Modules/DiscImageCreatorTests.cs
Normal file
165
MPF.Test/Modules/DiscImageCreatorTests.cs
Normal file
@@ -0,0 +1,165 @@
|
||||
using System.Collections.Generic;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Modules.DiscImageCreator;
|
||||
using RedumpLib.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Modules
|
||||
{
|
||||
public class DiscImageCreatorTests
|
||||
{
|
||||
#region Old Tests
|
||||
|
||||
[Theory]
|
||||
[InlineData(RedumpSystem.MicrosoftXbox, MediaType.CDROM, CommandStrings.CompactDisc)]
|
||||
[InlineData(RedumpSystem.MicrosoftXbox, MediaType.DVD, CommandStrings.XBOX)]
|
||||
[InlineData(RedumpSystem.MicrosoftXbox, MediaType.LaserDisc, null)]
|
||||
[InlineData(RedumpSystem.SonyPlayStation3, MediaType.BluRay, CommandStrings.BluRay)]
|
||||
[InlineData(RedumpSystem.AppleMacintosh, MediaType.FloppyDisk, CommandStrings.Floppy)]
|
||||
[InlineData(RedumpSystem.RawThrillsVarious, MediaType.GDROM, null)]
|
||||
public void ParametersFromSystemAndTypeTest(RedumpSystem? knownSystem, MediaType? mediaType, string expected)
|
||||
{
|
||||
var options = new Options { };
|
||||
var actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, options);
|
||||
Assert.Equal(expected, actual.BaseCommand);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(RedumpSystem.AppleMacintosh, MediaType.LaserDisc, true, 20, null, null)]
|
||||
[InlineData(RedumpSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc, false, 20, null, new string[] { FlagStrings.Raw })]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, false, 20, null, new string[] { FlagStrings.CopyrightManagementInformation, FlagStrings.ScanFileProtect })]
|
||||
/* paranoid mode tests */
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.CDROM, true, 1000, 2, new string[] { FlagStrings.C2Opcode, FlagStrings.NoFixSubQSecuROM, FlagStrings.ScanFileProtect, FlagStrings.ScanSectorProtect, FlagStrings.SubchannelReadLevel })]
|
||||
[InlineData(RedumpSystem.AppleMacintosh, MediaType.CDROM, false, 20, null, new string[] { FlagStrings.C2Opcode, FlagStrings.NoFixSubQSecuROM, FlagStrings.ScanFileProtect, FlagStrings.ScanSectorProtect, FlagStrings.SubchannelReadLevel })]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, true, 500, null, new string[] { FlagStrings.CopyrightManagementInformation, FlagStrings.ScanFileProtect })]
|
||||
[InlineData(RedumpSystem.HDDVDVideo, MediaType.HDDVD, true, 500, null, new string[] { FlagStrings.CopyrightManagementInformation })]
|
||||
[InlineData(RedumpSystem.IBMPCcompatible, MediaType.DVD, false, 500, null, new string[] { FlagStrings.CopyrightManagementInformation, FlagStrings.ScanFileProtect })]
|
||||
[InlineData(RedumpSystem.HDDVDVideo, MediaType.HDDVD, false, 500, null, new string[] { FlagStrings.CopyrightManagementInformation })]
|
||||
/* reread c2 */
|
||||
[InlineData(RedumpSystem.SegaDreamcast, MediaType.GDROM, false, 1000, null, new string[] { FlagStrings.C2Opcode })]
|
||||
[InlineData(RedumpSystem.SegaDreamcast, MediaType.GDROM, false, -1, null, new string[] { FlagStrings.C2Opcode })]
|
||||
public void ParametersFromOptionsTest(RedumpSystem? knownSystem, MediaType? mediaType, bool paranoid, int rereadC2, int? subchannelLevel, string[] expected)
|
||||
{
|
||||
var options = new Options { DICParanoidMode = paranoid, DICRereadCount = rereadC2 };
|
||||
var actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, options);
|
||||
|
||||
HashSet<string> expectedSet = new HashSet<string>(expected ?? new string[0]);
|
||||
HashSet<string> actualSet = new HashSet<string>(actual.Keys ?? new string[0]);
|
||||
Assert.Equal(expectedSet, actualSet);
|
||||
if (rereadC2 == -1 || !knownSystem.MediaTypes().Contains(mediaType))
|
||||
Assert.Null(actual.C2OpcodeValue[0]);
|
||||
else
|
||||
Assert.Equal(rereadC2, actual.C2OpcodeValue[0]);
|
||||
Assert.Equal(subchannelLevel, actual.SubchannelReadLevelValue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, false)]
|
||||
[InlineData("", false)]
|
||||
[InlineData("cd F test.bin 8 /c2 20", true)]
|
||||
[InlineData("fd A test.img", true)]
|
||||
[InlineData("dvd X super\\test.iso 8 /raw", true)]
|
||||
[InlineData("bd D longer\\path_test.iso 16", true)]
|
||||
[InlineData("stop D", true)]
|
||||
[InlineData("ls", false)]
|
||||
public void ValidateParametersTest(string parameters, bool expected)
|
||||
{
|
||||
var actual = new Parameters(parameters);
|
||||
Assert.Equal(expected, actual.IsValid());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(MediaType.CDROM, ".bin")]
|
||||
[InlineData(MediaType.DVD, ".iso")]
|
||||
[InlineData(MediaType.LaserDisc, ".raw")]
|
||||
[InlineData(MediaType.NintendoWiiUOpticalDisc, ".wud")]
|
||||
[InlineData(MediaType.FloppyDisk, ".img")]
|
||||
[InlineData(MediaType.Cassette, ".wav")]
|
||||
[InlineData(MediaType.NONE, null)]
|
||||
public void MediaTypeToExtensionTest(MediaType? mediaType, string expected)
|
||||
{
|
||||
string actual = MPF.Modules.DiscImageCreator.Converters.Extension(mediaType);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(CommandStrings.Audio, MediaType.CDROM)]
|
||||
[InlineData(CommandStrings.BluRay, MediaType.BluRay)]
|
||||
[InlineData(CommandStrings.Close, null)]
|
||||
[InlineData(CommandStrings.CompactDisc, MediaType.CDROM)]
|
||||
[InlineData(CommandStrings.Data, MediaType.CDROM)]
|
||||
[InlineData(CommandStrings.DigitalVideoDisc, MediaType.DVD)]
|
||||
[InlineData(CommandStrings.Eject, null)]
|
||||
[InlineData(CommandStrings.Floppy, MediaType.FloppyDisk)]
|
||||
[InlineData(CommandStrings.GDROM, MediaType.GDROM)]
|
||||
[InlineData(CommandStrings.MDS, null)]
|
||||
[InlineData(CommandStrings.Reset, null)]
|
||||
[InlineData(CommandStrings.SACD, MediaType.CDROM)]
|
||||
[InlineData(CommandStrings.Start, null)]
|
||||
[InlineData(CommandStrings.Stop, null)]
|
||||
[InlineData(CommandStrings.Sub, null)]
|
||||
[InlineData(CommandStrings.Swap, MediaType.GDROM)]
|
||||
[InlineData(CommandStrings.XBOX, MediaType.DVD)]
|
||||
public void BaseCommandToMediaTypeTest(string command, MediaType? expected)
|
||||
{
|
||||
MediaType? actual = MPF.Modules.DiscImageCreator.Converters.ToMediaType(command);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(CommandStrings.Audio, RedumpSystem.AudioCD)]
|
||||
[InlineData(CommandStrings.BluRay, RedumpSystem.SonyPlayStation3)]
|
||||
[InlineData(CommandStrings.Close, null)]
|
||||
[InlineData(CommandStrings.CompactDisc, RedumpSystem.IBMPCcompatible)]
|
||||
[InlineData(CommandStrings.Data, RedumpSystem.IBMPCcompatible)]
|
||||
[InlineData(CommandStrings.DigitalVideoDisc, RedumpSystem.IBMPCcompatible)]
|
||||
[InlineData(CommandStrings.Eject, null)]
|
||||
[InlineData(CommandStrings.Floppy, RedumpSystem.IBMPCcompatible)]
|
||||
[InlineData(CommandStrings.GDROM, RedumpSystem.SegaDreamcast)]
|
||||
[InlineData(CommandStrings.MDS, null)]
|
||||
[InlineData(CommandStrings.Reset, null)]
|
||||
[InlineData(CommandStrings.SACD, RedumpSystem.SuperAudioCD)]
|
||||
[InlineData(CommandStrings.Start, null)]
|
||||
[InlineData(CommandStrings.Stop, null)]
|
||||
[InlineData(CommandStrings.Sub, null)]
|
||||
[InlineData(CommandStrings.Swap, RedumpSystem.SegaDreamcast)]
|
||||
[InlineData(CommandStrings.XBOX, RedumpSystem.MicrosoftXbox)]
|
||||
public void BaseCommandToRedumpSystemTest(string command, RedumpSystem? expected)
|
||||
{
|
||||
RedumpSystem? actual = MPF.Modules.DiscImageCreator.Converters.ToRedumpSystem(command);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[Fact]
|
||||
public void DiscImageCreatorAudioParametersTest()
|
||||
{
|
||||
string originalParameters = "audio F \"ISO\\Audio CD\\Audio CD.bin\" 72 -5 0";
|
||||
|
||||
// Validate that a common audio commandline is parsed
|
||||
var parametersObject = new Parameters(originalParameters);
|
||||
Assert.NotNull(parametersObject);
|
||||
|
||||
// Validate that the same set of parameters are generated on the output
|
||||
string newParameters = parametersObject.GenerateParameters();
|
||||
Assert.NotNull(newParameters);
|
||||
Assert.Equal(originalParameters, newParameters);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DiscImageCreatorDataParametersTest()
|
||||
{
|
||||
string originalParameters = "data F \"ISO\\Data CD\\Data CD.bin\" 72 -5 0";
|
||||
|
||||
// Validate that a common audio commandline is parsed
|
||||
var parametersObject = new Parameters(originalParameters);
|
||||
Assert.NotNull(parametersObject);
|
||||
|
||||
// Validate that the same set of parameters are generated on the output
|
||||
string newParameters = parametersObject.GenerateParameters();
|
||||
Assert.NotNull(newParameters);
|
||||
Assert.Equal(originalParameters, newParameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
723
MPF.Test/RedumpLib/ExtensionsTests.cs
Normal file
723
MPF.Test/RedumpLib/ExtensionsTests.cs
Normal file
@@ -0,0 +1,723 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using RedumpLib.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.RedumpLib
|
||||
{
|
||||
// TODO: Add tests for string-to-enum conversion
|
||||
public class ExtensionsTests
|
||||
{
|
||||
#region Cross-Enumeration
|
||||
|
||||
/// <summary>
|
||||
/// DiscType values that map to MediaType
|
||||
/// </summary>
|
||||
private static readonly DiscType?[] _mappableDiscTypes = new DiscType?[]
|
||||
{
|
||||
DiscType.BD25,
|
||||
DiscType.BD50,
|
||||
DiscType.CD,
|
||||
DiscType.DVD5,
|
||||
DiscType.DVD9,
|
||||
DiscType.GDROM,
|
||||
DiscType.HDDVDSL,
|
||||
DiscType.NintendoGameCubeGameDisc,
|
||||
DiscType.NintendoWiiOpticalDiscSL,
|
||||
DiscType.NintendoWiiOpticalDiscDL,
|
||||
DiscType.NintendoWiiUOpticalDiscSL,
|
||||
DiscType.UMDSL,
|
||||
DiscType.UMDDL,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// MediaType values that map to DiscType
|
||||
/// </summary>
|
||||
private static readonly MediaType?[] _mappableMediaTypes = new MediaType?[]
|
||||
{
|
||||
MediaType.BluRay,
|
||||
MediaType.CDROM,
|
||||
MediaType.DVD,
|
||||
MediaType.GDROM,
|
||||
MediaType.HDDVD,
|
||||
MediaType.NintendoGameCubeGameDisc,
|
||||
MediaType.NintendoWiiOpticalDisc,
|
||||
MediaType.NintendoWiiUOpticalDisc,
|
||||
MediaType.UMD,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Check that every supported system has some set of MediaTypes supported
|
||||
/// </summary>
|
||||
/// <param name="redumpSystem">RedumpSystem value to check</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateRedumpSystemMappingTestData))]
|
||||
public void MediaTypesTest(RedumpSystem? redumpSystem)
|
||||
{
|
||||
var actual = redumpSystem.MediaTypes();
|
||||
Assert.NotEmpty(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that both mappable and unmappable media types output correctly
|
||||
/// </summary>
|
||||
/// <param name="mediaType">MediaType value to check</param>
|
||||
/// <param name="expectNull">True to expect a null mapping, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateMediaTypeMappingTestData))]
|
||||
public void ToDiscTypeTest(MediaType? mediaType, bool expectNull)
|
||||
{
|
||||
DiscType? actual = mediaType.ToDiscType();
|
||||
Assert.Equal(expectNull, actual == null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that DiscType values all map to something appropriate
|
||||
/// </summary>
|
||||
/// <param name="discType">DiscType value to check</param>
|
||||
/// <param name="expectNull">True to expect a null mapping, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateDiscTypeMappingTestData))]
|
||||
public void ToMediaTypeTest(DiscType? discType, bool expectNull)
|
||||
{
|
||||
MediaType? actual = discType.ToMediaType();
|
||||
Assert.Equal(expectNull, actual == null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of DiscType values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of DiscType values</returns>
|
||||
public static List<object[]> GenerateDiscTypeMappingTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
foreach (DiscType? discType in Enum.GetValues(typeof(DiscType)))
|
||||
{
|
||||
if (_mappableDiscTypes.Contains(discType))
|
||||
testData.Add(new object[] { discType, false });
|
||||
else
|
||||
testData.Add(new object[] { discType, true });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of RedumpSystem values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of RedumpSystem values</returns>
|
||||
public static List<object[]> GenerateRedumpSystemMappingTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null } };
|
||||
foreach (RedumpSystem? redumpSystem in Enum.GetValues(typeof(RedumpSystem)))
|
||||
{
|
||||
testData.Add(new object[] { redumpSystem });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of mappable media types
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of MediaTypes</returns>
|
||||
public static List<object[]> GenerateMediaTypeMappingTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
|
||||
foreach (MediaType? mediaType in Enum.GetValues(typeof(MediaType)))
|
||||
{
|
||||
if (_mappableMediaTypes.Contains(mediaType))
|
||||
testData.Add(new object[] { mediaType, false });
|
||||
else
|
||||
testData.Add(new object[] { mediaType, true });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Disc Category
|
||||
|
||||
/// <summary>
|
||||
/// Check that every DiscCategory has a long name provided
|
||||
/// </summary>
|
||||
/// <param name="discCategory">DiscCategory value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateDiscCategoryTestData))]
|
||||
public void DiscCategoryLongNameTest(DiscCategory? discCategory, bool expectNull)
|
||||
{
|
||||
string actual = discCategory.LongName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of DiscCategory values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of DiscCategory values</returns>
|
||||
public static List<object[]> GenerateDiscCategoryTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
foreach (DiscCategory? discCategory in Enum.GetValues(typeof(DiscCategory)))
|
||||
{
|
||||
testData.Add(new object[] { discCategory, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Disc Type
|
||||
|
||||
/// <summary>
|
||||
/// Check that every DiscType has a long name provided
|
||||
/// </summary>
|
||||
/// <param name="discType">DiscType value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateDiscTypeTestData))]
|
||||
public void DiscTypeLongNameTest(DiscType? discType, bool expectNull)
|
||||
{
|
||||
string actual = discType.LongName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of DiscType values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of DiscType values</returns>
|
||||
public static List<object[]> GenerateDiscTypeTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
foreach (DiscType? discType in Enum.GetValues(typeof(DiscType)))
|
||||
{
|
||||
if (discType == DiscType.NONE)
|
||||
testData.Add(new object[] { discType, true });
|
||||
else
|
||||
testData.Add(new object[] { discType, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Language
|
||||
|
||||
/// <summary>
|
||||
/// Check that every Language has a long name provided
|
||||
/// </summary>
|
||||
/// <param name="language">Language value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateLanguageTestData))]
|
||||
public void LanguageLongNameTest(Language? language, bool expectNull)
|
||||
{
|
||||
string actual = language.LongName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that every Language has a short name provided
|
||||
/// </summary>
|
||||
/// <param name="language">Language value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateLanguageTestData))]
|
||||
public void LanguageShortNameTest(Language? language, bool expectNull)
|
||||
{
|
||||
string actual = language.ShortName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure that every Language that has an ISO 639-1 code is unique
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void LanguageNoDuplicateTwoLetterCodeTest()
|
||||
{
|
||||
var fullLanguages = Enum.GetValues(typeof(Language)).Cast<Language?>().ToList();
|
||||
var filteredLanguages = new Dictionary<string, Language?>();
|
||||
|
||||
int totalCount = 0;
|
||||
foreach (Language? language in fullLanguages)
|
||||
{
|
||||
string code = language.TwoLetterCode();
|
||||
if (string.IsNullOrWhiteSpace(code))
|
||||
continue;
|
||||
|
||||
// Throw if the code already exists
|
||||
if (filteredLanguages.ContainsKey(code))
|
||||
throw new DuplicateNameException($"Code {code} already in dictionary");
|
||||
|
||||
filteredLanguages[code] = language;
|
||||
totalCount++;
|
||||
}
|
||||
|
||||
Assert.Equal(totalCount, filteredLanguages.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure that every Language that has a standard/bibliographic ISO 639-2 code is unique
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void LanguageNoDuplicateThreeLetterCodeTest()
|
||||
{
|
||||
var fullLanguages = Enum.GetValues(typeof(Language)).Cast<Language?>().ToList();
|
||||
var filteredLanguages = new Dictionary<string, Language?>();
|
||||
|
||||
int totalCount = 0;
|
||||
foreach (Language? language in fullLanguages)
|
||||
{
|
||||
string code = language.ThreeLetterCode();
|
||||
if (string.IsNullOrWhiteSpace(code))
|
||||
continue;
|
||||
|
||||
// Throw if the code already exists
|
||||
if (filteredLanguages.ContainsKey(code))
|
||||
throw new DuplicateNameException($"Code {code} already in dictionary");
|
||||
|
||||
filteredLanguages[code] = language;
|
||||
totalCount++;
|
||||
}
|
||||
|
||||
Assert.Equal(totalCount, filteredLanguages.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure that every Language that has a terminology ISO 639-2 code is unique
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void LanguageNoDuplicateThreeLetterCodeAltTest()
|
||||
{
|
||||
var fullLanguages = Enum.GetValues(typeof(Language)).Cast<Language?>().ToList();
|
||||
var filteredLanguages = new Dictionary<string, Language?>();
|
||||
|
||||
int totalCount = 0;
|
||||
foreach (Language? language in fullLanguages)
|
||||
{
|
||||
string code = language.ThreeLetterCodeAlt();
|
||||
if (string.IsNullOrWhiteSpace(code))
|
||||
continue;
|
||||
|
||||
// Throw if the code already exists
|
||||
if (filteredLanguages.ContainsKey(code))
|
||||
throw new DuplicateNameException($"Code {code} already in dictionary");
|
||||
|
||||
filteredLanguages[code] = language;
|
||||
totalCount++;
|
||||
}
|
||||
|
||||
Assert.Equal(totalCount, filteredLanguages.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of Language values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of Language values</returns>
|
||||
public static List<object[]> GenerateLanguageTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
foreach (Language? language in Enum.GetValues(typeof(Language)))
|
||||
{
|
||||
testData.Add(new object[] { language, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Language Selection
|
||||
|
||||
/// <summary>
|
||||
/// Check that every LanguageSelection has a long name provided
|
||||
/// </summary>
|
||||
/// <param name="languageSelection">LanguageSelection value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateLanguageSelectionTestData))]
|
||||
public void LanguageSelectionLongNameTest(LanguageSelection? languageSelection, bool expectNull)
|
||||
{
|
||||
string actual = languageSelection.LongName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of LanguageSelection values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of LanguageSelection values</returns>
|
||||
public static List<object[]> GenerateLanguageSelectionTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
foreach (LanguageSelection? languageSelection in Enum.GetValues(typeof(LanguageSelection)))
|
||||
{
|
||||
testData.Add(new object[] { languageSelection, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Media Type
|
||||
|
||||
/// <summary>
|
||||
/// Check that every MediaType has a long name provided
|
||||
/// </summary>
|
||||
/// <param name="mediaType">MediaType value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateMediaTypeTestData))]
|
||||
public void MediaTypeLongNameTest(MediaType? mediaType, bool expectNull)
|
||||
{
|
||||
string actual = mediaType.LongName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that every MediaType has a short name provided
|
||||
/// </summary>
|
||||
/// <param name="mediaType">MediaType value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateMediaTypeTestData))]
|
||||
public void MediaTypeShortNameTest(MediaType? mediaType, bool expectNull)
|
||||
{
|
||||
string actual = mediaType.ShortName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of MediaType values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of MediaType values</returns>
|
||||
public static List<object[]> GenerateMediaTypeTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
foreach (MediaType? mediaType in Enum.GetValues(typeof(MediaType)))
|
||||
{
|
||||
testData.Add(new object[] { mediaType, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Region
|
||||
|
||||
/// <summary>
|
||||
/// Check that every Region has a long name provided
|
||||
/// </summary>
|
||||
/// <param name="region">Region value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateRegionTestData))]
|
||||
public void RegionLongNameTest(Region? region, bool expectNull)
|
||||
{
|
||||
string actual = region.LongName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that every Region has a short name provided
|
||||
/// </summary>
|
||||
/// <param name="region">Region value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateRegionTestData))]
|
||||
public void RegionShortNameTest(Region? region, bool expectNull)
|
||||
{
|
||||
string actual = region.ShortName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure that every Language that has an ISO 639-1 code is unique
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void RegionNoDuplicateShortNameTest()
|
||||
{
|
||||
var fullRegions = Enum.GetValues(typeof(Region)).Cast<Region?>().ToList();
|
||||
var filteredRegions = new Dictionary<string, Region?>();
|
||||
|
||||
int totalCount = 0;
|
||||
foreach (Region? region in fullRegions)
|
||||
{
|
||||
string code = region.ShortName();
|
||||
if (string.IsNullOrWhiteSpace(code))
|
||||
continue;
|
||||
|
||||
// Throw if the code already exists
|
||||
if (filteredRegions.ContainsKey(code))
|
||||
throw new DuplicateNameException($"Code {code} already in dictionary");
|
||||
|
||||
filteredRegions[code] = region;
|
||||
totalCount++;
|
||||
}
|
||||
|
||||
Assert.Equal(totalCount, filteredRegions.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of Region values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of Region values</returns>
|
||||
public static List<object[]> GenerateRegionTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
foreach (Region? region in Enum.GetValues(typeof(Region)))
|
||||
{
|
||||
testData.Add(new object[] { region, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Site Code
|
||||
|
||||
/// <summary>
|
||||
/// Check that every SiteCode has a long name provided
|
||||
/// </summary>
|
||||
/// <param name="siteCode">SiteCode value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateSiteCodeTestData))]
|
||||
public void SiteCodeLongNameTest(SiteCode? siteCode, bool expectNull)
|
||||
{
|
||||
string actual = siteCode.LongName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that every SiteCode has a short name provided
|
||||
/// </summary>
|
||||
/// <param name="siteCode">SiteCode value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateSiteCodeTestData))]
|
||||
public void SiteCodeShortNameTest(SiteCode? siteCode, bool expectNull)
|
||||
{
|
||||
string actual = siteCode.ShortName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of SiteCode values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of SiteCode values</returns>
|
||||
public static List<object[]> GenerateSiteCodeTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
foreach (SiteCode? siteCode in Enum.GetValues(typeof(SiteCode)))
|
||||
{
|
||||
testData.Add(new object[] { siteCode, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region System
|
||||
|
||||
/// <summary>
|
||||
/// RedumpSystem values that are considered markers and not real systems
|
||||
/// </summary>
|
||||
private static readonly RedumpSystem?[] _markerSystemTypes = new RedumpSystem?[]
|
||||
{
|
||||
RedumpSystem.MarkerArcadeEnd,
|
||||
RedumpSystem.MarkerComputerEnd,
|
||||
RedumpSystem.MarkerDiscBasedConsoleEnd,
|
||||
RedumpSystem.MarkerOtherEnd,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Check that every RedumpSystem has a long name provided
|
||||
/// </summary>
|
||||
/// <param name="redumpSystem">RedumpSystem value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateRedumpSystemTestData))]
|
||||
public void RedumpSystemLongNameTest(RedumpSystem? redumpSystem, bool expectNull)
|
||||
{
|
||||
string actual = redumpSystem.LongName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
// TODO: Re-enable the following test once non-Redump systems are accounted for
|
||||
|
||||
/// <summary>
|
||||
/// Check that every RedumpSystem has a short name provided
|
||||
/// </summary>
|
||||
/// <param name="redumpSystem">RedumpSystem value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
//[Theory]
|
||||
//[MemberData(nameof(GenerateRedumpSystemTestData))]
|
||||
//public void RedumpSystemShortNameTest(RedumpSystem? redumpSystem, bool expectNull)
|
||||
//{
|
||||
// string actual = redumpSystem.ShortName();
|
||||
|
||||
// if (expectNull)
|
||||
// Assert.Null(actual);
|
||||
// else
|
||||
// Assert.NotNull(actual);
|
||||
//}
|
||||
|
||||
// TODO: Test the other attributes as well
|
||||
// Most are bool checks so they're not as interesting to have unit tests around
|
||||
// SystemCategory always returns something as well, so is it worth testing?
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of RedumpSystem values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of RedumpSystem values</returns>
|
||||
public static List<object[]> GenerateRedumpSystemTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
foreach (RedumpSystem? redumpSystem in Enum.GetValues(typeof(RedumpSystem)))
|
||||
{
|
||||
// We want to skip all markers for this
|
||||
if (_markerSystemTypes.Contains(redumpSystem))
|
||||
continue;
|
||||
|
||||
testData.Add(new object[] { redumpSystem, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region System Category
|
||||
|
||||
/// <summary>
|
||||
/// Check that every SystemCategory has a long name provided
|
||||
/// </summary>
|
||||
/// <param name="systemCategory">SystemCategory value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateSystemCategoryTestData))]
|
||||
public void SystemCategoryLongNameTest(SystemCategory? systemCategory, bool expectNull)
|
||||
{
|
||||
string actual = systemCategory.LongName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of SystemCategory values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of SystemCategory values</returns>
|
||||
public static List<object[]> GenerateSystemCategoryTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, true } };
|
||||
foreach (SystemCategory? systemCategory in Enum.GetValues(typeof(SystemCategory)))
|
||||
{
|
||||
if (systemCategory == SystemCategory.NONE)
|
||||
testData.Add(new object[] { systemCategory, true });
|
||||
else
|
||||
testData.Add(new object[] { systemCategory, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Yes/No
|
||||
|
||||
/// <summary>
|
||||
/// Check that every YesNo has a long name provided
|
||||
/// </summary>
|
||||
/// <param name="yesNo">YesNo value to check</param>
|
||||
/// <param name="expectNull">True to expect a null value, false otherwise</param>
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateYesNoTestData))]
|
||||
public void YesNoLongNameTest(YesNo? yesNo, bool expectNull)
|
||||
{
|
||||
string actual = yesNo.LongName();
|
||||
|
||||
if (expectNull)
|
||||
Assert.Null(actual);
|
||||
else
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a test set of YesNo values
|
||||
/// </summary>
|
||||
/// <returns>MemberData-compatible list of YesNo values</returns>
|
||||
public static List<object[]> GenerateYesNoTestData()
|
||||
{
|
||||
var testData = new List<object[]>() { new object[] { null, false } };
|
||||
foreach (YesNo? yesNo in Enum.GetValues(typeof(YesNo)))
|
||||
{
|
||||
testData.Add(new object[] { yesNo, false });
|
||||
}
|
||||
|
||||
return testData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
169
MPF.Test/RedumpLib/SubmissionInfoTests.cs
Normal file
169
MPF.Test/RedumpLib/SubmissionInfoTests.cs
Normal file
@@ -0,0 +1,169 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using RedumpLib.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.RedumpLib
|
||||
{
|
||||
public class SubmissionInfoTests
|
||||
{
|
||||
[Fact]
|
||||
public void EmptySerializationTest()
|
||||
{
|
||||
var submissionInfo = new SubmissionInfo();
|
||||
string json = JsonConvert.SerializeObject(submissionInfo, Formatting.Indented);
|
||||
Assert.NotNull(json);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PartialSerializationTest()
|
||||
{
|
||||
var submissionInfo = new SubmissionInfo()
|
||||
{
|
||||
CommonDiscInfo = new CommonDiscInfoSection(),
|
||||
VersionAndEditions = new VersionAndEditionsSection(),
|
||||
EDC = new EDCSection(),
|
||||
ParentCloneRelationship = new ParentCloneRelationshipSection(),
|
||||
Extras = new ExtrasSection(),
|
||||
CopyProtection = new CopyProtectionSection(),
|
||||
DumpersAndStatus = new DumpersAndStatusSection(),
|
||||
TracksAndWriteOffsets = new TracksAndWriteOffsetsSection(),
|
||||
SizeAndChecksums = new SizeAndChecksumsSection(),
|
||||
};
|
||||
|
||||
string json = JsonConvert.SerializeObject(submissionInfo, Formatting.Indented);
|
||||
Assert.NotNull(json);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FullSerializationTest()
|
||||
{
|
||||
var submissionInfo = new SubmissionInfo()
|
||||
{
|
||||
SchemaVersion = 1,
|
||||
MatchedIDs = new List<int> { 0, 1, 2, 3 },
|
||||
Added = DateTime.UtcNow,
|
||||
LastModified = DateTime.UtcNow,
|
||||
|
||||
CommonDiscInfo = new CommonDiscInfoSection()
|
||||
{
|
||||
System = RedumpSystem.IBMPCcompatible,
|
||||
Media = DiscType.CD,
|
||||
Title = "Game Title",
|
||||
ForeignTitleNonLatin = "Foreign Game Title",
|
||||
DiscNumberLetter = "1",
|
||||
DiscTitle = "Install Disc",
|
||||
Category = DiscCategory.Games,
|
||||
Region = Region.World,
|
||||
Languages = new Language?[] { Language.English, Language.Spanish, Language.French },
|
||||
LanguageSelection = new LanguageSelection?[] { LanguageSelection.BiosSettings },
|
||||
Serial = "Disc Serial",
|
||||
Layer0MasteringRing = "L0 Mastering Ring",
|
||||
Layer0MasteringSID = "L0 Mastering SID",
|
||||
Layer0ToolstampMasteringCode = "L0 Toolstamp",
|
||||
Layer0MouldSID = "L0 Mould SID",
|
||||
Layer0AdditionalMould = "L0 Additional Mould",
|
||||
Layer1MasteringRing = "L1 Mastering Ring",
|
||||
Layer1MasteringSID = "L1 Mastering SID",
|
||||
Layer1ToolstampMasteringCode = "L1 Toolstamp",
|
||||
Layer1MouldSID = "L1 Mould SID",
|
||||
Layer1AdditionalMould = "L1 Additional Mould",
|
||||
Layer2MasteringRing = "L2 Mastering Ring",
|
||||
Layer2MasteringSID = "L2 Mastering SID",
|
||||
Layer2ToolstampMasteringCode = "L2 Toolstamp",
|
||||
Layer3MasteringRing = "L3 Mastering Ring",
|
||||
Layer3MasteringSID = "L3 Mastering SID",
|
||||
Layer3ToolstampMasteringCode = "L3 Toolstamp",
|
||||
RingWriteOffset = "+12",
|
||||
Barcode = "UPC Barcode",
|
||||
EXEDateBuildDate = "19xx-xx-xx",
|
||||
ErrorsCount = "0",
|
||||
Comments = "Comment data line 1\r\nComment data line 2",
|
||||
CommentsSpecialFields = new Dictionary<SiteCode?, string>()
|
||||
{
|
||||
[SiteCode.ISBN] = "ISBN",
|
||||
},
|
||||
Contents = "Special contents 1\r\nSpecial contents 2",
|
||||
ContentsSpecialFields = new Dictionary<SiteCode?, string>()
|
||||
{
|
||||
[SiteCode.PlayableDemos] = "Game Demo 1",
|
||||
},
|
||||
},
|
||||
|
||||
VersionAndEditions = new VersionAndEditionsSection()
|
||||
{
|
||||
Version = "Original",
|
||||
VersionDatfile = "Alt",
|
||||
CommonEditions = new string[] { "Taikenban" },
|
||||
OtherEditions = "Rerelease",
|
||||
},
|
||||
|
||||
EDC = new EDCSection()
|
||||
{
|
||||
EDC = YesNo.Yes,
|
||||
},
|
||||
|
||||
ParentCloneRelationship = new ParentCloneRelationshipSection()
|
||||
{
|
||||
ParentID = "12345",
|
||||
RegionalParent = false,
|
||||
},
|
||||
|
||||
Extras = new ExtrasSection()
|
||||
{
|
||||
PVD = "PVD",
|
||||
DiscKey = "Disc key",
|
||||
DiscID = "Disc ID",
|
||||
PIC = "PIC",
|
||||
Header = "Header",
|
||||
BCA = "BCA",
|
||||
SecuritySectorRanges = "SSv1 Ranges",
|
||||
},
|
||||
|
||||
CopyProtection = new CopyProtectionSection()
|
||||
{
|
||||
AntiModchip = YesNo.Yes,
|
||||
LibCrypt = YesNo.No,
|
||||
LibCryptData = "LibCrypt data",
|
||||
Protection = "List of protections",
|
||||
SecuROMData = "SecuROM data",
|
||||
},
|
||||
|
||||
DumpersAndStatus = new DumpersAndStatusSection()
|
||||
{
|
||||
Status = DumpStatus.TwoOrMoHumanReadablesGreen,
|
||||
Dumpers = new string[] { "Dumper1", "Dumper2" },
|
||||
OtherDumpers = "Dumper3",
|
||||
},
|
||||
|
||||
TracksAndWriteOffsets = new TracksAndWriteOffsetsSection()
|
||||
{
|
||||
ClrMameProData = "Datfile",
|
||||
Cuesheet = "Cuesheet",
|
||||
CommonWriteOffsets = new int[] { 0, 12, -12 },
|
||||
OtherWriteOffsets = "-2",
|
||||
},
|
||||
|
||||
SizeAndChecksums = new SizeAndChecksumsSection()
|
||||
{
|
||||
Layerbreak = 0,
|
||||
Layerbreak2 = 1,
|
||||
Layerbreak3 = 2,
|
||||
Size = 12345,
|
||||
CRC32 = "CRC32",
|
||||
MD5 = "MD5",
|
||||
SHA1 = "SHA1",
|
||||
},
|
||||
|
||||
Artifacts = new Dictionary<string, string>()
|
||||
{
|
||||
["Sample Artifact"] = "Sample Data",
|
||||
},
|
||||
};
|
||||
|
||||
string json = JsonConvert.SerializeObject(submissionInfo, Formatting.Indented);
|
||||
Assert.NotNull(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using MPF.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test
|
||||
{
|
||||
public class ResultTest
|
||||
{
|
||||
[Fact]
|
||||
public void ResultSuccessTest()
|
||||
{
|
||||
Result actual = Result.Success();
|
||||
Assert.Empty(actual.Message);
|
||||
|
||||
string message = "Success!";
|
||||
actual = Result.Success(message);
|
||||
Assert.Equal(message, actual.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResultFailureTest()
|
||||
{
|
||||
Result actual = Result.Failure();
|
||||
Assert.Empty(actual.Message);
|
||||
|
||||
string message = "Failure!";
|
||||
actual = Result.Failure(message);
|
||||
Assert.Equal(message, actual.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Linq;
|
||||
using MPF.Data;
|
||||
using MPF.Core.Data;
|
||||
using RedumpLib.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Data
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MPF.Data;
|
||||
using MPF.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Utilities
|
||||
{
|
||||
public class ConvertersTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Set of all known systems for testing
|
||||
/// </summary>
|
||||
public static IEnumerable<object[]> KnownSystems = KnownSystemComboBoxItem.GenerateElements().Select(e => new object[] { e });
|
||||
|
||||
[Theory]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Audio, MediaType.CDROM)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.BluRay, MediaType.BluRay)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Close, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.CompactDisc, MediaType.CDROM)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Data, MediaType.CDROM)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.DigitalVideoDisc, MediaType.DVD)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Eject, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Floppy, MediaType.FloppyDisk)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.GDROM, MediaType.GDROM)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.MDS, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Reset, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.SACD, MediaType.CDROM)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Start, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Stop, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Sub, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Swap, MediaType.GDROM)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.XBOX, MediaType.DVD)]
|
||||
public void BaseCommandToMediaTypeTest(string command, MediaType? expected)
|
||||
{
|
||||
MediaType? actual = DiscImageCreator.Converters.ToMediaType(command);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Audio, KnownSystem.AudioCD)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.BluRay, KnownSystem.SonyPlayStation3)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Close, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.CompactDisc, KnownSystem.IBMPCCompatible)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Data, KnownSystem.IBMPCCompatible)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.DigitalVideoDisc, KnownSystem.IBMPCCompatible)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Eject, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Floppy, KnownSystem.IBMPCCompatible)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.GDROM, KnownSystem.SegaDreamcast)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.MDS, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Reset, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.SACD, KnownSystem.SuperAudioCD)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Start, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Stop, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Sub, null)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.Swap, KnownSystem.SegaDreamcast)]
|
||||
[InlineData(DiscImageCreator.CommandStrings.XBOX, KnownSystem.MicrosoftXBOX)]
|
||||
public void BaseCommandToKnownSystemTest(string command, KnownSystem? expected)
|
||||
{
|
||||
KnownSystem? actual = DiscImageCreator.Converters.ToKnownSystem(command);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(MediaType.CDROM, ".bin")]
|
||||
[InlineData(MediaType.DVD, ".iso")]
|
||||
[InlineData(MediaType.LaserDisc, ".raw")]
|
||||
[InlineData(MediaType.NintendoWiiUOpticalDisc, ".wud")]
|
||||
[InlineData(MediaType.FloppyDisk, ".img")]
|
||||
[InlineData(MediaType.Cassette, ".wav")]
|
||||
[InlineData(MediaType.NONE, null)]
|
||||
public void MediaTypeToExtensionTest(MediaType? mediaType, string expected)
|
||||
{
|
||||
string actual = DiscImageCreator.Converters.Extension(mediaType);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(MediaType.CDROM, "CD-ROM")]
|
||||
[InlineData(MediaType.LaserDisc, "LD-ROM / LV-ROM")]
|
||||
[InlineData(MediaType.NONE, "Unknown")]
|
||||
public void MediaTypeToStringTest(MediaType? mediaType, string expected)
|
||||
{
|
||||
string actual = Converters.LongName(mediaType);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(KnownSystem.MicrosoftXBOX, "Microsoft XBOX")]
|
||||
[InlineData(KnownSystem.NECPC88, "NEC PC-88")]
|
||||
[InlineData(KnownSystem.KonamiPython, "Konami Python")]
|
||||
[InlineData(KnownSystem.HDDVDVideo, "HD-DVD-Video")]
|
||||
[InlineData(KnownSystem.NONE, "Unknown")]
|
||||
public void KnownSystemToStringTest(KnownSystem? knownSystem, string expected)
|
||||
{
|
||||
string actual = Converters.LongName(knownSystem);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(KnownSystems))]
|
||||
public void KnownSystemHasValidCategory(KnownSystemComboBoxItem system)
|
||||
{
|
||||
KnownSystem[] markers = { KnownSystem.MarkerArcadeEnd, KnownSystem.MarkerDiscBasedConsoleEnd, /* KnownSystem.MarkerOtherConsoleEnd, */ KnownSystem.MarkerComputerEnd, KnownSystem.MarkerOtherEnd };
|
||||
|
||||
// Non-system items won't map
|
||||
if (system.IsHeader)
|
||||
return;
|
||||
|
||||
// NONE will never map
|
||||
if (system == KnownSystem.NONE)
|
||||
return;
|
||||
|
||||
// we check that the category is the first category value higher than the system
|
||||
KnownSystemCategory category = ((KnownSystem?)system).Category();
|
||||
KnownSystem marker = KnownSystem.NONE;
|
||||
|
||||
switch (category)
|
||||
{
|
||||
case KnownSystemCategory.Arcade: marker = KnownSystem.MarkerArcadeEnd; break;
|
||||
case KnownSystemCategory.DiscBasedConsole: marker = KnownSystem.MarkerDiscBasedConsoleEnd; break;
|
||||
/* case KnownSystemCategory.OtherConsole: marker = KnownSystem.MarkerOtherConsoleEnd; break; */
|
||||
case KnownSystemCategory.Computer: marker = KnownSystem.MarkerComputerEnd; break;
|
||||
case KnownSystemCategory.Other: marker = KnownSystem.MarkerOtherEnd; break;
|
||||
}
|
||||
|
||||
Assert.NotEqual(KnownSystem.NONE, marker);
|
||||
Assert.True(marker > system);
|
||||
|
||||
Array.ForEach(markers, mmarker =>
|
||||
{
|
||||
// a marker can be the same of the found one, or one of a category before or a category after but never in the middle between
|
||||
// the system and the mapped category
|
||||
Assert.True(mmarker == marker || mmarker < system || mmarker > marker);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
using System.IO;
|
||||
using MPF.Data;
|
||||
using MPF.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test
|
||||
{
|
||||
public class DumpEnvironmentTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(null, 'D', false, MediaType.NONE, false)]
|
||||
[InlineData("", 'D', false, MediaType.NONE, false)]
|
||||
[InlineData("cd F test.bin 8 /c2 20", 'F', false, MediaType.CDROM, true)]
|
||||
[InlineData("fd A test.img", 'A', true, MediaType.FloppyDisk, true)]
|
||||
[InlineData("dvd X test.iso 8 /raw", 'X', false, MediaType.FloppyDisk, false)]
|
||||
[InlineData("stop D", 'D', false, MediaType.DVD, true)]
|
||||
public void ParametersValidTest(string parameters, char letter, bool isFloppy, MediaType? mediaType, bool expected)
|
||||
{
|
||||
var options = new Options() { InternalProgram = InternalProgram.DiscImageCreator };
|
||||
var drive = isFloppy
|
||||
? new Drive(InternalDriveType.Floppy, new DriveInfo(letter.ToString()))
|
||||
: new Drive(InternalDriveType.Optical, new DriveInfo(letter.ToString()));
|
||||
|
||||
var env = new DumpEnvironment(options, string.Empty, string.Empty, drive, KnownSystem.IBMPCCompatible, mediaType, parameters);
|
||||
|
||||
bool actual = env.ParametersValid();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null, null, null)]
|
||||
[InlineData(" ", "", " ", "")]
|
||||
[InlineData("super", "blah.bin", "super", "blah.bin")]
|
||||
[InlineData("super\\hero", "blah.bin", "super\\hero", "blah.bin")]
|
||||
[InlineData("super.hero", "blah.bin", "super.hero", "blah.bin")]
|
||||
[InlineData("superhero", "blah.rev.bin", "superhero", "blah.rev.bin")]
|
||||
[InlineData("super&hero", "blah.bin", "super&hero", "blah.bin")]
|
||||
[InlineData("superhero", "blah&foo.bin", "superhero", "blah&foo.bin")]
|
||||
public void FixOutputPathsTest(string outputDirectory, string outputFilename, string expectedOutputDirectory, string expectedOutputFilename)
|
||||
{
|
||||
(string actualOutputDirectory, string actualOutputFilename) = DumpEnvironment.NormalizeOutputPaths(outputDirectory, outputFilename, false);
|
||||
Assert.Equal(expectedOutputDirectory, actualOutputDirectory);
|
||||
Assert.Equal(expectedOutputFilename, actualOutputFilename);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFirstTrackTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatOutputDataTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteOutputDataTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EjectDiscTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CancelDumpingTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StartDumpingTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
using System;
|
||||
using MPF.Data;
|
||||
using MPF.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Utilities
|
||||
{
|
||||
public class KnownSystemExtensionsTest
|
||||
{
|
||||
[Fact]
|
||||
public void IsMarkerTest()
|
||||
{
|
||||
var values = (KnownSystem[])Enum.GetValues(typeof(KnownSystem));
|
||||
foreach(var system in values)
|
||||
{
|
||||
bool expected = system == KnownSystem.MarkerArcadeEnd || system == KnownSystem.MarkerComputerEnd ||
|
||||
system == KnownSystem.MarkerOtherEnd || system == KnownSystem.MarkerDiscBasedConsoleEnd;
|
||||
// || system == KnownSystem.MarkerOtherConsoleEnd;
|
||||
|
||||
bool actual = ((KnownSystem?)system).IsMarker();
|
||||
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CategoryNameNotEmptyTest()
|
||||
{
|
||||
var values = (KnownSystemCategory[])Enum.GetValues(typeof(KnownSystemCategory));
|
||||
foreach (var system in values)
|
||||
{
|
||||
string actual = ((KnownSystem?)system).LongName();
|
||||
Assert.NotEqual("", actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
using MPF.Data;
|
||||
using MPF.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Utilities
|
||||
{
|
||||
public class MediaTypeExtensionsTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(MediaType.CDROM, "CD-ROM")]
|
||||
[InlineData(MediaType.LaserDisc, "LD-ROM / LV-ROM")]
|
||||
[InlineData(MediaType.NONE, "Unknown")]
|
||||
public void NameTest(MediaType? mediaType, string expected)
|
||||
{
|
||||
string actual = mediaType.LongName();
|
||||
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(MediaType.CDROM, ".bin")]
|
||||
[InlineData(MediaType.DVD, ".iso")]
|
||||
[InlineData(MediaType.LaserDisc, ".raw")]
|
||||
[InlineData(MediaType.FloppyDisk, ".img")]
|
||||
[InlineData(MediaType.NONE, null)]
|
||||
public void ExtensionTest(MediaType? mediaType, string expected)
|
||||
{
|
||||
string actual = DiscImageCreator.Converters.Extension(mediaType);
|
||||
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(MediaType.CDROM, true)]
|
||||
[InlineData(MediaType.DVD, true)]
|
||||
[InlineData(MediaType.FloppyDisk, false)]
|
||||
[InlineData(MediaType.BluRay, true)]
|
||||
[InlineData(MediaType.LaserDisc, false)]
|
||||
public void DriveSpeedSupportedTest(MediaType? mediaType, bool expected)
|
||||
{
|
||||
bool actual = mediaType.DoesSupportDriveSpeed();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MPF.Data;
|
||||
using MPF.DiscImageCreator;
|
||||
using MPF.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Utilities
|
||||
{
|
||||
public class ParametersTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(KnownSystem.MicrosoftXBOX, MediaType.CDROM, CommandStrings.CompactDisc)]
|
||||
[InlineData(KnownSystem.MicrosoftXBOX, MediaType.DVD, CommandStrings.XBOX)]
|
||||
[InlineData(KnownSystem.MicrosoftXBOX, MediaType.LaserDisc, null)]
|
||||
[InlineData(KnownSystem.SegaNu, MediaType.BluRay, CommandStrings.BluRay)]
|
||||
[InlineData(KnownSystem.AppleMacintosh, MediaType.FloppyDisk, CommandStrings.Floppy)]
|
||||
[InlineData(KnownSystem.RawThrillsVarious, MediaType.GDROM, null)]
|
||||
public void ParametersFromSystemAndTypeTest(KnownSystem? knownSystem, MediaType? mediaType, string expected)
|
||||
{
|
||||
var options = new Options { };
|
||||
var actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, options);
|
||||
Assert.Equal(expected, actual.BaseCommand);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(KnownSystem.AppleMacintosh, MediaType.LaserDisc, true, 20, null, null)]
|
||||
[InlineData(KnownSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc, false, 20, null, new string[] { FlagStrings.Raw })]
|
||||
[InlineData(KnownSystem.IBMPCCompatible, MediaType.DVD, false, 20, null, new string[] { FlagStrings.CopyrightManagementInformation, FlagStrings.ScanFileProtect })]
|
||||
/* paranoid mode tests */
|
||||
[InlineData(KnownSystem.IBMPCCompatible, MediaType.CDROM, true, 1000, 2, new string[] { FlagStrings.C2Opcode, FlagStrings.NoFixSubQSecuROM, FlagStrings.ScanFileProtect, FlagStrings.ScanSectorProtect, FlagStrings.SubchannelReadLevel })]
|
||||
[InlineData(KnownSystem.AppleMacintosh, MediaType.CDROM, false, 20, null, new string[] { FlagStrings.C2Opcode, FlagStrings.NoFixSubQSecuROM, FlagStrings.ScanFileProtect, FlagStrings.ScanSectorProtect, FlagStrings.SubchannelReadLevel })]
|
||||
[InlineData(KnownSystem.IBMPCCompatible, MediaType.DVD, true, 500, null, new string[] { FlagStrings.CopyrightManagementInformation, FlagStrings.ScanFileProtect })]
|
||||
[InlineData(KnownSystem.HDDVDVideo, MediaType.HDDVD, true, 500, null, new string[] { FlagStrings.CopyrightManagementInformation })]
|
||||
[InlineData(KnownSystem.IBMPCCompatible, MediaType.DVD, false, 500, null, new string[] { FlagStrings.CopyrightManagementInformation, FlagStrings.ScanFileProtect })]
|
||||
[InlineData(KnownSystem.HDDVDVideo, MediaType.HDDVD, false, 500, null, new string[] { FlagStrings.CopyrightManagementInformation })]
|
||||
/* reread c2 */
|
||||
[InlineData(KnownSystem.SegaDreamcast, MediaType.GDROM, false, 1000, null, new string[] { FlagStrings.C2Opcode })]
|
||||
[InlineData(KnownSystem.SegaDreamcast, MediaType.GDROM, false, -1, null, new string[] { FlagStrings.C2Opcode })]
|
||||
|
||||
public void ParametersFromOptionsTest(KnownSystem? knownSystem, MediaType? mediaType, bool paranoid, int rereadC2, int? subchannelLevel, string[] expected)
|
||||
{
|
||||
var options = new Options { DICParanoidMode = paranoid, DICRereadCount = rereadC2 };
|
||||
var actual = new Parameters(knownSystem, mediaType, 'D', "disc.bin", 16, options);
|
||||
|
||||
HashSet<string> expectedSet = new HashSet<string>(expected ?? new string[0]);
|
||||
HashSet<string> actualSet = new HashSet<string>(actual.Keys.Cast<string>() ?? new string[0]);
|
||||
Assert.Equal(expectedSet, actualSet);
|
||||
if (rereadC2 == -1 || !Validators.GetValidMediaTypes(knownSystem).Contains(mediaType))
|
||||
Assert.Null(actual.C2OpcodeValue[0]);
|
||||
else
|
||||
Assert.Equal(rereadC2, actual.C2OpcodeValue[0]);
|
||||
Assert.Equal(subchannelLevel, actual.SubchannelReadLevelValue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, false)]
|
||||
[InlineData("", false)]
|
||||
[InlineData("cd F test.bin 8 /c2 20", true)]
|
||||
[InlineData("fd A test.img", true)]
|
||||
[InlineData("dvd X super\\test.iso 8 /raw", true)]
|
||||
[InlineData("bd D longer\\path_test.iso 16", true)]
|
||||
[InlineData("stop D", true)]
|
||||
[InlineData("ls", false)]
|
||||
public void ValidateParametersTest(string parameters, bool expected)
|
||||
{
|
||||
var actual = new Parameters(parameters);
|
||||
Assert.Equal(expected, actual.IsValid());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using MPF.Data;
|
||||
using MPF.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace MPF.Test.Utilities
|
||||
{
|
||||
public class ValidatorsTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(KnownSystem.BandaiApplePippin, MediaType.CDROM)]
|
||||
[InlineData(KnownSystem.MicrosoftXBOX, MediaType.DVD)]
|
||||
[InlineData(KnownSystem.NintendoGameCube, MediaType.NintendoGameCubeGameDisc)]
|
||||
[InlineData(KnownSystem.NintendoWii, MediaType.NintendoWiiOpticalDisc)]
|
||||
[InlineData(KnownSystem.NintendoWiiU, MediaType.NintendoWiiUOpticalDisc)]
|
||||
[InlineData(KnownSystem.SonyPlayStationPortable, MediaType.UMD)]
|
||||
public void GetValidMediaTypesTest(KnownSystem? knownSystem, MediaType? expected)
|
||||
{
|
||||
var actual = Validators.GetValidMediaTypes(knownSystem);
|
||||
Assert.Contains(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateListOfSystemsTest()
|
||||
{
|
||||
int expected = Enum.GetValues(typeof(KnownSystem)).Length;
|
||||
var actual = KnownSystemComboBoxItem.GenerateElements().ToList();
|
||||
Assert.Equal(expected, actual.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateListOfDrivesTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDiscTypeTest()
|
||||
{
|
||||
// TODO: Implement
|
||||
Assert.True(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
30
MPF.sln
30
MPF.sln
@@ -18,6 +18,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RedumpLib", "RedumpLib\RedumpLib.csproj", "{13574913-A426-4644-9955-F49AD0876E5F}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MPF.CueSheets", "MPF.CueSheets\MPF.CueSheets.csproj", "{F2C12798-DF53-4D4C-A55B-F5A77F29D6B1}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CICMMetadataEditor", "CICMMetadata\CICMMetadataEditor\CICMMetadataEditor\CICMMetadataEditor.csproj", "{E4271454-6217-4500-BC36-F8856AC7AD6B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MPF.Core", "MPF.Core\MPF.Core.csproj", "{70B1265D-FE49-472A-A83D-0B462152D37A}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MPF.Modules", "MPF.Modules\MPF.Modules.csproj", "{8A4254BD-552F-4238-B8EB-D59AACD768B9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -40,6 +50,26 @@ Global
|
||||
{8CFDE289-E171-4D49-A40D-5293265C1253}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8CFDE289-E171-4D49-A40D-5293265C1253}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8CFDE289-E171-4D49-A40D-5293265C1253}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{13574913-A426-4644-9955-F49AD0876E5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{13574913-A426-4644-9955-F49AD0876E5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{13574913-A426-4644-9955-F49AD0876E5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{13574913-A426-4644-9955-F49AD0876E5F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F2C12798-DF53-4D4C-A55B-F5A77F29D6B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F2C12798-DF53-4D4C-A55B-F5A77F29D6B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F2C12798-DF53-4D4C-A55B-F5A77F29D6B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F2C12798-DF53-4D4C-A55B-F5A77F29D6B1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E4271454-6217-4500-BC36-F8856AC7AD6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E4271454-6217-4500-BC36-F8856AC7AD6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E4271454-6217-4500-BC36-F8856AC7AD6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E4271454-6217-4500-BC36-F8856AC7AD6B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{70B1265D-FE49-472A-A83D-0B462152D37A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{70B1265D-FE49-472A-A83D-0B462152D37A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{70B1265D-FE49-472A-A83D-0B462152D37A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{70B1265D-FE49-472A-A83D-0B462152D37A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8A4254BD-552F-4238-B8EB-D59AACD768B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8A4254BD-552F-4238-B8EB-D59AACD768B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8A4254BD-552F-4238-B8EB-D59AACD768B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8A4254BD-552F-4238-B8EB-D59AACD768B9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
14
MPF/App.xaml
14
MPF/App.xaml
@@ -1,9 +1,13 @@
|
||||
<Application
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:MPF"
|
||||
xmlns:Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero" x:Class="MPF.App"
|
||||
StartupUri="Windows\MainWindow.xaml">
|
||||
xmlns:Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
|
||||
xmlns:windows="clr-namespace:MPF.Windows"
|
||||
x:Class="MPF.App">
|
||||
<Application.MainWindow>
|
||||
<windows:MainWindow Visibility="Visible"/>
|
||||
</Application.MainWindow>
|
||||
|
||||
<Application.Resources>
|
||||
|
||||
<!-- Button -->
|
||||
@@ -53,7 +57,7 @@
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
|
||||
<!-- ComboBox -->
|
||||
<Style x:Key="FocusVisual">
|
||||
<Setter Property="Control.Template">
|
||||
@@ -569,7 +573,7 @@
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
|
||||
<!-- TabItem -->
|
||||
<LinearGradientBrush x:Key="TabItem.Static.Background" EndPoint="0,1" StartPoint="0,0">
|
||||
<GradientStop Color="#F0F0F0" Offset="0.0"/>
|
||||
|
||||
@@ -1,11 +1,60 @@
|
||||
using System.Windows;
|
||||
using MPF.Core.Data;
|
||||
using MPF.GUI.ViewModels;
|
||||
using MPF.Windows;
|
||||
|
||||
namespace MPF
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This application is not fully MVVM. The following steps are needed to get there:
|
||||
/// - Use commands instead of event handlers, where at all possible
|
||||
/// - Reduce the amount of manual UI adjustments needed, instead binding to the view models
|
||||
/// </remarks>
|
||||
public partial class App : Application
|
||||
{
|
||||
/// <summary>
|
||||
/// Static application instance for reference
|
||||
/// </summary>
|
||||
private static App _appInstance;
|
||||
|
||||
/// <summary>
|
||||
/// Read-only access to the current main window
|
||||
/// </summary>
|
||||
public static MainWindow Instance => _appInstance.MainWindow as MainWindow;
|
||||
|
||||
/// <summary>
|
||||
/// Read-only access to the current log window
|
||||
/// </summary>
|
||||
public static LogViewModel Logger => Instance.LogOutput.LogViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// Access to the current options
|
||||
/// </summary>
|
||||
public static Options Options
|
||||
{
|
||||
get => _options;
|
||||
set
|
||||
{
|
||||
_options = value;
|
||||
OptionsLoader.SaveToConfig(_options);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal reference to Options
|
||||
/// </summary>
|
||||
private static Options _options;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public App()
|
||||
{
|
||||
_appInstance = this;
|
||||
_options = OptionsLoader.LoadFromConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MPF.Utilities;
|
||||
using MPF.Core.Converters;
|
||||
|
||||
namespace MPF
|
||||
{
|
||||
@@ -22,7 +22,7 @@ namespace MPF
|
||||
public static implicit operator T? (Element<T> item) => item?.Data;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => Converters.GetLongName(Data);
|
||||
public string Name => EnumConverter.GetLongName(Data);
|
||||
|
||||
public override string ToString() => Name;
|
||||
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MPF.Data;
|
||||
using MPF.Utilities;
|
||||
using MPF.Core.Converters;
|
||||
using MPF.Core.Utilities;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single item in the System combo box
|
||||
/// </summary>
|
||||
public class KnownSystemComboBoxItem : IElement
|
||||
public class RedumpSystemComboBoxItem : IElement
|
||||
{
|
||||
private readonly object Data;
|
||||
|
||||
public KnownSystemComboBoxItem(KnownSystem? system) => Data = system;
|
||||
public KnownSystemComboBoxItem(KnownSystemCategory? category) => Data = category;
|
||||
public RedumpSystemComboBoxItem(RedumpSystem? system) => Data = system;
|
||||
public RedumpSystemComboBoxItem(SystemCategory? category) => Data = category;
|
||||
|
||||
public static implicit operator KnownSystem?(KnownSystemComboBoxItem item) => item.Data as KnownSystem?;
|
||||
public static implicit operator RedumpSystem?(RedumpSystemComboBoxItem item) => item.Data as RedumpSystem?;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name
|
||||
@@ -24,9 +25,9 @@ namespace MPF
|
||||
get
|
||||
{
|
||||
if (IsHeader)
|
||||
return "---------- " + Converters.GetLongName(Data as KnownSystemCategory?) + " ----------";
|
||||
return "---------- " + (Data as SystemCategory?).LongName() + " ----------";
|
||||
else
|
||||
return Converters.GetLongName(Data as KnownSystem?);
|
||||
return (Data as RedumpSystem?).LongName() ?? "No system selected";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,31 +36,31 @@ namespace MPF
|
||||
/// <summary>
|
||||
/// Internal enum value
|
||||
/// </summary>
|
||||
public KnownSystem? Value => Data as KnownSystem?;
|
||||
public RedumpSystem? Value => Data as RedumpSystem?;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the item is a header value
|
||||
/// </summary>
|
||||
public bool IsHeader => Data is KnownSystemCategory?;
|
||||
public bool IsHeader => Data is SystemCategory?;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the item is a standard system value
|
||||
/// </summary>
|
||||
public bool IsSystem => Data is KnownSystem?;
|
||||
public bool IsSystem => Data is RedumpSystem?;
|
||||
|
||||
/// <summary>
|
||||
/// Generate all elements for the known system combo box
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<KnownSystemComboBoxItem> GenerateElements()
|
||||
public static IEnumerable<RedumpSystemComboBoxItem> GenerateElements()
|
||||
{
|
||||
var knownSystems = Enum.GetValues(typeof(KnownSystem))
|
||||
.OfType<KnownSystem?>()
|
||||
.Where(s => !s.IsMarker() && s != KnownSystem.NONE)
|
||||
var knownSystems = Enum.GetValues(typeof(RedumpSystem))
|
||||
.OfType<RedumpSystem?>()
|
||||
.Where(s => !s.IsMarker() && s.GetCategory() != SystemCategory.NONE)
|
||||
.ToList();
|
||||
|
||||
Dictionary<KnownSystemCategory, List<KnownSystem?>> mapping = knownSystems
|
||||
.GroupBy(s => s.Category())
|
||||
Dictionary<SystemCategory, List<RedumpSystem?>> mapping = knownSystems
|
||||
.GroupBy(s => s.GetCategory())
|
||||
.ToDictionary(
|
||||
k => k.Key,
|
||||
v => v
|
||||
@@ -67,15 +68,15 @@ namespace MPF
|
||||
.ToList()
|
||||
);
|
||||
|
||||
var systemsValues = new List<KnownSystemComboBoxItem>
|
||||
var systemsValues = new List<RedumpSystemComboBoxItem>
|
||||
{
|
||||
new KnownSystemComboBoxItem(KnownSystem.NONE),
|
||||
new RedumpSystemComboBoxItem((RedumpSystem?)null),
|
||||
};
|
||||
|
||||
foreach (var group in mapping)
|
||||
{
|
||||
systemsValues.Add(new KnownSystemComboBoxItem(group.Key));
|
||||
group.Value.ForEach(system => systemsValues.Add(new KnownSystemComboBoxItem(system)));
|
||||
systemsValues.Add(new RedumpSystemComboBoxItem(group.Key));
|
||||
group.Value.ForEach(system => systemsValues.Add(new RedumpSystemComboBoxItem(system)));
|
||||
}
|
||||
|
||||
return systemsValues;
|
||||
|
||||
@@ -11,14 +11,14 @@ namespace MPF
|
||||
public static class Constants
|
||||
{
|
||||
// Private lists of known drive speed ranges
|
||||
private static IReadOnlyList<int> cd { get; } = new List<int> { 1, 2, 3, 4, 6, 8, 12, 16, 20, 24, 32, 40, 44, 48, 52, 56, 72 };
|
||||
private static IReadOnlyList<int> dvd { get; } = cd.Where(s => s <= 24).ToList();
|
||||
private static IReadOnlyList<int> bd { get; } = cd.Where(s => s <= 16).ToList();
|
||||
private static IReadOnlyList<int> CD { get; } = new List<int> { 1, 2, 3, 4, 6, 8, 12, 16, 20, 24, 32, 40, 44, 48, 52, 56, 72 };
|
||||
private static IReadOnlyList<int> DVD { get; } = CD.Where(s => s <= 24).ToList();
|
||||
private static IReadOnlyList<int> BD { get; } = CD.Where(s => s <= 16).ToList();
|
||||
|
||||
// Create collections for UI based on known drive speeds
|
||||
public static DoubleCollection SpeedsForCDAsCollection { get; } = GetDoubleCollectionFromIntList(cd);
|
||||
public static DoubleCollection SpeedsForDVDAsCollection { get; } = GetDoubleCollectionFromIntList(dvd);
|
||||
public static DoubleCollection SpeedsForBDAsCollection { get; } = GetDoubleCollectionFromIntList(bd);
|
||||
public static DoubleCollection SpeedsForCDAsCollection { get; } = GetDoubleCollectionFromIntList(CD);
|
||||
public static DoubleCollection SpeedsForDVDAsCollection { get; } = GetDoubleCollectionFromIntList(DVD);
|
||||
public static DoubleCollection SpeedsForBDAsCollection { get; } = GetDoubleCollectionFromIntList(BD);
|
||||
private static DoubleCollection GetDoubleCollectionFromIntList(IReadOnlyList<int> list)
|
||||
=> new DoubleCollection(list.Select(i => Convert.ToDouble(i)).ToList());
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 423 KiB After Width: | Height: | Size: 423 KiB |
BIN
MPF/Images/ring-code-guide-2-layer.png
Normal file
BIN
MPF/Images/ring-code-guide-2-layer.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net48;netcoreapp3.1</TargetFrameworks>
|
||||
<TargetFrameworks>net48;netcoreapp3.1;net5.0-windows</TargetFrameworks>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
@@ -13,7 +13,7 @@
|
||||
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
|
||||
<Copyright>Copyright (c)2019-2021</Copyright>
|
||||
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
|
||||
<Version>2.1</Version>
|
||||
<Version>2.3</Version>
|
||||
<AssemblyVersion>$(Version)</AssemblyVersion>
|
||||
<FileVersion>$(Version)</FileVersion>
|
||||
<IncludeSource>true</IncludeSource>
|
||||
@@ -27,10 +27,10 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="1.7.0" GeneratePathProperty="true">
|
||||
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="1.8.0" GeneratePathProperty="true">
|
||||
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.0-preview.6.21352.12" />
|
||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.0-rc.1.21451.13" />
|
||||
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
@@ -42,15 +42,22 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Resource Include="Images\Icon.ico" />
|
||||
<Resource Include="Images\ring-code-guide.png" />
|
||||
<None Remove="Images\ring-code-guide-2-layer.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Resource Include="Images\Icon.ico" />
|
||||
<Resource Include="Images\ring-code-guide-2-layer.png" />
|
||||
<Resource Include="Images\ring-code-guide-1-layer.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MPF.Core\MPF.Core.csproj" />
|
||||
<ProjectReference Include="..\MPF.Library\MPF.Library.csproj">
|
||||
<Project>{51ab0928-13f9-44bf-a407-b6957a43a056}</Project>
|
||||
<Name>MPF.Library</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\RedumpLib\RedumpLib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
44
MPF/OptionsLoader.cs
Normal file
44
MPF/OptionsLoader.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using MPF.Core.Data;
|
||||
|
||||
namespace MPF
|
||||
{
|
||||
public static class OptionsLoader
|
||||
{
|
||||
/// <summary>
|
||||
/// Load the current set of options from the application configuration
|
||||
/// </summary>
|
||||
public static Options LoadFromConfig()
|
||||
{
|
||||
Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
|
||||
|
||||
var settings = configFile.AppSettings.Settings;
|
||||
var dict = new Dictionary<string, string>();
|
||||
|
||||
foreach (string key in settings.AllKeys)
|
||||
{
|
||||
dict[key] = settings[key]?.Value ?? string.Empty;
|
||||
}
|
||||
|
||||
return new Options(dict);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save the current set of options to the application configuration
|
||||
/// </summary>
|
||||
public static void SaveToConfig(Options options)
|
||||
{
|
||||
Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
|
||||
|
||||
// Loop through all settings in Options and save them, overwriting existing settings
|
||||
foreach (var kvp in options)
|
||||
{
|
||||
configFile.AppSettings.Settings.Remove(kvp.Key);
|
||||
configFile.AppSettings.Settings.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
|
||||
configFile.Save(ConfigurationSaveMode.Modified);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,16 +14,16 @@
|
||||
</Grid>
|
||||
|
||||
<Border Height="180" Background="White" BorderBrush="Gainsboro" BorderThickness="1" Margin="10">
|
||||
<ScrollViewer Name="OutputViewer" SizeChanged="OutputViewerSizeChanged" Template="{DynamicResource CustomScrollViewerControlStyle}">
|
||||
<RichTextBox Name="Output" FontFamily="Consolas" Background="#FF202020" IsReadOnly="true" TextChanged="OnTextChanged" />
|
||||
<ScrollViewer Name="OutputViewer" Template="{DynamicResource CustomScrollViewerControlStyle}">
|
||||
<RichTextBox Name="Output" FontFamily="Consolas" Background="#FF202020" IsReadOnly="true" />
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
|
||||
<GroupBox Grid.Row="2" Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<UniformGrid Columns="4" Margin="5,5,5,5" Height="28">
|
||||
<Label/> <!-- Empty label for padding -->
|
||||
<Button Name="ClearButton" Height="25" Width="80" Content="Clear" Click="OnClearButton" Style="{DynamicResource CustomButtonStyle}" />
|
||||
<Button Name="SaveButton" Height="25" Width="80" Content="Save" Click="OnSaveButton" Style="{DynamicResource CustomButtonStyle}" />
|
||||
<Button Name="ClearButton" Height="25" Width="80" Content="Clear" Style="{DynamicResource CustomButtonStyle}" />
|
||||
<Button Name="SaveButton" Height="25" Width="80" Content="Save" Style="{DynamicResource CustomButtonStyle}" />
|
||||
<Label/> <!-- Empty label for padding -->
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
|
||||
@@ -1,546 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Media;
|
||||
using MPF.Data;
|
||||
using System.Windows.Controls;
|
||||
using MPF.GUI.ViewModels;
|
||||
|
||||
namespace MPF.UserControls
|
||||
{
|
||||
public partial class LogOutput : UserControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Paragraph backing the log
|
||||
/// Read-only access to the current log view model
|
||||
/// </summary>
|
||||
private readonly Paragraph _paragraph;
|
||||
|
||||
/// <summary>
|
||||
/// Cached value of the last line written
|
||||
/// </summary>
|
||||
private Run lastLine = null;
|
||||
|
||||
/// <summary>
|
||||
/// Queue of items that need to be logged
|
||||
/// </summary>
|
||||
private readonly ProcessingQueue<LogLine> logQueue;
|
||||
|
||||
/// <summary>
|
||||
/// List of Matchers for progress tracking
|
||||
/// </summary>
|
||||
private readonly List<Matcher?> _matchers;
|
||||
|
||||
/// <summary>
|
||||
/// Cached value of the last matcher used
|
||||
/// </summary>
|
||||
private Matcher? lastUsedMatcher = null;
|
||||
|
||||
/// <summary>
|
||||
/// Regex pattern to find DiscImageCreator progress messages
|
||||
/// </summary>
|
||||
private const string DiscImageCreatorProgressPattern = @"\s*(\d+)\/\s*(\d+)$";
|
||||
public LogViewModel LogViewModel => DataContext as LogViewModel;
|
||||
|
||||
public LogOutput()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = this;
|
||||
|
||||
var document = new FlowDocument()
|
||||
{
|
||||
Background = new SolidColorBrush(Color.FromArgb(0xFF, 0x20, 0x20, 0x20))
|
||||
};
|
||||
_paragraph = new Paragraph();
|
||||
document.Blocks.Add(_paragraph);
|
||||
Output.Document = document;
|
||||
|
||||
// TODO: Can we dynamically add matchers *only* during dumping?
|
||||
_matchers = new List<Matcher?>();
|
||||
AddAaruMatchers();
|
||||
AddDiscImageCreatorMatchers();
|
||||
|
||||
logQueue = new ProcessingQueue<LogLine>(ProcessLogLine);
|
||||
DataContext = new LogViewModel(this);
|
||||
}
|
||||
|
||||
#region Matching
|
||||
|
||||
/// <summary>
|
||||
/// Matching wrapper
|
||||
/// </summary>
|
||||
private struct Matcher
|
||||
{
|
||||
private readonly string prefix;
|
||||
private readonly Regex regex;
|
||||
private readonly int start;
|
||||
private readonly string progressBarText;
|
||||
private readonly Action<Match, string> lambda;
|
||||
|
||||
public Matcher(string prefix, string regex, string progressBarText, Action<Match, string> lambda)
|
||||
{
|
||||
this.prefix = prefix;
|
||||
this.regex = new Regex(regex);
|
||||
this.start = prefix.Length;
|
||||
this.progressBarText = progressBarText;
|
||||
this.lambda = lambda;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the text matches the prefix
|
||||
/// </summary>
|
||||
/// <param name="text">Text to check</param>
|
||||
/// <returns>True if the line starts with the prefix, false otherwise</returns>
|
||||
public bool Matches(string text) => text.StartsWith(prefix);
|
||||
|
||||
/// <summary>
|
||||
/// Generate a Match and apply the lambda
|
||||
/// </summary>
|
||||
/// <param name="text">Text to match and apply from</param>
|
||||
public void Apply(string text)
|
||||
{
|
||||
Match match = regex?.Match(text, start);
|
||||
lambda?.Invoke(match, progressBarText);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add all Matchers for Aaru
|
||||
/// </summary>
|
||||
private void AddAaruMatchers()
|
||||
{
|
||||
// TODO: Determine matchers that can be added
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add all Matchers for DiscImageCreator
|
||||
/// </summary>
|
||||
private void AddDiscImageCreatorMatchers()
|
||||
{
|
||||
#region Pre-dump Checking
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Checking EXE",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Checking executables...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Checking Pregap sync, msf, mode (LBA)",
|
||||
@"\s*-(\d+)$",
|
||||
"Checking Pregap sync, msf, mode",
|
||||
(match, text) =>
|
||||
{
|
||||
ProgressBar.Value = 0;
|
||||
ProgressLabel.Text = text;
|
||||
}));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Checking SubQ adr (Track)",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Checking SubQ adr...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Checking SubQ ctl (Track)",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Checking SubQ ctl...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Checking SubRtoW (Track)",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Checking SubRtoW...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Reading DirectoryRecord",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Reading directory records...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Scanning sector for anti-mod string (LBA)",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Scanning sectors for anti-mod string...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dumping
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
@"Creating iso(LBA)",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Creating ISO...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
@"Creating .scm (LBA)",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Creating scrambled image...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
#endregion
|
||||
|
||||
#region Post-Dump Processing
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Checking sectors:",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Checking for errors...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Creating bin (Track)",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Creating BIN(s)...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Creating cue and ccd (Track)",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Creating CUE and CCD...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Descrambling data sector of img:",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Descrambling image...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Scanning sector (LBA)",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Scanning sectors for protection...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Logging
|
||||
|
||||
/// <summary>
|
||||
/// Log level for output
|
||||
/// </summary>
|
||||
private enum LogLevel
|
||||
{
|
||||
USER,
|
||||
VERBOSE,
|
||||
ERROR,
|
||||
SECRET,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log line wrapper
|
||||
/// </summary>
|
||||
private struct LogLine
|
||||
{
|
||||
public readonly string Text;
|
||||
public readonly LogLevel LogLevel;
|
||||
|
||||
public LogLine(string text, LogLevel logLevel)
|
||||
{
|
||||
this.Text = text;
|
||||
this.LogLevel = logLevel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the foreground Brush for the current LogLevel
|
||||
/// </summary>
|
||||
/// <returns>Brush representing the color</returns>
|
||||
public Brush GetForegroundColor()
|
||||
{
|
||||
switch (this.LogLevel)
|
||||
{
|
||||
case LogLevel.SECRET:
|
||||
return Brushes.Blue;
|
||||
case LogLevel.ERROR:
|
||||
return Brushes.Red;
|
||||
case LogLevel.VERBOSE:
|
||||
return Brushes.Yellow;
|
||||
case LogLevel.USER:
|
||||
default:
|
||||
return Brushes.White;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a Run object from the current LogLine
|
||||
/// </summary>
|
||||
/// <returns>Run object based on internal values</returns>
|
||||
public Run GenerateRun()
|
||||
{
|
||||
return new Run { Text = this.Text, Foreground = GetForegroundColor() };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue text to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void Log(string text) => LogInternal(text);
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue text with a newline to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void LogLn(string text) => Log(text + "\n");
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue error text to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void ErrorLog(string text) => LogInternal(text, LogLevel.ERROR);
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue error text with a newline to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void ErrorLogLn(string text) => ErrorLog(text + "\n");
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue secret text to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void SecretLog(string text) => LogInternal(text, LogLevel.SECRET);
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue secret text with a newline to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void SecretLogLn(string text) => SecretLog(text + "\n");
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue verbose text to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void VerboseLog(string text) => LogInternal(text, LogLevel.VERBOSE);
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue verbose text with a newline to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void VerboseLogLn(string text) => VerboseLog(text + "\n");
|
||||
|
||||
/// <summary>
|
||||
/// Reset the progress bar state
|
||||
/// </summary>
|
||||
public void ResetProgressBar()
|
||||
{
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
ProgressBar.Value = 0;
|
||||
ProgressLabel.Text = string.Empty;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue text to the log with formatting
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
/// <param name="logLevel">LogLevel for the log, defaults to USER</param>
|
||||
private void LogInternal(string text, LogLevel logLevel = LogLevel.USER)
|
||||
{
|
||||
// Null text gets ignored
|
||||
if (text == null)
|
||||
return;
|
||||
|
||||
// If we have verbose logs but not enabled, ignore
|
||||
if (logLevel == LogLevel.VERBOSE && !ViewModels.OptionsViewModel.VerboseLogging)
|
||||
return;
|
||||
|
||||
// Enqueue the text
|
||||
logQueue.Enqueue(new LogLine(text, logLevel));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process the log lines in the queue
|
||||
/// </summary>
|
||||
/// <param name="nextLogLine">LogLine item to process</param>
|
||||
private void ProcessLogLine(LogLine nextLogLine)
|
||||
{
|
||||
// Null text gets ignored
|
||||
string nextText = Dispatcher.Invoke(() => nextLogLine.Text);
|
||||
if (nextText == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
// If we're not processing log formatting, just append and continue
|
||||
if (!ViewModels.OptionsViewModel.EnableLogFormatting)
|
||||
{
|
||||
if (nextText.StartsWith("\r"))
|
||||
ReplaceLastLine(nextLogLine);
|
||||
else
|
||||
AppendToTextBox(nextLogLine);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Get last line
|
||||
lastLine = lastLine ?? GetLastLine();
|
||||
|
||||
// Always append if there's no previous line
|
||||
if (lastLine == null)
|
||||
{
|
||||
AppendToTextBox(nextLogLine);
|
||||
lastUsedMatcher = _matchers.FirstOrDefault(m => m?.Matches(nextText) == true);
|
||||
}
|
||||
// Return always means overwrite
|
||||
else if (nextText.StartsWith("\r"))
|
||||
{
|
||||
ReplaceLastLine(nextLogLine);
|
||||
lastUsedMatcher = _matchers.FirstOrDefault(m => m?.Matches(nextText.TrimStart('\r')) == true);
|
||||
}
|
||||
// If we have a cached matcher and we match
|
||||
else if (lastUsedMatcher?.Matches(nextText) == true)
|
||||
{
|
||||
ReplaceLastLine(nextLogLine);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get the first matching Matcher
|
||||
var firstMatcher = _matchers.FirstOrDefault(m => m?.Matches(nextText) == true);
|
||||
if (firstMatcher.HasValue)
|
||||
{
|
||||
string lastText = Dispatcher.Invoke(() => { return lastLine.Text; });
|
||||
if (firstMatcher.Value.Matches(lastText))
|
||||
ReplaceLastLine(nextLogLine);
|
||||
else if (string.IsNullOrWhiteSpace(lastText))
|
||||
ReplaceLastLine(nextLogLine);
|
||||
else
|
||||
AppendToTextBox(nextLogLine);
|
||||
|
||||
// Cache the last used Matcher
|
||||
lastUsedMatcher = firstMatcher;
|
||||
}
|
||||
// Default case for all other text
|
||||
else
|
||||
{
|
||||
AppendToTextBox(nextLogLine);
|
||||
lastUsedMatcher = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the bar if needed
|
||||
if (ViewModels.OptionsViewModel.EnableProgressProcessing)
|
||||
ProcessStringForProgressBar(nextText, lastUsedMatcher);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// In the event that something fails horribly, we want to log
|
||||
AppendToTextBox(new LogLine(ex.ToString(), LogLevel.ERROR));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Append log line to the log text box
|
||||
/// </summary>
|
||||
/// <param name="logLine">LogLine value to append</param>
|
||||
private void AppendToTextBox(LogLine logLine)
|
||||
{
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
var run = logLine.GenerateRun();
|
||||
_paragraph.Inlines.Add(run);
|
||||
lastLine = run;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the last line written to the log text box
|
||||
/// </summary>
|
||||
private Run GetLastLine()
|
||||
{
|
||||
return Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (!_paragraph.Inlines.Any())
|
||||
return null;
|
||||
|
||||
return _paragraph.Inlines.LastInline as Run;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process text if it should update the progress bar
|
||||
/// </summary>
|
||||
/// <param name="text">Text to check and update with</param>
|
||||
private void ProcessStringForProgressBar(string text, Matcher? matcher)
|
||||
{
|
||||
Dispatcher.Invoke(() => { matcher?.Apply(text); });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replace the last line written to the log text box
|
||||
/// </summary>
|
||||
/// <param name="logLine">LogLine value to append</param>
|
||||
private void ReplaceLastLine(LogLine logLine)
|
||||
{
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
lastLine.Text = logLine.Text;
|
||||
lastLine.Foreground = logLine.GetForegroundColor();
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region EventHandlers
|
||||
|
||||
private void OnClearButton(object sender, EventArgs e)
|
||||
{
|
||||
_paragraph.Inlines.Clear();
|
||||
ResetProgressBar();
|
||||
}
|
||||
|
||||
private void OnSaveButton(object sender, EventArgs e)
|
||||
{
|
||||
using (StreamWriter tw = new StreamWriter(File.OpenWrite("console.log")))
|
||||
{
|
||||
foreach (var inline in _paragraph.Inlines)
|
||||
{
|
||||
if (inline is Run run)
|
||||
tw.Write(run.Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
OutputViewer.ScrollToBottom();
|
||||
}
|
||||
|
||||
private void OutputViewerSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
OutputViewer.ScrollToBottom();
|
||||
}
|
||||
|
||||
private void StandardDiscImageCreatorProgress(Match match, string text)
|
||||
{
|
||||
if (uint.TryParse(match.Groups[1].Value, out uint current) && uint.TryParse(match.Groups[2].Value, out uint total))
|
||||
{
|
||||
float percentProgress = (current / (float)total) * 100;
|
||||
ProgressBar.Value = percentProgress;
|
||||
ProgressLabel.Text = string.Format($"{text} ({percentProgress:N2}%)");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,19 +2,29 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MPF.UserControls"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800" x:Name="userInput">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="0.75*" />
|
||||
<ColumnDefinition Width="1.25*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Right"
|
||||
Content="{Binding ElementName=userInput, Path=Label}" />
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="{Binding Label}" />
|
||||
<TextBox Grid.Row="0" Grid.Column="1" Height="{Binding TextHeight}" HorizontalAlignment="Stretch" Text="{Binding Text}"
|
||||
AcceptsTab="{Binding Tab}" AcceptsReturn="{Binding Enter}" TextWrapping="{Binding TextWrapping}"
|
||||
VerticalContentAlignment="{Binding VerticalContentAlignmentValue}" VerticalScrollBarVisibility="{Binding ScrollBarVisibility}"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1"
|
||||
Height="{Binding ElementName=userInput, Path=TextHeight}"
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding ElementName=userInput, Path=Text}"
|
||||
AcceptsTab="{Binding ElementName=userInput, Path=Tab}"
|
||||
AcceptsReturn="{Binding ElementName=userInput, Path=Enter}"
|
||||
TextWrapping="{Binding ElementName=userInput, Path=TextWrapping}"
|
||||
IsReadOnly="{Binding ElementName=userInput, Path=IsReadOnly}"
|
||||
VerticalContentAlignment="{Binding ElementName=userInput, Path=VerticalContentAlignmentValue}"
|
||||
HorizontalScrollBarVisibility="{Binding ElementName=userInput, Path=HorizontalScrollBarVisibility}"
|
||||
VerticalScrollBarVisibility="{Binding ElementName=userInput, Path=VerticalScrollBarVisibility}"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -8,19 +8,118 @@ namespace MPF.UserControls
|
||||
/// </summary>
|
||||
public partial class UserInput : UserControl
|
||||
{
|
||||
public string Label { get; set; }
|
||||
public string Text { get; set; }
|
||||
public string TextHeight { get; set; } = "22";
|
||||
public bool Tab { get; set; } = false;
|
||||
public bool Enter { get; set; } = false;
|
||||
public TextWrapping TextWrapping { get; set; } = TextWrapping.NoWrap;
|
||||
public VerticalAlignment VerticalContentAlignmentValue { get; set; } = VerticalAlignment.Center;
|
||||
public ScrollBarVisibility ScrollBarVisibility { get; set; } = ScrollBarVisibility.Auto;
|
||||
#region Dependency Properties
|
||||
|
||||
public static readonly DependencyProperty LabelProperty =
|
||||
DependencyProperty.Register("Label", typeof(string), typeof(UserInput));
|
||||
|
||||
public static readonly DependencyProperty TextProperty =
|
||||
DependencyProperty.Register("Text", typeof(string), typeof(UserInput));
|
||||
|
||||
public static readonly DependencyProperty TextHeightProperty =
|
||||
DependencyProperty.Register("TextHeight", typeof(string), typeof(UserInput));
|
||||
|
||||
public static readonly DependencyProperty TabProperty =
|
||||
DependencyProperty.Register("Tab", typeof(bool), typeof(UserInput));
|
||||
|
||||
public static readonly DependencyProperty EnterProperty =
|
||||
DependencyProperty.Register("Enter", typeof(bool), typeof(UserInput));
|
||||
|
||||
public static readonly DependencyProperty TextWrappingProperty =
|
||||
DependencyProperty.Register("TextWrapping", typeof(TextWrapping), typeof(UserInput));
|
||||
|
||||
public static readonly DependencyProperty IsReadOnlyProperty =
|
||||
DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(UserInput));
|
||||
|
||||
public static readonly DependencyProperty VerticalContentAlignmentValueProperty =
|
||||
DependencyProperty.Register("VerticalContentAlignmentValue", typeof(VerticalAlignment), typeof(UserInput));
|
||||
|
||||
public static readonly DependencyProperty HorizontalScrollBarVisibilityProperty =
|
||||
DependencyProperty.Register("HorizontalScrollBarVisibility", typeof(ScrollBarVisibility), typeof(UserInput));
|
||||
|
||||
public static readonly DependencyProperty VerticalScrollBarVisibilityProperty =
|
||||
DependencyProperty.Register("VerticalScrollBarVisibility", typeof(ScrollBarVisibility), typeof(UserInput));
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public string Label
|
||||
{
|
||||
get => (string)GetValue(LabelProperty);
|
||||
set => SetValue(LabelProperty, value);
|
||||
}
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => (string)GetValue(TextProperty);
|
||||
set => SetValue(TextProperty, value);
|
||||
}
|
||||
|
||||
public string TextHeight
|
||||
{
|
||||
get => (string)GetValue(TextHeightProperty);
|
||||
set => SetValue(TextHeightProperty, value);
|
||||
}
|
||||
|
||||
public bool Tab
|
||||
{
|
||||
get => (bool)GetValue(TabProperty);
|
||||
set => SetValue(TabProperty, value);
|
||||
}
|
||||
|
||||
public bool Enter
|
||||
{
|
||||
get => (bool)GetValue(EnterProperty);
|
||||
set => SetValue(EnterProperty, value);
|
||||
}
|
||||
|
||||
public TextWrapping TextWrapping
|
||||
{
|
||||
get => (TextWrapping)GetValue(TextWrappingProperty);
|
||||
set => SetValue(TextWrappingProperty, value);
|
||||
}
|
||||
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get => (bool)GetValue(IsReadOnlyProperty);
|
||||
set => SetValue(IsReadOnlyProperty, value);
|
||||
}
|
||||
|
||||
public VerticalAlignment VerticalContentAlignmentValue
|
||||
{
|
||||
get => (VerticalAlignment)GetValue(VerticalContentAlignmentValueProperty);
|
||||
set => SetValue(VerticalContentAlignmentValueProperty, value);
|
||||
}
|
||||
|
||||
public ScrollBarVisibility HorizontalScrollBarVisibility
|
||||
{
|
||||
get => (ScrollBarVisibility)GetValue(HorizontalScrollBarVisibilityProperty);
|
||||
set => SetValue(HorizontalScrollBarVisibilityProperty, value);
|
||||
}
|
||||
|
||||
public ScrollBarVisibility VerticalScrollBarVisibility
|
||||
{
|
||||
get => (ScrollBarVisibility)GetValue(VerticalScrollBarVisibilityProperty);
|
||||
set => SetValue(VerticalScrollBarVisibilityProperty, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public UserInput()
|
||||
{
|
||||
// Set default values
|
||||
TextHeight = "22";
|
||||
Tab = false;
|
||||
Enter = false;
|
||||
TextWrapping = TextWrapping.NoWrap;
|
||||
IsReadOnly = false;
|
||||
VerticalContentAlignmentValue = VerticalAlignment.Center;
|
||||
HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden;
|
||||
VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
|
||||
|
||||
InitializeComponent();
|
||||
DataContext = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
using MPF.Data;
|
||||
|
||||
namespace MPF
|
||||
{
|
||||
/// <summary>
|
||||
/// Globally referencable options
|
||||
/// </summary>
|
||||
public class OptionsViewModel
|
||||
{
|
||||
private readonly Options options;
|
||||
|
||||
public bool VerboseLogging
|
||||
{
|
||||
get { return options.VerboseLogging; }
|
||||
}
|
||||
|
||||
public bool EnableLogFormatting
|
||||
{
|
||||
get { return options.EnableLogFormatting; }
|
||||
}
|
||||
|
||||
public bool EnableProgressProcessing
|
||||
{
|
||||
get { return options.EnableProgressProcessing; }
|
||||
}
|
||||
|
||||
public OptionsViewModel(Options options)
|
||||
{
|
||||
this.options = options;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ViewModels
|
||||
{
|
||||
public static OptionsViewModel OptionsViewModel { get; set; }
|
||||
}
|
||||
}
|
||||
627
MPF/ViewModels/DiscInformationViewModel.cs
Normal file
627
MPF/ViewModels/DiscInformationViewModel.cs
Normal file
@@ -0,0 +1,627 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using MPF.Core.Utilities;
|
||||
using MPF.Windows;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.GUI.ViewModels
|
||||
{
|
||||
public class DiscInformationViewModel
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// Parent DiscInformationWindow object
|
||||
/// </summary>
|
||||
public DiscInformationWindow Parent { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// SubmissionInfo object to fill and save
|
||||
/// </summary>
|
||||
public SubmissionInfo SubmissionInfo { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Lists
|
||||
|
||||
/// <summary>
|
||||
/// List of available disc categories
|
||||
/// </summary>
|
||||
public List<Element<DiscCategory>> Categories { get; private set; } = Element<DiscCategory>.GenerateElements().ToList();
|
||||
|
||||
/// <summary>
|
||||
/// List of available regions
|
||||
/// </summary>
|
||||
public List<Element<Region>> Regions { get; private set; } = Element<Region>.GenerateElements().ToList();
|
||||
|
||||
/// <summary>
|
||||
/// List of available languages
|
||||
/// </summary>
|
||||
public List<Element<Language>> Languages { get; private set; } = Element<Language>.GenerateElements().ToList();
|
||||
|
||||
/// <summary>
|
||||
/// List of available languages
|
||||
/// </summary>
|
||||
public List<Element<LanguageSelection>> LanguageSelections { get; private set; } = Element<LanguageSelection>.GenerateElements().ToList();
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public DiscInformationViewModel(DiscInformationWindow parent, SubmissionInfo submissionInfo)
|
||||
{
|
||||
Parent = parent;
|
||||
SubmissionInfo = submissionInfo.Clone() as SubmissionInfo ?? new SubmissionInfo();
|
||||
|
||||
// Add handlers
|
||||
Parent.AcceptButton.Click += OnAcceptClick;
|
||||
Parent.CancelButton.Click += OnCancelClick;
|
||||
Parent.RingCodeGuideButton.Click += OnRingCodeGuideClick;
|
||||
|
||||
// Update UI with new values
|
||||
ManipulateFields();
|
||||
Load();
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Enable tab entry on supported fields
|
||||
/// </summary>
|
||||
private void EnableTabsInInputFields()
|
||||
{
|
||||
// Additional Information
|
||||
Parent.CommentsTextBox.Tab = true;
|
||||
Parent.GeneralContent.Tab = true;
|
||||
Parent.ExtrasTextBox.Tab = true;
|
||||
Parent.GameFootageTextBox.Tab = true;
|
||||
Parent.NetYarozeGamesTextBox.Tab = true;
|
||||
Parent.PatchesTextBox.Tab = true;
|
||||
Parent.PlayableDemosTextBox.Tab = true;
|
||||
Parent.RollingDemosTextBox.Tab = true;
|
||||
Parent.SavegamesTextBox.Tab = true;
|
||||
Parent.TechDemosTextBox.Tab = true;
|
||||
|
||||
// L0
|
||||
Parent.L0MasteringRing.Tab = true;
|
||||
Parent.L0MasteringSID.Tab = true;
|
||||
Parent.L0Toolstamp.Tab = true;
|
||||
Parent.L0MouldSID.Tab = true;
|
||||
Parent.L0AdditionalMould.Tab = true;
|
||||
|
||||
// L1
|
||||
Parent.L1MasteringRing.Tab = true;
|
||||
Parent.L1MasteringSID.Tab = true;
|
||||
Parent.L1Toolstamp.Tab = true;
|
||||
Parent.L1MouldSID.Tab = true;
|
||||
Parent.L1AdditionalMould.Tab = true;
|
||||
|
||||
// L2
|
||||
Parent.L2MasteringRing.Tab = true;
|
||||
Parent.L2MasteringSID.Tab = true;
|
||||
Parent.L2Toolstamp.Tab = true;
|
||||
|
||||
// L3
|
||||
Parent.L3MasteringRing.Tab = true;
|
||||
Parent.L3MasteringSID.Tab = true;
|
||||
Parent.L3Toolstamp.Tab = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hide any optional, read-only fields if they don't have a value
|
||||
/// </summary>
|
||||
private void HideReadOnlyFields()
|
||||
{
|
||||
if (SubmissionInfo?.MatchedIDs == null)
|
||||
Parent.MatchedIDs.Visibility = Visibility.Collapsed;
|
||||
else
|
||||
Parent.MatchedIDs.Text = string.Join(", ", SubmissionInfo.MatchedIDs);
|
||||
if (SubmissionInfo?.CopyProtection?.AntiModchip == null)
|
||||
Parent.AntiModchip.Visibility = Visibility.Collapsed;
|
||||
else
|
||||
Parent.AntiModchip.Text = SubmissionInfo.CopyProtection.AntiModchip.LongName();
|
||||
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.DMIHash) != true)
|
||||
Parent.DMIHash.Visibility = Visibility.Collapsed;
|
||||
if (string.IsNullOrWhiteSpace(SubmissionInfo?.CommonDiscInfo?.ErrorsCount))
|
||||
Parent.ErrorsCount.Visibility = Visibility.Collapsed;
|
||||
if (string.IsNullOrWhiteSpace(SubmissionInfo?.CommonDiscInfo?.EXEDateBuildDate))
|
||||
Parent.EXEDateBuildDate.Visibility = Visibility.Collapsed;
|
||||
if (SubmissionInfo?.EDC?.EDC == null)
|
||||
Parent.EDC.Visibility = Visibility.Collapsed;
|
||||
else
|
||||
Parent.EDC.Text = SubmissionInfo.EDC.EDC.LongName();
|
||||
if (string.IsNullOrWhiteSpace(SubmissionInfo?.Extras?.Header))
|
||||
Parent.Header.Visibility = Visibility.Collapsed;
|
||||
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.InternalSerialName) != true)
|
||||
Parent.InternalSerialName.Visibility = Visibility.Collapsed;
|
||||
if (SubmissionInfo?.CopyProtection?.LibCrypt == null)
|
||||
Parent.LibCrypt.Visibility = Visibility.Collapsed;
|
||||
else
|
||||
Parent.LibCrypt.Text = SubmissionInfo.CopyProtection.LibCrypt.LongName();
|
||||
if (string.IsNullOrWhiteSpace(SubmissionInfo?.CopyProtection?.LibCryptData))
|
||||
Parent.LibCryptData.Visibility = Visibility.Collapsed;
|
||||
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.PFIHash) != true)
|
||||
Parent.PFIHash.Visibility = Visibility.Collapsed;
|
||||
if (string.IsNullOrWhiteSpace(SubmissionInfo?.Extras?.PIC))
|
||||
Parent.PIC.Visibility = Visibility.Collapsed;
|
||||
if (string.IsNullOrWhiteSpace(SubmissionInfo?.CopyProtection?.Protection))
|
||||
Parent.Protection.Visibility = Visibility.Collapsed;
|
||||
if (string.IsNullOrWhiteSpace(SubmissionInfo?.Extras?.PVD))
|
||||
Parent.PVD.Visibility = Visibility.Collapsed;
|
||||
if (string.IsNullOrWhiteSpace(SubmissionInfo?.CopyProtection?.SecuROMData))
|
||||
Parent.SecuROMData.Visibility = Visibility.Collapsed;
|
||||
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.SSHash) != true)
|
||||
Parent.SSHash.Visibility = Visibility.Collapsed;
|
||||
if (string.IsNullOrWhiteSpace(SubmissionInfo?.Extras?.SecuritySectorRanges))
|
||||
Parent.SecuritySectorRanges.Visibility = Visibility.Collapsed;
|
||||
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.SSVersion) != true)
|
||||
Parent.SSVersion.Visibility = Visibility.Collapsed;
|
||||
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.VolumeLabel) != true)
|
||||
Parent.VolumeLabel.Visibility = Visibility.Collapsed;
|
||||
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.XeMID) != true)
|
||||
Parent.XeMID.Visibility = Visibility.Collapsed;
|
||||
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.XMID) != true)
|
||||
Parent.XMID.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manipulate fields based on the current disc
|
||||
/// </summary>
|
||||
private void ManipulateFields()
|
||||
{
|
||||
// Enable tabs in all fields, if required
|
||||
if (App.Options.EnableTabsInInputFields)
|
||||
EnableTabsInInputFields();
|
||||
|
||||
// Hide read-only fields that don't have values set
|
||||
HideReadOnlyFields();
|
||||
|
||||
// Different media types mean different fields available
|
||||
UpdateFromDiscType();
|
||||
|
||||
// Different systems mean different fields available
|
||||
UpdateFromSystemType();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load the current contents of the base SubmissionInfo to the UI
|
||||
/// </summary>
|
||||
private void Load()
|
||||
{
|
||||
Parent.CategoryComboBox.SelectedIndex = Categories.FindIndex(r => r == SubmissionInfo.CommonDiscInfo.Category);
|
||||
Parent.RegionComboBox.SelectedIndex = Regions.FindIndex(r => r == SubmissionInfo.CommonDiscInfo.Region);
|
||||
if (SubmissionInfo.CommonDiscInfo.Languages != null)
|
||||
Languages.ForEach(l => l.IsChecked = SubmissionInfo.CommonDiscInfo.Languages.Contains(l));
|
||||
if (SubmissionInfo.CommonDiscInfo.LanguageSelection != null)
|
||||
LanguageSelections.ForEach(ls => ls.IsChecked = SubmissionInfo.CommonDiscInfo.LanguageSelection.Contains(ls));
|
||||
|
||||
// TODO: Figure out if this can be automatically mapped instead
|
||||
|
||||
// Comment Fields
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields != null)
|
||||
{
|
||||
// Additional Information
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.AlternativeTitle))
|
||||
Parent.AlternativeTitleTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.AlternativeTitle];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.AlternativeForeignTitle))
|
||||
Parent.AlternativeForeignTitleTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.AlternativeForeignTitle];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.Genre))
|
||||
Parent.GenreTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.Genre];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.PostgapType))
|
||||
Parent.PostgapTypeCheckBox.IsChecked = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.PostgapType] != null;
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.Series))
|
||||
Parent.SeriesTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.Series];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.VCD))
|
||||
Parent.VCDCheckBox.IsChecked = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.VCD] != null;
|
||||
|
||||
// Physical Identifiers
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.BBFCRegistrationNumber))
|
||||
Parent.BBFCRegistrationNumberTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.BBFCRegistrationNumber];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.DiscHologramID))
|
||||
Parent.DiscHologramIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.DiscHologramID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.DNASDiscID))
|
||||
Parent.DNASDiscIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.DNASDiscID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.ISBN))
|
||||
Parent.ISBNTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.ISBN];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.ISSN))
|
||||
Parent.ISSNTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.ISSN];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.PPN))
|
||||
Parent.PPNTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.PPN];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.VFCCode))
|
||||
Parent.VFCCodeTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.VFCCode];
|
||||
|
||||
// Publisher Identifiers
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.AcclaimID))
|
||||
Parent.AcclaimIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.AcclaimID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.ActivisionID))
|
||||
Parent.ActivisionIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.ActivisionID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.BandaiID))
|
||||
Parent.BandaiIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.BandaiID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.ElectronicArtsID))
|
||||
Parent.ElectronicArtsIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.ElectronicArtsID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.FoxInteractiveID))
|
||||
Parent.FoxInteractiveIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.FoxInteractiveID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.GTInteractiveID))
|
||||
Parent.GTInteractiveIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.GTInteractiveID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.JASRACID))
|
||||
Parent.JASRACIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.JASRACID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.KingRecordsID))
|
||||
Parent.KingRecordsIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.KingRecordsID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.KoeiID))
|
||||
Parent.KoeiIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.KoeiID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.KonamiID))
|
||||
Parent.KonamiIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.KonamiID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.LucasArtsID))
|
||||
Parent.LucasArtsIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.LucasArtsID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.MicrosoftID))
|
||||
Parent.MicrosoftIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.MicrosoftID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.NaganoID))
|
||||
Parent.NaganoIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.NaganoID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.NamcoID))
|
||||
Parent.NamcoIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.NamcoID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.NipponIchiSoftwareID))
|
||||
Parent.NipponIchiSoftwareIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.NipponIchiSoftwareID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.OriginID))
|
||||
Parent.OriginIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.OriginID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.PonyCanyonID))
|
||||
Parent.PonyCanyonIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.PonyCanyonID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.SegaID))
|
||||
Parent.SegaIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SegaID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.SelenID))
|
||||
Parent.SelenIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SelenID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.SierraID))
|
||||
Parent.SierraIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SierraID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.TaitoID))
|
||||
Parent.TaitoIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.TaitoID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.UbisoftID))
|
||||
Parent.UbisoftIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.UbisoftID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.ValveID))
|
||||
Parent.ValveIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.ValveID];
|
||||
|
||||
// Read-Only Information
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.DMIHash))
|
||||
Parent.DMIHash.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.DMIHash];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.InternalSerialName))
|
||||
Parent.InternalSerialName.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.PFIHash))
|
||||
Parent.PFIHash.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.PFIHash];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.SSHash))
|
||||
Parent.SSHash.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSHash];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.SSVersion))
|
||||
Parent.SSVersion.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSVersion];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.VolumeLabel))
|
||||
Parent.VolumeLabel.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.VolumeLabel];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.XeMID))
|
||||
Parent.XeMID.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.XeMID];
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.XMID))
|
||||
Parent.XMID.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.XMID];
|
||||
}
|
||||
|
||||
// Content Fields
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields != null)
|
||||
{
|
||||
// Games
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields.ContainsKey(SiteCode.Games))
|
||||
Parent.GamesTextBox.Text = SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.Games];
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields.ContainsKey(SiteCode.NetYarozeGames))
|
||||
Parent.NetYarozeGamesTextBox.Text = SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.NetYarozeGames];
|
||||
|
||||
// Demos
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields.ContainsKey(SiteCode.PlayableDemos))
|
||||
Parent.PlayableDemosTextBox.Text = SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.PlayableDemos];
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields.ContainsKey(SiteCode.RollingDemos))
|
||||
Parent.RollingDemosTextBox.Text = SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.RollingDemos];
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields.ContainsKey(SiteCode.TechDemos))
|
||||
Parent.TechDemosTextBox.Text = SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.TechDemos];
|
||||
|
||||
// Video
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields.ContainsKey(SiteCode.GameFootage))
|
||||
Parent.GameFootageTextBox.Text = SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.GameFootage];
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields.ContainsKey(SiteCode.Videos))
|
||||
Parent.VideosTextBox.Text = SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.Videos];
|
||||
|
||||
// Miscellaneous
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields.ContainsKey(SiteCode.Patches))
|
||||
Parent.PatchesTextBox.Text = SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.Patches];
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields.ContainsKey(SiteCode.Savegames))
|
||||
Parent.SavegamesTextBox.Text = SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.Savegames];
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields.ContainsKey(SiteCode.Extras))
|
||||
Parent.ExtrasTextBox.Text = SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.Extras];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save the current contents of the UI to the base SubmissionInfo
|
||||
/// </summary>
|
||||
public void Save()
|
||||
{
|
||||
SubmissionInfo.CommonDiscInfo.Category = (Parent.CategoryComboBox.SelectedItem as Element<DiscCategory>)?.Value ?? DiscCategory.Games;
|
||||
SubmissionInfo.CommonDiscInfo.Region = (Parent.RegionComboBox.SelectedItem as Element<Region>)?.Value ?? Region.World;
|
||||
SubmissionInfo.CommonDiscInfo.Languages = Languages.Where(l => l.IsChecked).Select(l => l?.Value).ToArray();
|
||||
if (!SubmissionInfo.CommonDiscInfo.Languages.Any())
|
||||
SubmissionInfo.CommonDiscInfo.Languages = new Language?[] { null };
|
||||
SubmissionInfo.CommonDiscInfo.LanguageSelection = LanguageSelections.Where(ls => ls.IsChecked).Select(ls => ls?.Value).ToArray();
|
||||
|
||||
// TODO: Figure out if this can be automatically mapped instead
|
||||
|
||||
// Initialize the dictionaries, if needed
|
||||
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields == null)
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode?, string>();
|
||||
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields == null)
|
||||
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields = new Dictionary<SiteCode?, string>();
|
||||
|
||||
#region Comment Fields
|
||||
|
||||
// Additional Information
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.AlternativeTitle] = Parent.AlternativeTitleTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.AlternativeForeignTitle] = Parent.AlternativeForeignTitleTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.Genre] = Parent.GenreTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.PostgapType] = Parent.PostgapTypeCheckBox.IsChecked?.ToString();
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.Series] = Parent.SeriesTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.VCD] = Parent.VCDCheckBox.IsChecked?.ToString();
|
||||
|
||||
// Physical Identifiers
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.BBFCRegistrationNumber] = Parent.BBFCRegistrationNumberTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.DiscHologramID] = Parent.DiscHologramIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.DNASDiscID] = Parent.DNASDiscIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.ISBN] = Parent.ISBNTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.ISSN] = Parent.ISSNTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.PPN] = Parent.PPNTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.VFCCode] = Parent.VFCCodeTextBox.Text;
|
||||
|
||||
// Publisher Identifiers
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.AcclaimID] = Parent.AcclaimIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.ActivisionID] = Parent.ActivisionIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.BandaiID] = Parent.BandaiIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.ElectronicArtsID] = Parent.ElectronicArtsIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.FoxInteractiveID] = Parent.FoxInteractiveIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.GTInteractiveID] = Parent.GTInteractiveIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.JASRACID] = Parent.JASRACIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.KingRecordsID] = Parent.KingRecordsIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.KoeiID] = Parent.KoeiIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.KonamiID] = Parent.KonamiIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.LucasArtsID] = Parent.LucasArtsIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.MicrosoftID] = Parent.MicrosoftIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.NaganoID] = Parent.NaganoIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.NamcoID] = Parent.NamcoIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.NipponIchiSoftwareID] = Parent.NipponIchiSoftwareIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.OriginID] = Parent.OriginIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.PonyCanyonID] = Parent.PonyCanyonIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SegaID] = Parent.SegaIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SelenID] = Parent.SelenIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SierraID] = Parent.SierraIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.TaitoID] = Parent.TaitoIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.UbisoftID] = Parent.UbisoftIDTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.ValveID] = Parent.ValveIDTextBox.Text;
|
||||
|
||||
// Read-Only Information
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.DMIHash] = Parent.DMIHash.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = Parent.InternalSerialName.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.PFIHash] = Parent.PFIHash.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSHash] = Parent.SSHash.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSVersion] = Parent.SSVersion.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.VolumeLabel] = Parent.VolumeLabel.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.XeMID] = Parent.XeMID.Text;
|
||||
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.XMID] = Parent.XMID.Text;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Content Fields
|
||||
|
||||
// Games
|
||||
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.Games] = Parent.GamesTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.NetYarozeGames] = Parent.NetYarozeGamesTextBox.Text;
|
||||
|
||||
// Demos
|
||||
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.PlayableDemos] = Parent.PlayableDemosTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.RollingDemos] = Parent.RollingDemosTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.TechDemos] = Parent.TechDemosTextBox.Text;
|
||||
|
||||
// Video
|
||||
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.GameFootage] = Parent.GameFootageTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.Videos] = Parent.VideosTextBox.Text;
|
||||
|
||||
// Miscellaneous
|
||||
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.Patches] = Parent.PatchesTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.Savegames] = Parent.SavegamesTextBox.Text;
|
||||
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[SiteCode.Extras] = Parent.ExtrasTextBox.Text;
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update visible fields and sections based on the media type
|
||||
/// </summary>
|
||||
private void UpdateFromDiscType()
|
||||
{
|
||||
// Sony-printed discs have layers in the opposite order
|
||||
var system = SubmissionInfo?.CommonDiscInfo?.System;
|
||||
bool reverseOrder = system.HasReversedRingcodes();
|
||||
|
||||
switch (SubmissionInfo?.CommonDiscInfo?.Media)
|
||||
{
|
||||
case DiscType.CD:
|
||||
case DiscType.GDROM:
|
||||
Parent.L0Info.Header = "Data Side";
|
||||
Parent.L0MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L0MasteringSID.Label = "Mastering SID";
|
||||
Parent.L0Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
Parent.L0MouldSID.Label = "Mould SID";
|
||||
Parent.L0AdditionalMould.Label = "Additional Mould";
|
||||
|
||||
Parent.L1Info.Header = "Label Side";
|
||||
Parent.L1MasteringRing.Visibility = Visibility.Collapsed;
|
||||
Parent.L1MasteringSID.Visibility = Visibility.Collapsed;
|
||||
Parent.L1Toolstamp.Visibility = Visibility.Collapsed;
|
||||
Parent.L1MouldSID.Label = "Mould SID";
|
||||
Parent.L1AdditionalMould.Label = "Additional Mould";
|
||||
break;
|
||||
|
||||
case DiscType.DVD5:
|
||||
case DiscType.DVD9:
|
||||
case DiscType.HDDVDSL:
|
||||
case DiscType.BD25:
|
||||
case DiscType.BD50:
|
||||
case DiscType.NintendoGameCubeGameDisc:
|
||||
case DiscType.NintendoWiiOpticalDiscSL:
|
||||
case DiscType.NintendoWiiOpticalDiscDL:
|
||||
case DiscType.NintendoWiiUOpticalDiscSL:
|
||||
// Quad-layer discs
|
||||
if (SubmissionInfo?.SizeAndChecksums?.Layerbreak3 != default(long))
|
||||
{
|
||||
Parent.L2Info.Visibility = Visibility.Visible;
|
||||
Parent.L3Info.Visibility = Visibility.Visible;
|
||||
|
||||
Parent.L0Info.Header = reverseOrder ? "Layer 0 (Outer)" : "Layer 0 (Inner)";
|
||||
Parent.L0MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L0MasteringSID.Label = "Mastering SID";
|
||||
Parent.L0Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
Parent.L0MouldSID.Label = "Data Side Mould SID";
|
||||
Parent.L0AdditionalMould.Label = "Data Side Additional Mould";
|
||||
|
||||
Parent.L1Info.Header = "Layer 1";
|
||||
Parent.L1MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L1MasteringSID.Label = "Mastering SID";
|
||||
Parent.L1Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
Parent.L1MouldSID.Label = "Label Side Mould SID";
|
||||
Parent.L1AdditionalMould.Label = "Label Side Additional Mould";
|
||||
|
||||
Parent.L2Info.Header = "Layer 2";
|
||||
Parent.L2MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L2MasteringSID.Label = "Mastering SID";
|
||||
Parent.L2Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
|
||||
Parent.L3Info.Header = reverseOrder ? "Layer 3 (Inner)" : "Layer 3 (Outer)";
|
||||
Parent.L3MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L3MasteringSID.Label = "Mastering SID";
|
||||
Parent.L3Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
}
|
||||
|
||||
// Triple-layer discs
|
||||
else if (SubmissionInfo?.SizeAndChecksums?.Layerbreak2 != default(long))
|
||||
{
|
||||
Parent.L2Info.Visibility = Visibility.Visible;
|
||||
|
||||
Parent.L0Info.Header = reverseOrder ? "Layer 0 (Outer)" : "Layer 0 (Inner)";
|
||||
Parent.L0MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L0MasteringSID.Label = "Mastering SID";
|
||||
Parent.L0Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
Parent.L0MouldSID.Label = "Data Side Mould SID";
|
||||
Parent.L0AdditionalMould.Label = "Data Side Additional Mould";
|
||||
|
||||
Parent.L1Info.Header = "Layer 1";
|
||||
Parent.L1MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L1MasteringSID.Label = "Mastering SID";
|
||||
Parent.L1Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
Parent.L1MouldSID.Label = "Label Side Mould SID";
|
||||
Parent.L1AdditionalMould.Label = "Label Side Additional Mould";
|
||||
|
||||
Parent.L2Info.Header = reverseOrder ? "Layer 2 (Inner)" : "Layer 2 (Outer)";
|
||||
Parent.L2MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L2MasteringSID.Label = "Mastering SID";
|
||||
Parent.L2Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
}
|
||||
|
||||
// Double-layer discs
|
||||
else if (SubmissionInfo?.SizeAndChecksums?.Layerbreak != default(long))
|
||||
{
|
||||
Parent.L0Info.Header = reverseOrder ? "Layer 0 (Outer)" : "Layer 0 (Inner)";
|
||||
Parent.L0MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L0MasteringSID.Label = "Mastering SID";
|
||||
Parent.L0Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
Parent.L0MouldSID.Label = "Data Side Mould SID";
|
||||
Parent.L0AdditionalMould.Label = "Data Side Additional Mould";
|
||||
|
||||
Parent.L1Info.Header = reverseOrder ? "Layer 1 (Inner)" : "Layer 1 (Outer)";
|
||||
Parent.L1MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L1MasteringSID.Label = "Mastering SID";
|
||||
Parent.L1Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
Parent.L1MouldSID.Label = "Label Side Mould SID";
|
||||
Parent.L1AdditionalMould.Label = "Label Side Additional Mould";
|
||||
}
|
||||
|
||||
// Single-layer discs
|
||||
else
|
||||
{
|
||||
Parent.L0Info.Header = "Data Side";
|
||||
Parent.L0MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L0MasteringSID.Label = "Mastering SID";
|
||||
Parent.L0Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
Parent.L0MouldSID.Label = "Mould SID";
|
||||
Parent.L0AdditionalMould.Label = "Additional Mould";
|
||||
|
||||
Parent.L1Info.Header = "Label Side";
|
||||
Parent.L1MasteringRing.Label = "Mastering Ring";
|
||||
Parent.L1MasteringSID.Label = "Mastering SID";
|
||||
Parent.L1Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
Parent.L1MouldSID.Label = "Mould SID";
|
||||
Parent.L1AdditionalMould.Label = "Additional Mould";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// All other media we assume to have no rings
|
||||
default:
|
||||
Parent.L0Info.Visibility = Visibility.Collapsed;
|
||||
Parent.L1Info.Visibility = Visibility.Collapsed;
|
||||
Parent.L2Info.Visibility = Visibility.Collapsed;
|
||||
Parent.L3Info.Visibility = Visibility.Collapsed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update visible fields and sections based on the system type
|
||||
/// </summary>
|
||||
private void UpdateFromSystemType()
|
||||
{
|
||||
var system = SubmissionInfo?.CommonDiscInfo?.System;
|
||||
switch (system)
|
||||
{
|
||||
case RedumpSystem.SonyPlayStation2:
|
||||
Parent.LanguageSelectionGrid.Visibility = Visibility.Visible;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
/// <summary>
|
||||
/// Handler for AcceptButton Click event
|
||||
/// </summary>
|
||||
private void OnAcceptClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Save();
|
||||
Parent.DialogResult = true;
|
||||
Parent.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for CancelButton Click event
|
||||
/// </summary>
|
||||
private void OnCancelClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Parent.DialogResult = false;
|
||||
Parent.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for RingCodeGuideButton Click event
|
||||
/// </summary>
|
||||
private void OnRingCodeGuideClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var ringCodeGuideWindow = new RingCodeGuideWindow()
|
||||
{
|
||||
Owner = Parent,
|
||||
WindowStartupLocation = WindowStartupLocation.CenterOwner,
|
||||
};
|
||||
ringCodeGuideWindow.Show();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
577
MPF/ViewModels/LogViewModel.cs
Normal file
577
MPF/ViewModels/LogViewModel.cs
Normal file
@@ -0,0 +1,577 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Media;
|
||||
using MPF.Core.Data;
|
||||
using MPF.UserControls;
|
||||
|
||||
namespace MPF.GUI.ViewModels
|
||||
{
|
||||
public class LogViewModel
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// Parent OptionsWindow object
|
||||
/// </summary>
|
||||
public LogOutput Parent { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private State Variables
|
||||
|
||||
/// <summary>
|
||||
/// Paragraph backing the log
|
||||
/// </summary>
|
||||
private readonly Paragraph _paragraph;
|
||||
|
||||
/// <summary>
|
||||
/// Cached value of the last line written
|
||||
/// </summary>
|
||||
private Run lastLine = null;
|
||||
|
||||
/// <summary>
|
||||
/// Queue of items that need to be logged
|
||||
/// </summary>
|
||||
private readonly ProcessingQueue<LogLine> logQueue;
|
||||
|
||||
/// <summary>
|
||||
/// List of Matchers for progress tracking
|
||||
/// </summary>
|
||||
private readonly List<Matcher?> _matchers;
|
||||
|
||||
/// <summary>
|
||||
/// Cached value of the last matcher used
|
||||
/// </summary>
|
||||
private Matcher? lastUsedMatcher = null;
|
||||
|
||||
/// <summary>
|
||||
/// Regex pattern to find DiscImageCreator progress messages
|
||||
/// </summary>
|
||||
private const string DiscImageCreatorProgressPattern = @"\s*(\d+)\/\s*(\d+)$";
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public LogViewModel(LogOutput parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
// Add handlers
|
||||
Parent.OutputViewer.SizeChanged += OutputViewerSizeChanged;
|
||||
Parent.Output.TextChanged += OnTextChanged;
|
||||
Parent.ClearButton.Click += OnClearButton;
|
||||
Parent.SaveButton.Click += OnSaveButton;
|
||||
|
||||
// Update the internal state
|
||||
var document = new FlowDocument()
|
||||
{
|
||||
Background = new SolidColorBrush(Color.FromArgb(0xFF, 0x20, 0x20, 0x20))
|
||||
};
|
||||
_paragraph = new Paragraph();
|
||||
document.Blocks.Add(_paragraph);
|
||||
Parent.Output.Document = document;
|
||||
|
||||
// TODO: Can we dynamically add matchers *only* during dumping?
|
||||
_matchers = new List<Matcher?>();
|
||||
AddAaruMatchers();
|
||||
AddDiscImageCreatorMatchers();
|
||||
|
||||
logQueue = new ProcessingQueue<LogLine>(ProcessLogLine);
|
||||
}
|
||||
|
||||
#region Matching
|
||||
|
||||
/// <summary>
|
||||
/// Matching wrapper
|
||||
/// </summary>
|
||||
private struct Matcher
|
||||
{
|
||||
private readonly string prefix;
|
||||
private readonly Regex regex;
|
||||
private readonly int start;
|
||||
private readonly string progressBarText;
|
||||
private readonly Action<Match, string> lambda;
|
||||
|
||||
public Matcher(string prefix, string regex, string progressBarText, Action<Match, string> lambda)
|
||||
{
|
||||
this.prefix = prefix;
|
||||
this.regex = new Regex(regex);
|
||||
this.start = prefix.Length;
|
||||
this.progressBarText = progressBarText;
|
||||
this.lambda = lambda;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the text matches the prefix
|
||||
/// </summary>
|
||||
/// <param name="text">Text to check</param>
|
||||
/// <returns>True if the line starts with the prefix, false otherwise</returns>
|
||||
public bool Matches(string text) => text.StartsWith(prefix);
|
||||
|
||||
/// <summary>
|
||||
/// Generate a Match and apply the lambda
|
||||
/// </summary>
|
||||
/// <param name="text">Text to match and apply from</param>
|
||||
public void Apply(string text)
|
||||
{
|
||||
Match match = regex?.Match(text, start);
|
||||
lambda?.Invoke(match, progressBarText);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add all Matchers for Aaru
|
||||
/// </summary>
|
||||
private void AddAaruMatchers()
|
||||
{
|
||||
// TODO: Determine matchers that can be added
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add all Matchers for DiscImageCreator
|
||||
/// </summary>
|
||||
private void AddDiscImageCreatorMatchers()
|
||||
{
|
||||
#region Pre-dump Checking
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Checking EXE",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Checking executables...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Checking Pregap sync, msf, mode (LBA)",
|
||||
@"\s*-(\d+)$",
|
||||
"Checking Pregap sync, msf, mode",
|
||||
(match, text) =>
|
||||
{
|
||||
Parent.ProgressBar.Value = 0;
|
||||
Parent.ProgressLabel.Text = text;
|
||||
}));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Checking SubQ adr (Track)",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Checking SubQ adr...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Checking SubQ ctl (Track)",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Checking SubQ ctl...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Checking SubRtoW (Track)",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Checking SubRtoW...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Reading DirectoryRecord",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Reading directory records...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Scanning sector for anti-mod string (LBA)",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Scanning sectors for anti-mod string...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dumping
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
@"Creating iso(LBA)",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Creating ISO...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
@"Creating .scm (LBA)",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Creating scrambled image...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
#endregion
|
||||
|
||||
#region Post-Dump Processing
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Checking sectors:",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Checking for errors...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Creating bin (Track)",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Creating BIN(s)...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Creating cue and ccd (Track)",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Creating CUE and CCD...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Descrambling data sector of img:",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Descrambling image...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
_matchers.Add(new Matcher(
|
||||
"Scanning sector (LBA)",
|
||||
DiscImageCreatorProgressPattern,
|
||||
"Scanning sectors for protection...",
|
||||
StandardDiscImageCreatorProgress
|
||||
));
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Logging
|
||||
|
||||
/// <summary>
|
||||
/// Log level for output
|
||||
/// </summary>
|
||||
public enum LogLevel
|
||||
{
|
||||
USER,
|
||||
VERBOSE,
|
||||
ERROR,
|
||||
SECRET,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log line wrapper
|
||||
/// </summary>
|
||||
private struct LogLine
|
||||
{
|
||||
public readonly string Text;
|
||||
public readonly LogLevel LogLevel;
|
||||
|
||||
public LogLine(string text, LogLevel logLevel)
|
||||
{
|
||||
this.Text = text;
|
||||
this.LogLevel = logLevel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the foreground Brush for the current LogLevel
|
||||
/// </summary>
|
||||
/// <returns>Brush representing the color</returns>
|
||||
public Brush GetForegroundColor()
|
||||
{
|
||||
switch (this.LogLevel)
|
||||
{
|
||||
case LogLevel.SECRET:
|
||||
return Brushes.Blue;
|
||||
case LogLevel.ERROR:
|
||||
return Brushes.Red;
|
||||
case LogLevel.VERBOSE:
|
||||
return Brushes.Yellow;
|
||||
case LogLevel.USER:
|
||||
default:
|
||||
return Brushes.White;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a Run object from the current LogLine
|
||||
/// </summary>
|
||||
/// <returns>Run object based on internal values</returns>
|
||||
public Run GenerateRun()
|
||||
{
|
||||
return new Run { Text = this.Text, Foreground = GetForegroundColor() };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue text to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void Log(string text) => LogInternal(text);
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue text with a newline to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void LogLn(string text) => Log(text + "\n");
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue error text to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void ErrorLog(string text) => LogInternal(text, LogViewModel.LogLevel.ERROR);
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue error text with a newline to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void ErrorLogLn(string text) => ErrorLog(text + "\n");
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue secret text to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void SecretLog(string text) => LogInternal(text, LogViewModel.LogLevel.SECRET);
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue secret text with a newline to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void SecretLogLn(string text) => SecretLog(text + "\n");
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue verbose text to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void VerboseLog(string text) => LogInternal(text, LogViewModel.LogLevel.VERBOSE);
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue verbose text with a newline to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void VerboseLogLn(string text) => VerboseLog(text + "\n");
|
||||
|
||||
/// <summary>
|
||||
/// Reset the progress bar state
|
||||
/// </summary>
|
||||
public void ResetProgressBar()
|
||||
{
|
||||
Parent.Dispatcher.Invoke(() =>
|
||||
{
|
||||
Parent.ProgressBar.Value = 0;
|
||||
Parent.ProgressLabel.Text = string.Empty;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue text to the log with formatting
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
/// <param name="logLevel">LogLevel for the log, defaults to USER</param>
|
||||
private void LogInternal(string text, LogLevel logLevel = LogLevel.USER)
|
||||
{
|
||||
// Null text gets ignored
|
||||
if (text == null)
|
||||
return;
|
||||
|
||||
// If we have verbose logs but not enabled, ignore
|
||||
if (logLevel == LogLevel.VERBOSE && !App.Options.VerboseLogging)
|
||||
return;
|
||||
|
||||
// Enqueue the text
|
||||
logQueue.Enqueue(new LogLine(text, logLevel));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process the log lines in the queue
|
||||
/// </summary>
|
||||
/// <param name="nextLogLine">LogLine item to process</param>
|
||||
private void ProcessLogLine(LogLine nextLogLine)
|
||||
{
|
||||
// Null text gets ignored
|
||||
string nextText = Parent.Dispatcher.Invoke(() => nextLogLine.Text);
|
||||
if (nextText == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
// If we're not processing log formatting, just append and continue
|
||||
if (!App.Options.EnableLogFormatting)
|
||||
{
|
||||
if (nextText.StartsWith("\r"))
|
||||
ReplaceLastLine(nextLogLine);
|
||||
else
|
||||
AppendToTextBox(nextLogLine);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Get last line
|
||||
lastLine = lastLine ?? GetLastLine();
|
||||
|
||||
// Always append if there's no previous line
|
||||
if (lastLine == null)
|
||||
{
|
||||
AppendToTextBox(nextLogLine);
|
||||
lastUsedMatcher = _matchers.FirstOrDefault(m => m?.Matches(nextText) == true);
|
||||
}
|
||||
// Return always means overwrite
|
||||
else if (nextText.StartsWith("\r"))
|
||||
{
|
||||
ReplaceLastLine(nextLogLine);
|
||||
lastUsedMatcher = _matchers.FirstOrDefault(m => m?.Matches(nextText.TrimStart('\r')) == true);
|
||||
}
|
||||
// If we have a cached matcher and we match
|
||||
else if (lastUsedMatcher?.Matches(nextText) == true)
|
||||
{
|
||||
ReplaceLastLine(nextLogLine);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get the first matching Matcher
|
||||
var firstMatcher = _matchers.FirstOrDefault(m => m?.Matches(nextText) == true);
|
||||
if (firstMatcher.HasValue)
|
||||
{
|
||||
string lastText = Parent.Dispatcher.Invoke(() => { return lastLine.Text; });
|
||||
if (firstMatcher.Value.Matches(lastText))
|
||||
ReplaceLastLine(nextLogLine);
|
||||
else if (string.IsNullOrWhiteSpace(lastText))
|
||||
ReplaceLastLine(nextLogLine);
|
||||
else
|
||||
AppendToTextBox(nextLogLine);
|
||||
|
||||
// Cache the last used Matcher
|
||||
lastUsedMatcher = firstMatcher;
|
||||
}
|
||||
// Default case for all other text
|
||||
else
|
||||
{
|
||||
AppendToTextBox(nextLogLine);
|
||||
lastUsedMatcher = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the bar if needed
|
||||
if (App.Options.EnableProgressProcessing)
|
||||
ProcessStringForProgressBar(nextText, lastUsedMatcher);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// In the event that something fails horribly, we want to log
|
||||
AppendToTextBox(new LogLine(ex.ToString(), LogLevel.ERROR));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Append log line to the log text box
|
||||
/// </summary>
|
||||
/// <param name="logLine">LogLine value to append</param>
|
||||
private void AppendToTextBox(LogLine logLine)
|
||||
{
|
||||
Parent.Dispatcher.Invoke(() =>
|
||||
{
|
||||
var run = logLine.GenerateRun();
|
||||
_paragraph.Inlines.Add(run);
|
||||
lastLine = run;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the last line written to the log text box
|
||||
/// </summary>
|
||||
private Run GetLastLine()
|
||||
{
|
||||
return Parent.Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (!_paragraph.Inlines.Any())
|
||||
return null;
|
||||
|
||||
return _paragraph.Inlines.LastInline as Run;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process text if it should update the progress bar
|
||||
/// </summary>
|
||||
/// <param name="text">Text to check and update with</param>
|
||||
private void ProcessStringForProgressBar(string text, Matcher? matcher)
|
||||
{
|
||||
Parent.Dispatcher.Invoke(() => { matcher?.Apply(text); });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replace the last line written to the log text box
|
||||
/// </summary>
|
||||
/// <param name="logLine">LogLine value to append</param>
|
||||
private void ReplaceLastLine(LogLine logLine)
|
||||
{
|
||||
Parent.Dispatcher.Invoke(() =>
|
||||
{
|
||||
lastLine.Text = logLine.Text;
|
||||
lastLine.Foreground = logLine.GetForegroundColor();
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Scroll the current view to the bottom
|
||||
/// </summary>
|
||||
public void ScrollToBottom()
|
||||
{
|
||||
Parent.OutputViewer.ScrollToBottom();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region EventHandlers
|
||||
|
||||
private void OnClearButton(object sender, EventArgs e)
|
||||
{
|
||||
_paragraph.Inlines.Clear();
|
||||
ResetProgressBar();
|
||||
}
|
||||
|
||||
private void OnSaveButton(object sender, EventArgs e)
|
||||
{
|
||||
using (StreamWriter tw = new StreamWriter(File.OpenWrite("console.log")))
|
||||
{
|
||||
foreach (var inline in _paragraph.Inlines)
|
||||
{
|
||||
if (inline is Run run)
|
||||
tw.Write(run.Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTextChanged(object sender, TextChangedEventArgs e) =>
|
||||
ScrollToBottom();
|
||||
|
||||
private void OutputViewerSizeChanged(object sender, SizeChangedEventArgs e) =>
|
||||
ScrollToBottom();
|
||||
|
||||
private void StandardDiscImageCreatorProgress(Match match, string text)
|
||||
{
|
||||
if (uint.TryParse(match.Groups[1].Value, out uint current) && uint.TryParse(match.Groups[2].Value, out uint total))
|
||||
{
|
||||
float percentProgress = (current / (float)total) * 100;
|
||||
Parent.ProgressBar.Value = percentProgress;
|
||||
Parent.ProgressLabel.Text = string.Format($"{text} ({percentProgress:N2}%)");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
1503
MPF/ViewModels/MainViewModel.cs
Normal file
1503
MPF/ViewModels/MainViewModel.cs
Normal file
File diff suppressed because it is too large
Load Diff
264
MPF/ViewModels/OptionsViewModel.cs
Normal file
264
MPF/ViewModels/OptionsViewModel.cs
Normal file
@@ -0,0 +1,264 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Windows;
|
||||
using RedumpLib.Web;
|
||||
using WPFCustomMessageBox;
|
||||
|
||||
namespace MPF.GUI.ViewModels
|
||||
{
|
||||
public class OptionsViewModel
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// Parent OptionsWindow object
|
||||
/// </summary>
|
||||
public OptionsWindow Parent { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Current set of options
|
||||
/// </summary>
|
||||
public Options Options { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Flag for if settings were saved or not
|
||||
/// </summary>
|
||||
public bool SavedSettings { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Lists
|
||||
|
||||
/// <summary>
|
||||
/// List of available internal programs
|
||||
/// </summary>
|
||||
public List<Element<InternalProgram>> InternalPrograms => PopulateInternalPrograms();
|
||||
|
||||
/// <summary>
|
||||
/// Current list of supported system profiles
|
||||
/// </summary>
|
||||
public List<RedumpSystemComboBoxItem> Systems => RedumpSystemComboBoxItem.GenerateElements().ToList();
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public OptionsViewModel(OptionsWindow parent)
|
||||
{
|
||||
Parent = parent;
|
||||
Options = App.Options.Clone() as Options;
|
||||
|
||||
// Add handlers
|
||||
Parent.AaruPathButton.Click += BrowseForPathClick;
|
||||
Parent.DiscImageCreatorPathButton.Click += BrowseForPathClick;
|
||||
Parent.DDPathButton.Click += BrowseForPathClick;
|
||||
Parent.DefaultOutputPathButton.Click += BrowseForPathClick;
|
||||
|
||||
Parent.AcceptButton.Click += OnAcceptClick;
|
||||
Parent.CancelButton.Click += OnCancelClick;
|
||||
Parent.RedumpLoginTestButton.Click += OnRedumpTestClick;
|
||||
|
||||
// Update UI with new values
|
||||
Load();
|
||||
}
|
||||
|
||||
#region Load and Save
|
||||
|
||||
/// <summary>
|
||||
/// Load any options-related elements
|
||||
/// </summary>
|
||||
private void Load()
|
||||
{
|
||||
Parent.InternalProgramComboBox.SelectedIndex = InternalPrograms.FindIndex(r => r == Options.InternalProgram);
|
||||
Parent.DefaultSystemComboBox.SelectedIndex = Systems.FindIndex(r => r == Options.DefaultSystem);
|
||||
Parent.RedumpPasswordBox.Password = Options.RedumpPassword;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save any options-related elements
|
||||
/// </summary>
|
||||
private void Save()
|
||||
{
|
||||
var selectedInternalProgram = Parent.InternalProgramComboBox.SelectedItem as Element<InternalProgram>;
|
||||
Options.InternalProgram = selectedInternalProgram?.Value ?? InternalProgram.DiscImageCreator;
|
||||
var selectedDefaultSystem = Parent.DefaultSystemComboBox.SelectedItem as RedumpSystemComboBoxItem;
|
||||
Options.DefaultSystem = selectedDefaultSystem?.Value ?? null;
|
||||
Options.RedumpPassword = Parent.RedumpPasswordBox.Password;
|
||||
|
||||
SavedSettings = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Population
|
||||
|
||||
/// <summary>
|
||||
/// Get a complete list of supported internal programs
|
||||
/// </summary>
|
||||
private static List<Element<InternalProgram>> PopulateInternalPrograms()
|
||||
{
|
||||
var internalPrograms = new List<InternalProgram> { InternalProgram.DiscImageCreator, InternalProgram.Aaru, InternalProgram.DD };
|
||||
return internalPrograms.Select(ip => new Element<InternalProgram>(ip)).ToList();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI Commands
|
||||
|
||||
/// <summary>
|
||||
/// Browse and set a path based on the invoking button
|
||||
/// </summary>
|
||||
private void BrowseForPath(System.Windows.Controls.Button button)
|
||||
{
|
||||
// If the button is null, we can't do anything
|
||||
if (button == null)
|
||||
return;
|
||||
|
||||
// Strips button prefix to obtain the setting name
|
||||
string pathSettingName = button.Name.Substring(0, button.Name.IndexOf("Button"));
|
||||
|
||||
// TODO: hack for now, then we'll see
|
||||
bool shouldBrowseForPath = pathSettingName == "DefaultOutputPath";
|
||||
|
||||
string currentPath = TextBoxForPathSetting(pathSettingName)?.Text;
|
||||
string initialDirectory = AppDomain.CurrentDomain.BaseDirectory;
|
||||
if (!shouldBrowseForPath && !string.IsNullOrEmpty(currentPath))
|
||||
initialDirectory = Path.GetDirectoryName(Path.GetFullPath(currentPath));
|
||||
|
||||
CommonDialog dialog = shouldBrowseForPath
|
||||
? (CommonDialog)CreateFolderBrowserDialog()
|
||||
: CreateOpenFileDialog(initialDirectory);
|
||||
using (dialog)
|
||||
{
|
||||
DialogResult result = dialog.ShowDialog();
|
||||
if (result == DialogResult.OK)
|
||||
{
|
||||
string path = string.Empty;
|
||||
bool exists = false;
|
||||
|
||||
if (shouldBrowseForPath && dialog is FolderBrowserDialog folderBrowserDialog)
|
||||
{
|
||||
path = folderBrowserDialog.SelectedPath;
|
||||
exists = Directory.Exists(path);
|
||||
}
|
||||
else if (dialog is OpenFileDialog openFileDialog)
|
||||
{
|
||||
path = openFileDialog.FileName;
|
||||
exists = File.Exists(path);
|
||||
}
|
||||
|
||||
if (exists)
|
||||
{
|
||||
Options[pathSettingName] = path;
|
||||
TextBoxForPathSetting(pathSettingName).Text = path;
|
||||
}
|
||||
else
|
||||
{
|
||||
CustomMessageBox.Show(
|
||||
"Specified path doesn't exist!",
|
||||
"Error",
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Error
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Optionally save the current options and close the parent window
|
||||
/// </summary>
|
||||
private void OptionalSaveAndClose(bool save)
|
||||
{
|
||||
// Save if we're supposed to
|
||||
if (save)
|
||||
Save();
|
||||
|
||||
Parent.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test Redump login credentials
|
||||
/// </summary>
|
||||
private void TestRedumpLogin()
|
||||
{
|
||||
using (RedumpWebClient wc = new RedumpWebClient())
|
||||
{
|
||||
bool? loggedIn = wc.Login(Parent.RedumpUsernameTextBox.Text, Parent.RedumpPasswordBox.Password);
|
||||
if (loggedIn == true)
|
||||
CustomMessageBox.Show(Parent, "Redump login credentials accepted!", "Success", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
else if (loggedIn == false)
|
||||
CustomMessageBox.Show(Parent, "Redump login credentials denied!", "Failure", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
else
|
||||
CustomMessageBox.Show(Parent, "Error validating credentials!", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI Functionality
|
||||
|
||||
/// <summary>
|
||||
/// Create an open folder dialog box
|
||||
/// </summary>
|
||||
private static FolderBrowserDialog CreateFolderBrowserDialog() => new FolderBrowserDialog();
|
||||
|
||||
/// <summary>
|
||||
/// Create an open file dialog box
|
||||
/// </summary>
|
||||
private static OpenFileDialog CreateOpenFileDialog(string initialDirectory)
|
||||
{
|
||||
return new OpenFileDialog()
|
||||
{
|
||||
InitialDirectory = initialDirectory,
|
||||
Filter = "Executables (*.exe)|*.exe",
|
||||
FilterIndex = 0,
|
||||
RestoreDirectory = true,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find a TextBox by setting name
|
||||
/// </summary>
|
||||
/// <param name="name">Setting name to find</param>
|
||||
/// <returns>TextBox for that setting</returns>
|
||||
private System.Windows.Controls.TextBox TextBoxForPathSetting(string name) =>
|
||||
Parent.FindName(name + "TextBox") as System.Windows.Controls.TextBox;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
/// <summary>
|
||||
/// Handler for generic Click event
|
||||
/// </summary>
|
||||
private void BrowseForPathClick(object sender, EventArgs e) =>
|
||||
BrowseForPath(sender as System.Windows.Controls.Button);
|
||||
|
||||
/// <summary>
|
||||
/// Handler for AcceptButton Click event
|
||||
/// </summary>
|
||||
private void OnAcceptClick(object sender, EventArgs e) =>
|
||||
OptionalSaveAndClose(true);
|
||||
|
||||
/// <summary>
|
||||
/// Handler for CancelButtom Click event
|
||||
/// </summary>
|
||||
private void OnCancelClick(object sender, EventArgs e) =>
|
||||
OptionalSaveAndClose(false);
|
||||
|
||||
/// <summary>
|
||||
/// Test Redump credentials for validity
|
||||
/// </summary>
|
||||
private void OnRedumpTestClick(object sender, EventArgs e) =>
|
||||
TestRedumpLogin();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
<Window x:Class="MPF.Windows.DiscInformationWindow"
|
||||
<windows:WindowBase x:Class="MPF.Windows.DiscInformationWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:MPF"
|
||||
xmlns:controls="clr-namespace:MPF.UserControls"
|
||||
xmlns:windows="clr-namespace:MPF.Windows"
|
||||
mc:Ignorable="d"
|
||||
Title="Disc Information" Width="515" WindowStyle="None"
|
||||
WindowStartupLocation="CenterOwner" ResizeMode="CanMinimize" SizeToContent="Height"
|
||||
@@ -15,7 +15,7 @@
|
||||
</WindowChrome.WindowChrome>
|
||||
|
||||
<Grid>
|
||||
<StackPanel Orientation="Vertical" Width="500">
|
||||
<StackPanel Orientation="Vertical" Width="500" MaxHeight="650">
|
||||
<Grid Margin="0,10,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="25"/>
|
||||
@@ -67,133 +67,329 @@
|
||||
Foreground="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"
|
||||
Style="{DynamicResource CustomTabControlStyle}">
|
||||
<TabItem x:Name="CommonInfo" Header="Common Info" Style="{DynamicResource CustomTabItemStyle}">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<Expander Margin="5" Padding="5" BorderThickness="1" BorderBrush="LightGray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Common Disc Information" IsExpanded="True">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<controls:UserInput x:Name="GameTitle" Label="Title"/>
|
||||
<controls:UserInput x:Name="ForeignTitle" Label="Foreign Title (Non-Latin)"/>
|
||||
<controls:UserInput x:Name="DiscNumberLetter" Label="Disc Number / Letter"/>
|
||||
<controls:UserInput x:Name="DiscTitle" Label="Disc Title"/>
|
||||
<ScrollViewer CanContentScroll="False" VerticalScrollBarVisibility="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MaxHeight="500">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<GroupBox Header="Common Disc Information" Margin="5" Padding="5" BorderThickness="1" BorderBrush="LightGray"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<controls:UserInput Label="Title"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.Title, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="AlternativeTitleTextBox" Label="Alternative Title"/>
|
||||
<controls:UserInput Label="Foreign Title (Non-Latin)"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.ForeignTitleNonLatin, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="AlternativeForeignTitleTextBox" Label="Alternative Foreign Title"/>
|
||||
<controls:UserInput Label="Disc Number / Letter"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.DiscNumberLetter, Mode=TwoWay}"/>
|
||||
<controls:UserInput Label="Disc Title"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.DiscTitle, Mode=TwoWay}"/>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1.25*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="0.75*" />
|
||||
<ColumnDefinition Width="1.25*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label x:Name="CategoryLabel" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Category" />
|
||||
<ComboBox x:Name="CategoryComboBox" Grid.Row="0" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" ItemsSource="{Binding Categories}"
|
||||
SelectedIndex="0" Style="{DynamicResource CustomComboBoxStyle}" />
|
||||
</Grid>
|
||||
<Label x:Name="CategoryLabel" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Category" />
|
||||
<ComboBox x:Name="CategoryComboBox" Grid.Row="0" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" ItemsSource="{Binding Categories}"
|
||||
Style="{DynamicResource CustomComboBoxStyle}" />
|
||||
</Grid>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1.25*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="0.75*" />
|
||||
<ColumnDefinition Width="1.25*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label x:Name="RegionLabel" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Region" />
|
||||
<ComboBox x:Name="RegionComboBox" Grid.Row="0" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" ItemsSource="{Binding Regions}"
|
||||
SelectedIndex="0" Style="{DynamicResource CustomComboBoxStyle}" />
|
||||
</Grid>
|
||||
<Label x:Name="RegionLabel" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Region" />
|
||||
<ComboBox x:Name="RegionComboBox" Grid.Row="0" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" ItemsSource="{Binding Regions}"
|
||||
Style="{DynamicResource CustomComboBoxStyle}" />
|
||||
</Grid>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1.25*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="0.75*" />
|
||||
<ColumnDefinition Width="1.25*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label x:Name="LanguagesLabel" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Languages" />
|
||||
<ComboBox x:Name="LanguagesComboBox" Grid.Row="0" Grid.Column="1" Height="24" HorizontalAlignment="Stretch" ItemsSource="{Binding Languages}"
|
||||
SelectedIndex="0" Style="{DynamicResource CustomComboBoxStyle}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</Grid>
|
||||
<Label x:Name="LanguagesLabel" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Languages" />
|
||||
<ComboBox x:Name="LanguagesComboBox" Grid.Row="0" Grid.Column="1" Height="24" HorizontalAlignment="Stretch" ItemsSource="{Binding Languages}"
|
||||
SelectedIndex="0" Style="{DynamicResource CustomComboBoxStyle}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</Grid>
|
||||
|
||||
<Grid x:Name="LanguageSelectionGrid" Visibility="Collapsed">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1.25*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid x:Name="LanguageSelectionGrid" Visibility="Collapsed">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="0.75*" />
|
||||
<ColumnDefinition Width="1.25*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label x:Name="LanguageSelectionLabel" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Language Selection Via" />
|
||||
<ComboBox x:Name="LanguageSelectionComboBox" Grid.Row="0" Grid.Column="1" Height="24" HorizontalAlignment="Stretch" ItemsSource="{Binding LanguageSelections}"
|
||||
SelectedIndex="0" Style="{DynamicResource CustomComboBoxStyle}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</Grid>
|
||||
<Label x:Name="LanguageSelectionLabel" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Language Selection Via" />
|
||||
<ComboBox x:Name="LanguageSelectionComboBox" Grid.Row="0" Grid.Column="1" Height="24" HorizontalAlignment="Stretch" ItemsSource="{Binding LanguageSelections}"
|
||||
SelectedIndex="0" Style="{DynamicResource CustomComboBoxStyle}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</Grid>
|
||||
|
||||
<controls:UserInput x:Name="Serial" Label="Serial"/>
|
||||
<controls:UserInput x:Name="Barcode" Label="Barcode"/>
|
||||
<controls:UserInput x:Name="Comments" Label="Comments" TextHeight="50" Tab="True" Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top" />
|
||||
<controls:UserInput x:Name="Contents" Label="Contents" TextHeight="50" Tab="True" Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"/>
|
||||
</StackPanel>
|
||||
</Expander>
|
||||
<Expander Margin="5" Padding="5" BorderThickness="1" BorderBrush="LightGray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Version and Editions" IsExpanded="True">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<controls:UserInput x:Name="Version" Label="Version"/>
|
||||
<controls:UserInput x:Name="Edition" Label="Edition"/>
|
||||
</StackPanel>
|
||||
</Expander>
|
||||
</StackPanel>
|
||||
<controls:UserInput Label="Serial" Text="{Binding SubmissionInfo.CommonDiscInfo.Serial, Mode=TwoWay}"/>
|
||||
<controls:UserInput Label="Barcode" Text="{Binding SubmissionInfo.CommonDiscInfo.Barcode, Mode=TwoWay}"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Version and Editions" Margin="5" Padding="5" BorderThickness="1" BorderBrush="LightGray"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<controls:UserInput Label="Version" Text="{Binding SubmissionInfo.VersionAndEditions.Version, Mode=TwoWay}"/>
|
||||
<controls:UserInput Label="Edition" Text="{Binding SubmissionInfo.VersionAndEditions.OtherEditions, Mode=TwoWay}"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
|
||||
<TabItem x:Name="L0Info" Header="Data/L0 Info" Style="{DynamicResource CustomTabItemStyle}">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<controls:UserInput x:Name="L0MasteringRing" Label="Data/L0 Mastering Ring" Tab="True"/>
|
||||
<controls:UserInput x:Name="L0MasteringSID" Label="Data/L0 Mastering SID"/>
|
||||
<controls:UserInput x:Name="L0Toolstamp" Label="Data/L0 Toolstamp/Mastering Code"/>
|
||||
<controls:UserInput x:Name="L0MouldSID" Label="Data/L0 Mould SID"/>
|
||||
<controls:UserInput x:Name="L0AdditionalMould" Label="Data/L0 Additional Mould"/>
|
||||
</StackPanel>
|
||||
<TabItem Header="Additional Info" Style="{DynamicResource CustomTabItemStyle}">
|
||||
<ScrollViewer CanContentScroll="False" VerticalScrollBarVisibility="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MaxHeight="500">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<GroupBox Header="Extras" Margin="5" Padding="5" BorderThickness="1" BorderBrush="LightGray"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<controls:UserInput x:Name="CommentsTextBox" Label="Comments"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.Comments, Mode=TwoWay}" TextHeight="50"
|
||||
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top" />
|
||||
<controls:UserInput x:Name="GenreTextBox" Label="Genre"/>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="0.75*" />
|
||||
<ColumnDefinition Width="1.25*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label/>
|
||||
<CheckBox Grid.Column="1" x:Name="PostgapTypeCheckBox" Content="Postgap type (Form 2)" Margin="0,4"/>
|
||||
</Grid>
|
||||
<controls:UserInput x:Name="SeriesTextBox" Label="Series"/>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="0.75*" />
|
||||
<ColumnDefinition Width="1.25*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label/>
|
||||
<CheckBox Grid.Column="1" x:Name="VCDCheckBox" Content="V-CD" Margin="0,4"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Physical Identifiers" Margin="5" Padding="5" BorderThickness="1" BorderBrush="LightGray"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<controls:UserInput x:Name="BBFCRegistrationNumberTextBox" Label="BBFC Reg. No."/>
|
||||
<controls:UserInput x:Name="DiscHologramIDTextBox" Label="Disc Hologram ID"/>
|
||||
<controls:UserInput x:Name="DNASDiscIDTextBox" Label="DNAS Disc ID"/>
|
||||
<controls:UserInput x:Name="ISBNTextBox" Label="ISBN"/>
|
||||
<controls:UserInput x:Name="ISSNTextBox" Label="ISSN"/>
|
||||
<controls:UserInput x:Name="PPNTextBox" Label="PPN"/>
|
||||
<controls:UserInput x:Name="VFCCodeTextBox" Label="VFC code"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Publisher Identifiers" Margin="5" Padding="5" BorderThickness="1" BorderBrush="LightGray"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<controls:UserInput x:Name="AcclaimIDTextBox" Label="Acclaim ID"/>
|
||||
<controls:UserInput x:Name="ActivisionIDTextBox" Label="Activision ID"/>
|
||||
<controls:UserInput x:Name="BandaiIDTextBox" Label="Bandai ID"/>
|
||||
<controls:UserInput x:Name="ElectronicArtsIDTextBox" Label="Electronic Arts ID"/>
|
||||
<controls:UserInput x:Name="FoxInteractiveIDTextBox" Label="Fox Interactive ID"/>
|
||||
<controls:UserInput x:Name="GTInteractiveIDTextBox" Label="GT Interactive ID"/>
|
||||
<controls:UserInput x:Name="JASRACIDTextBox" Label="JASRAC ID"/>
|
||||
<controls:UserInput x:Name="KingRecordsIDTextBox" Label="King Records ID"/>
|
||||
<controls:UserInput x:Name="KoeiIDTextBox" Label="Koei ID"/>
|
||||
<controls:UserInput x:Name="KonamiIDTextBox" Label="Konami ID"/>
|
||||
<controls:UserInput x:Name="LucasArtsIDTextBox" Label="LucasArts ID"/>
|
||||
<controls:UserInput x:Name="MicrosoftIDTextBox" Label="Microsoft ID"/>
|
||||
<controls:UserInput x:Name="NaganoIDTextBox" Label="Nagano ID"/>
|
||||
<controls:UserInput x:Name="NamcoIDTextBox" Label="Namco ID"/>
|
||||
<controls:UserInput x:Name="NipponIchiSoftwareIDTextBox" Label="Nippon Ichi Software ID"/>
|
||||
<controls:UserInput x:Name="OriginIDTextBox" Label="Origin ID"/>
|
||||
<controls:UserInput x:Name="PonyCanyonIDTextBox" Label="Pony Canyon ID"/>
|
||||
<controls:UserInput x:Name="SegaIDTextBox" Label="Sega ID"/>
|
||||
<controls:UserInput x:Name="SelenIDTextBox" Label="Selen ID"/>
|
||||
<controls:UserInput x:Name="SierraIDTextBox" Label="Sierra ID"/>
|
||||
<controls:UserInput x:Name="TaitoIDTextBox" Label="Taito ID"/>
|
||||
<controls:UserInput x:Name="UbisoftIDTextBox" Label="Ubisoft ID"/>
|
||||
<controls:UserInput x:Name="ValveIDTextBox" Label="Valve ID"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
|
||||
<TabItem x:Name="L1Info" Header="Label/L1 Info" Style="{DynamicResource CustomTabItemStyle}">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<controls:UserInput x:Name="L1MasteringRing" Label="Label/L1 Mastering Ring" Tab="True"/>
|
||||
<controls:UserInput x:Name="L1MasteringSID" Label="Label/L1 Mastering SID"/>
|
||||
<controls:UserInput x:Name="L1Toolstamp" Label="Label/L1 Toolstamp/Mastering Code"/>
|
||||
<controls:UserInput x:Name="L1MouldSID" Label="Label/L1 Mould SID"/>
|
||||
<controls:UserInput x:Name="L1AdditionalMould" Label="Label/L1 Additional Mould"/>
|
||||
</StackPanel>
|
||||
<TabItem Header="Contents" Style="{DynamicResource CustomTabItemStyle}">
|
||||
<ScrollViewer CanContentScroll="False" VerticalScrollBarVisibility="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MaxHeight="500">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<controls:UserInput x:Name="GeneralContent" Label="General"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.Contents, Mode=TwoWay}" TextHeight="50"
|
||||
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"/>
|
||||
|
||||
<!-- Games -->
|
||||
<controls:UserInput x:Name="GamesTextBox" Label="Games" TextHeight="50"
|
||||
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"/>
|
||||
<controls:UserInput x:Name="NetYarozeGamesTextBox" Label="Net Yaroze Games" TextHeight="50"
|
||||
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"/>
|
||||
|
||||
<!-- Demos -->
|
||||
<controls:UserInput x:Name="PlayableDemosTextBox" Label="Playable Demos" TextHeight="50"
|
||||
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"/>
|
||||
<controls:UserInput x:Name="RollingDemosTextBox" Label="Rolling Demos" TextHeight="50"
|
||||
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"/>
|
||||
<controls:UserInput x:Name="TechDemosTextBox" Label="Tech Demos" TextHeight="50"
|
||||
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"/>
|
||||
|
||||
<!-- Video -->
|
||||
<controls:UserInput x:Name="GameFootageTextBox" Label="Game Footage" TextHeight="50"
|
||||
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"/>
|
||||
<controls:UserInput x:Name="VideosTextBox" Label="Videos" TextHeight="50"
|
||||
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"/>
|
||||
|
||||
<!-- Miscellaneous -->
|
||||
<controls:UserInput x:Name="PatchesTextBox" Label="Patches" TextHeight="50"
|
||||
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"/>
|
||||
<controls:UserInput x:Name="SavegamesTextBox" Label="Savegames" TextHeight="50"
|
||||
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"/>
|
||||
<controls:UserInput x:Name="ExtrasTextBox" Label="Extras" TextHeight="50"
|
||||
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"/>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
|
||||
<TabItem x:Name="L2Info" Header="L2 Info" Visibility="Collapsed" Style="{DynamicResource CustomTabItemStyle}">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<controls:UserInput x:Name="L2MasteringRing" Label="L2 Mastering Ring" Tab="True"/>
|
||||
<controls:UserInput x:Name="L2MasteringSID" Label="L2 Mastering SID"/>
|
||||
<controls:UserInput x:Name="L2Toolstamp" Label="L2 Toolstamp/Mastering Code"/>
|
||||
</StackPanel>
|
||||
<TabItem Header="Ringcodes" Style="{DynamicResource CustomTabItemStyle}">
|
||||
<ScrollViewer CanContentScroll="False" VerticalScrollBarVisibility="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MaxHeight="500">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<GroupBox x:Name="L0Info" Header="Data/L0 Info" Margin="5" Padding="5" BorderThickness="1" BorderBrush="LightGray"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<controls:UserInput x:Name="L0MasteringRing" Label="Data/L0 Mastering Ring"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.Layer0MasteringRing, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="L0MasteringSID" Label="Data/L0 Mastering SID"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.Layer0MasteringSID, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="L0Toolstamp" Label="Data/L0 Toolstamp/Mastering Code"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.Layer0ToolstampMasteringCode, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="L0MouldSID" Label="Data/L0 Mould SID"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.Layer0MouldSID, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="L0AdditionalMould" Label="Data/L0 Additional Mould"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.Layer0AdditionalMould, Mode=TwoWay}"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox x:Name="L1Info" Header="Label/L1 Info" Margin="5" Padding="5" BorderThickness="1" BorderBrush="LightGray"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<controls:UserInput x:Name="L1MasteringRing" Label="Label/L1 Mastering Ring"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.Layer1MasteringRing, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="L1MasteringSID" Label="Label/L1 Mastering SID"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.Layer1MasteringSID, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="L1Toolstamp" Label="Label/L1 Toolstamp/Mastering Code"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.Layer1ToolstampMasteringCode, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="L1MouldSID" Label="Label/L1 Mould SID"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.Layer1MouldSID, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="L1AdditionalMould" Label="Label/L1 Additional Mould"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.Layer1AdditionalMould, Mode=TwoWay}"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox x:Name="L2Info" Header="L2 Info" Visibility="Collapsed" Margin="5" Padding="5" BorderThickness="1" BorderBrush="LightGray"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<controls:UserInput x:Name="L2MasteringRing" Label="L2 Mastering Ring"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.Layer2MasteringRing, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="L2MasteringSID" Label="L2 Mastering SID"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.Layer2MasteringSID, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="L2Toolstamp" Label="L2 Toolstamp/Mastering Code"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.Layer2ToolstampMasteringCode, Mode=TwoWay}"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox x:Name="L3Info" Header="L3 Info" Visibility="Collapsed" Margin="5" Padding="5" BorderThickness="1" BorderBrush="LightGray"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<controls:UserInput x:Name="L3MasteringRing" Label="L3 Mastering Ring"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.Layer3MasteringRing, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="L3MasteringSID" Label="L3 Mastering SID"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.Layer3MasteringSID, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="L3Toolstamp" Label="L3 Toolstamp/Mastering Code"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.Layer3ToolstampMasteringCode, Mode=TwoWay}"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
|
||||
<TabItem x:Name="L3Info" Header="L3 Info" Visibility="Collapsed" Style="{DynamicResource CustomTabItemStyle}">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<controls:UserInput x:Name="L3MasteringRing" Label="L3 Mastering Ring" Tab="True"/>
|
||||
<controls:UserInput x:Name="L3MasteringSID" Label="L3 Mastering SID"/>
|
||||
<controls:UserInput x:Name="L3Toolstamp" Label="L3 Toolstamp/Mastering Code"/>
|
||||
</StackPanel>
|
||||
<TabItem Header="Read-Only Info" Style="{DynamicResource CustomTabItemStyle}">
|
||||
<ScrollViewer CanContentScroll="False" VerticalScrollBarVisibility="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MaxHeight="500">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<controls:UserInput x:Name="MatchedIDs" Label="Matched ID(s)" IsReadOnly="True"/>
|
||||
<controls:UserInput x:Name="AntiModchip" Label="Anti-Modchip" IsReadOnly="True"/>
|
||||
<controls:UserInput x:Name="DMIHash" Label="DMI Hash" IsReadOnly="True"/>
|
||||
<controls:UserInput x:Name="EDC" Label="EDC" IsReadOnly="True"/>
|
||||
<controls:UserInput x:Name="ErrorsCount" Label="Error(s) Count" IsReadOnly="True"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.ErrorsCount, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="EXEDateBuildDate" Label="EXE/Build Date" IsReadOnly="True"
|
||||
Text="{Binding SubmissionInfo.CommonDiscInfo.EXEDateBuildDate, Mode=TwoWay}"/>
|
||||
<controls:UserInput x:Name="Header" Label="Header" IsReadOnly="True"
|
||||
Text="{Binding SubmissionInfo.Extras.Header, Mode=TwoWay}" TextHeight="75" TextWrapping="NoWrap"
|
||||
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>
|
||||
<controls:UserInput x:Name="InternalSerialName" Label="Internal Serial" IsReadOnly="True"/>
|
||||
<controls:UserInput x:Name="LibCrypt" Label="LibCrypt" IsReadOnly="True"/>
|
||||
<controls:UserInput x:Name="LibCryptData" Label="LibCrypt Data" IsReadOnly="True"
|
||||
Text="{Binding SubmissionInfo.CopyProtection.LibCryptData, Mode=TwoWay}" TextHeight="75" TextWrapping="NoWrap"
|
||||
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>
|
||||
<controls:UserInput x:Name="PFIHash" Label="PFI Hash" IsReadOnly="True"/>
|
||||
<controls:UserInput x:Name="PIC" Label="PIC" IsReadOnly="True"
|
||||
Text="{Binding SubmissionInfo.Extras.PIC, Mode=TwoWay}" TextHeight="75" TextWrapping="NoWrap"
|
||||
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>
|
||||
<controls:UserInput x:Name="Protection" Label="Protection" IsReadOnly="True"
|
||||
Text="{Binding SubmissionInfo.CopyProtection.Protection, Mode=TwoWay}" TextHeight="75" TextWrapping="Wrap"
|
||||
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>
|
||||
<controls:UserInput x:Name="PVD" Label="PVD" IsReadOnly="True"
|
||||
Text="{Binding SubmissionInfo.Extras.PVD, Mode=TwoWay}" TextHeight="75" TextWrapping="NoWrap"
|
||||
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>
|
||||
<controls:UserInput x:Name="SecuROMData" Label="SecuROM Data" IsReadOnly="True"
|
||||
Text="{Binding SubmissionInfo.CopyProtection.SecuROMData, Mode=TwoWay}" TextHeight="75" TextWrapping="NoWrap"
|
||||
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>
|
||||
<controls:UserInput x:Name="SSHash" Label="Security Sector Hash" IsReadOnly="True"/>
|
||||
<controls:UserInput x:Name="SecuritySectorRanges" Label="Security Sector Ranges" IsReadOnly="True"
|
||||
Text="{Binding SubmissionInfo.Extras.SecuritySectorRanges, Mode=TwoWay}" TextHeight="75" TextWrapping="NoWrap"
|
||||
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>
|
||||
<controls:UserInput x:Name="SSVersion" Label="Security Sector Version" IsReadOnly="True"/>
|
||||
<controls:UserInput x:Name="VolumeLabel" Label="Volume Label" IsReadOnly="True"/>
|
||||
<controls:UserInput x:Name="XeMID" Label="XeMID" IsReadOnly="True"/>
|
||||
<controls:UserInput x:Name="XMID" Label="XMID" IsReadOnly="True"/>
|
||||
|
||||
<!-- TODO: Add track/checksum data once there's a reasonable way to do so -->
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
|
||||
<!-- Accept / Cancel -->
|
||||
<GroupBox Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<UniformGrid Columns="3" Margin="5,5,5,5" Height="28">
|
||||
<Button Name="AcceptButton" Grid.Column="0" Height="25" Width="120" IsDefault="True" Content="Accept"
|
||||
Click="OnAcceptClick" Style="{DynamicResource CustomButtonStyle}" />
|
||||
<Button Name="CancelButton" Grid.Column="1" Height="25" Width="120" IsCancel="True" Content="Cancel"
|
||||
Click="OnCancelClick" Style="{DynamicResource CustomButtonStyle}" />
|
||||
<Button Name="AcceptButton" Height="25" Width="80" Content="Accept"
|
||||
Style="{DynamicResource CustomButtonStyle}" />
|
||||
<Button Name="CancelButton" Height="25" Width="80" Content="Cancel"
|
||||
Style="{DynamicResource CustomButtonStyle}" />
|
||||
<Button Name="RingCodeGuideButton" Grid.Column="2" Height="25" Width="120" Content="Ring Code Guide"
|
||||
Click="OnRingCodeGuideClick" Style="{DynamicResource CustomButtonStyle}" />
|
||||
Style="{DynamicResource CustomButtonStyle}" />
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
</windows:WindowBase>
|
||||
|
||||
@@ -1,355 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using MPF.Data;
|
||||
using MPF.GUI.ViewModels;
|
||||
using RedumpLib.Data;
|
||||
|
||||
namespace MPF.Windows
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for DiscInformationWindow.xaml
|
||||
/// </summary>
|
||||
public partial class DiscInformationWindow : Window
|
||||
public partial class DiscInformationWindow : WindowBase
|
||||
{
|
||||
#region Fields
|
||||
/// <summary>
|
||||
/// Read-only access to the current disc information view model
|
||||
/// </summary>
|
||||
public DiscInformationViewModel DiscInformationViewModel => DataContext as DiscInformationViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// List of available disc categories
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public List<Element<RedumpDiscCategory>> Categories { get; private set; } = Element<RedumpDiscCategory>.GenerateElements().ToList();
|
||||
|
||||
/// <summary>
|
||||
/// SubmissionInfo object to fill and save
|
||||
/// </summary>
|
||||
public SubmissionInfo SubmissionInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of available regions
|
||||
/// </summary>
|
||||
public List<Element<RedumpRegion>> Regions { get; private set; } = Element<RedumpRegion>.GenerateElements().ToList();
|
||||
|
||||
/// <summary>
|
||||
/// List of available languages
|
||||
/// </summary>
|
||||
public List<Element<RedumpLanguage>> Languages { get; private set; } = Element<RedumpLanguage>.GenerateElements().ToList();
|
||||
|
||||
/// <summary>
|
||||
/// List of available languages
|
||||
/// </summary>
|
||||
public List<Element<RedumpLanguageSelection>> LanguageSelections { get; private set; } = Element<RedumpLanguageSelection>.GenerateElements().ToList();
|
||||
|
||||
#endregion
|
||||
|
||||
public DiscInformationWindow(SubmissionInfo submissionInfo)
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = this;
|
||||
|
||||
this.SubmissionInfo = submissionInfo;
|
||||
ManipulateFields();
|
||||
Load();
|
||||
DataContext = new DiscInformationViewModel(this, submissionInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manipulate fields based on the current disc
|
||||
/// </summary>
|
||||
private void ManipulateFields()
|
||||
{
|
||||
// Sony-printed discs have layers in the opposite order
|
||||
var system = SubmissionInfo?.CommonDiscInfo?.System;
|
||||
bool reverseOrder = (system == KnownSystem.SonyPlayStation2
|
||||
|| system == KnownSystem.SonyPlayStation3
|
||||
|| system == KnownSystem.SonyPlayStation4
|
||||
|| system == KnownSystem.SonyPlayStation5);
|
||||
|
||||
// Different media types mean different fields available
|
||||
switch (SubmissionInfo?.CommonDiscInfo?.Media)
|
||||
{
|
||||
case MediaType.CDROM:
|
||||
case MediaType.GDROM:
|
||||
L0Info.Header = "Data Side";
|
||||
L0MasteringRing.Label = "Mastering Ring";
|
||||
L0MasteringSID.Label = "Mastering SID";
|
||||
L0Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
L0MouldSID.Label = "Mould SID";
|
||||
L0AdditionalMould.Label = "Additional Mould";
|
||||
|
||||
L1Info.Header = "Label Side";
|
||||
L1MasteringRing.Visibility = Visibility.Collapsed;
|
||||
L1MasteringSID.Visibility = Visibility.Collapsed;
|
||||
L1Toolstamp.Visibility = Visibility.Collapsed;
|
||||
L1MouldSID.Label = "Mould SID";
|
||||
L1AdditionalMould.Label = "Additional Mould";
|
||||
break;
|
||||
|
||||
case MediaType.DVD:
|
||||
case MediaType.HDDVD:
|
||||
case MediaType.BluRay:
|
||||
case MediaType.NintendoGameCubeGameDisc:
|
||||
case MediaType.NintendoWiiOpticalDisc:
|
||||
case MediaType.NintendoWiiUOpticalDisc:
|
||||
// Quad-layer discs
|
||||
if (SubmissionInfo?.SizeAndChecksums?.Layerbreak3 != default(long))
|
||||
{
|
||||
L2Info.Visibility = Visibility.Visible;
|
||||
L3Info.Visibility = Visibility.Visible;
|
||||
|
||||
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 = "Layer 1";
|
||||
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";
|
||||
|
||||
L2Info.Header = "Layer 2";
|
||||
L2MasteringRing.Label = "Mastering Ring";
|
||||
L2MasteringSID.Label = "Mastering SID";
|
||||
L2Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
|
||||
L3Info.Header = reverseOrder ? "Layer 3 (Inner)" : "Layer 3 (Outer)";
|
||||
L3MasteringRing.Label = "Mastering Ring";
|
||||
L3MasteringSID.Label = "Mastering SID";
|
||||
L3Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
}
|
||||
|
||||
// Triple-layer discs
|
||||
else if (SubmissionInfo?.SizeAndChecksums?.Layerbreak2 != default(long))
|
||||
{
|
||||
L2Info.Visibility = Visibility.Visible;
|
||||
|
||||
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 = "Layer 1";
|
||||
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";
|
||||
|
||||
L2Info.Header = reverseOrder ? "Layer 2 (Inner)" : "Layer 2 (Outer)";
|
||||
L2MasteringRing.Label = "Mastering Ring";
|
||||
L2MasteringSID.Label = "Mastering SID";
|
||||
L2Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
}
|
||||
|
||||
// Double-layer discs
|
||||
else if (SubmissionInfo?.SizeAndChecksums?.Layerbreak != default(long))
|
||||
{
|
||||
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";
|
||||
}
|
||||
|
||||
// Single-layer discs
|
||||
else
|
||||
{
|
||||
L0Info.Header = "Data Side";
|
||||
L0MasteringRing.Label = "Mastering Ring";
|
||||
L0MasteringSID.Label = "Mastering SID";
|
||||
L0Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
L0MouldSID.Label = "Mould SID";
|
||||
L0AdditionalMould.Label = "Additional Mould";
|
||||
|
||||
L1Info.Header = "Label Side";
|
||||
L1MasteringRing.Label = "Mastering Ring";
|
||||
L1MasteringSID.Label = "Mastering SID";
|
||||
L1Toolstamp.Label = "Toolstamp/Mastering Code";
|
||||
L1MouldSID.Label = "Mould SID";
|
||||
L1AdditionalMould.Label = "Additional Mould";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// All other media we assume to have no rings
|
||||
default:
|
||||
L0Info.Visibility = Visibility.Collapsed;
|
||||
L1Info.Visibility = Visibility.Collapsed;
|
||||
L2Info.Visibility = Visibility.Collapsed;
|
||||
L3Info.Visibility = Visibility.Collapsed;
|
||||
break;
|
||||
}
|
||||
|
||||
// Different systems mean different fields available
|
||||
switch (system)
|
||||
{
|
||||
case KnownSystem.SonyPlayStation2:
|
||||
LanguageSelectionGrid.Visibility = Visibility.Visible;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load the current contents of the base SubmissionInfo to the UI
|
||||
/// </summary>
|
||||
private void Load()
|
||||
{
|
||||
GameTitle.Text = SubmissionInfo.CommonDiscInfo.Title ?? "";
|
||||
ForeignTitle.Text = SubmissionInfo.CommonDiscInfo.ForeignTitleNonLatin ?? "";
|
||||
DiscNumberLetter.Text = SubmissionInfo.CommonDiscInfo.DiscNumberLetter ?? "";
|
||||
DiscTitle.Text = SubmissionInfo.CommonDiscInfo.DiscTitle ?? "";
|
||||
CategoryComboBox.SelectedIndex = Categories.FindIndex(r => r == SubmissionInfo.CommonDiscInfo.Category);
|
||||
RegionComboBox.SelectedIndex = Regions.FindIndex(r => r == SubmissionInfo.CommonDiscInfo.Region);
|
||||
if (SubmissionInfo.CommonDiscInfo.Languages != null)
|
||||
Languages.ForEach(l => l.IsChecked = SubmissionInfo.CommonDiscInfo.Languages.Contains(l));
|
||||
if (SubmissionInfo.CommonDiscInfo.LanguageSelection != null)
|
||||
LanguageSelections.ForEach(ls => ls.IsChecked = SubmissionInfo.CommonDiscInfo.LanguageSelection.Contains(ls));
|
||||
Serial.Text = SubmissionInfo.CommonDiscInfo.Serial ?? "";
|
||||
|
||||
L0MasteringRing.Text = SubmissionInfo.CommonDiscInfo.Layer0MasteringRing ?? "";
|
||||
L0MasteringSID.Text = SubmissionInfo.CommonDiscInfo.Layer0MasteringSID ?? "";
|
||||
L0Toolstamp.Text = SubmissionInfo.CommonDiscInfo.Layer0ToolstampMasteringCode ?? "";
|
||||
L0MouldSID.Text = SubmissionInfo.CommonDiscInfo.Layer0MouldSID ?? "";
|
||||
L0AdditionalMould.Text = SubmissionInfo.CommonDiscInfo.Layer0AdditionalMould ?? "";
|
||||
|
||||
L1MasteringRing.Text = SubmissionInfo.CommonDiscInfo.Layer1MasteringRing ?? "";
|
||||
L1MasteringSID.Text = SubmissionInfo.CommonDiscInfo.Layer1MasteringSID ?? "";
|
||||
L1Toolstamp.Text = SubmissionInfo.CommonDiscInfo.Layer1ToolstampMasteringCode ?? "";
|
||||
L1MouldSID.Text = SubmissionInfo.CommonDiscInfo.Layer1MouldSID ?? "";
|
||||
L1AdditionalMould.Text = SubmissionInfo.CommonDiscInfo.Layer1AdditionalMould ?? "";
|
||||
|
||||
L2MasteringRing.Text = SubmissionInfo.CommonDiscInfo.Layer2MasteringRing ?? "";
|
||||
L2MasteringSID.Text = SubmissionInfo.CommonDiscInfo.Layer2MasteringSID ?? "";
|
||||
L2Toolstamp.Text = SubmissionInfo.CommonDiscInfo.Layer2ToolstampMasteringCode ?? ""; ;
|
||||
|
||||
L3MasteringRing.Text = SubmissionInfo.CommonDiscInfo.Layer3MasteringRing ?? "";
|
||||
L3MasteringSID.Text = SubmissionInfo.CommonDiscInfo.Layer3MasteringSID ?? "";
|
||||
L3Toolstamp.Text = SubmissionInfo.CommonDiscInfo.Layer3ToolstampMasteringCode ?? "";
|
||||
|
||||
Barcode.Text = SubmissionInfo.CommonDiscInfo.Barcode ?? "";
|
||||
Comments.Text = SubmissionInfo.CommonDiscInfo.Comments ?? "";
|
||||
Contents.Text = SubmissionInfo.CommonDiscInfo.Contents ?? "";
|
||||
|
||||
Version.Text = SubmissionInfo.VersionAndEditions.Version ?? "";
|
||||
Edition.Text = SubmissionInfo.VersionAndEditions.OtherEditions ?? "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save the current contents of the UI to the base SubmissionInfo
|
||||
/// </summary>
|
||||
private void Save()
|
||||
{
|
||||
SubmissionInfo.CommonDiscInfo.Title = GameTitle.Text ?? "";
|
||||
SubmissionInfo.CommonDiscInfo.ForeignTitleNonLatin = ForeignTitle.Text ?? "";
|
||||
SubmissionInfo.CommonDiscInfo.DiscNumberLetter = DiscNumberLetter.Text ?? "";
|
||||
SubmissionInfo.CommonDiscInfo.DiscTitle = DiscTitle.Text ?? "";
|
||||
SubmissionInfo.CommonDiscInfo.Category = (CategoryComboBox.SelectedItem as Element<RedumpDiscCategory>)?.Value ?? RedumpDiscCategory.Games;
|
||||
SubmissionInfo.CommonDiscInfo.Region = (RegionComboBox.SelectedItem as Element<RedumpRegion>)?.Value ?? RedumpRegion.World;
|
||||
SubmissionInfo.CommonDiscInfo.Languages = Languages.Where(l => l.IsChecked).Select(l => l?.Value).ToArray();
|
||||
if (!SubmissionInfo.CommonDiscInfo.Languages.Any())
|
||||
SubmissionInfo.CommonDiscInfo.Languages = new RedumpLanguage?[] { null };
|
||||
SubmissionInfo.CommonDiscInfo.LanguageSelection = LanguageSelections.Where(ls => ls.IsChecked).Select(ls => ls?.Value).ToArray();
|
||||
SubmissionInfo.CommonDiscInfo.Serial = Serial.Text ?? "";
|
||||
SubmissionInfo.CommonDiscInfo.Layer0MasteringRing = L0MasteringRing.Text ?? "";
|
||||
SubmissionInfo.CommonDiscInfo.Layer0MasteringSID = L0MasteringSID.Text ?? "";
|
||||
SubmissionInfo.CommonDiscInfo.Layer0ToolstampMasteringCode = L0Toolstamp.Text ?? "";
|
||||
SubmissionInfo.CommonDiscInfo.Layer0MouldSID = L0MouldSID.Text ?? "";
|
||||
SubmissionInfo.CommonDiscInfo.Layer0AdditionalMould = L0AdditionalMould.Text ?? "";
|
||||
|
||||
SubmissionInfo.CommonDiscInfo.Layer1MasteringRing = L1MasteringRing.Text ?? "";
|
||||
SubmissionInfo.CommonDiscInfo.Layer1MasteringSID = L1MasteringSID.Text ?? "";
|
||||
SubmissionInfo.CommonDiscInfo.Layer1ToolstampMasteringCode = L1Toolstamp.Text ?? "";
|
||||
SubmissionInfo.CommonDiscInfo.Layer1MouldSID = L1MouldSID.Text ?? "";
|
||||
SubmissionInfo.CommonDiscInfo.Layer1AdditionalMould = L1AdditionalMould.Text ?? "";
|
||||
|
||||
SubmissionInfo.CommonDiscInfo.Layer2MasteringRing = L2MasteringRing.Text ?? "";
|
||||
SubmissionInfo.CommonDiscInfo.Layer2MasteringSID = L2MasteringSID.Text ?? "";
|
||||
SubmissionInfo.CommonDiscInfo.Layer2ToolstampMasteringCode = L2Toolstamp.Text ?? "";
|
||||
|
||||
SubmissionInfo.CommonDiscInfo.Layer3MasteringRing = L3MasteringRing.Text ?? "";
|
||||
SubmissionInfo.CommonDiscInfo.Layer3MasteringSID = L3MasteringSID.Text ?? "";
|
||||
SubmissionInfo.CommonDiscInfo.Layer3ToolstampMasteringCode = L3Toolstamp.Text ?? "";
|
||||
|
||||
SubmissionInfo.CommonDiscInfo.Barcode = Barcode.Text ?? "";
|
||||
SubmissionInfo.CommonDiscInfo.Comments = Comments.Text ?? "";
|
||||
SubmissionInfo.CommonDiscInfo.Contents = Contents.Text ?? "";
|
||||
|
||||
SubmissionInfo.VersionAndEditions.Version = this.Version.Text ?? "";
|
||||
SubmissionInfo.VersionAndEditions.OtherEditions = Edition.Text ?? "";
|
||||
}
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
/// <summary>
|
||||
/// Handler for CloseButton Click event
|
||||
/// </summary>
|
||||
private void CloseButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.DialogResult = false;
|
||||
Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for MinimizeButton Click event
|
||||
/// </summary>
|
||||
private void MinimizeButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.WindowState = WindowState.Minimized;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for AcceptButton Click event
|
||||
/// </summary>
|
||||
private void OnAcceptClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Save();
|
||||
this.DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for CancelButton Click event
|
||||
/// </summary>
|
||||
private void OnCancelClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.DialogResult = false;
|
||||
Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for RingCodeGuideButton Click event
|
||||
/// </summary>
|
||||
private void OnRingCodeGuideClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var ringCodeGuideWindow = new RingCodeGuideWindow()
|
||||
{
|
||||
Owner = this,
|
||||
WindowStartupLocation = WindowStartupLocation.CenterOwner,
|
||||
};
|
||||
ringCodeGuideWindow.Show();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for Title MouseDown event
|
||||
/// </summary>
|
||||
private void TitleMouseDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.ChangedButton == MouseButton.Left)
|
||||
this.DragMove();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<Window x:Class="MPF.Windows.MainWindow"
|
||||
<windows:WindowBase x:Class="MPF.Windows.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:MPF"
|
||||
xmlns:controls="clr-namespace:MPF.UserControls"
|
||||
xmlns:viewModels="clr-namespace:MPF.GUI.ViewModels"
|
||||
xmlns:windows="clr-namespace:MPF.Windows"
|
||||
mc:Ignorable="d"
|
||||
Title="Media Preservation Frontend" Width="600" WindowStyle="None"
|
||||
WindowStartupLocation="CenterScreen" ResizeMode="CanMinimize" SizeToContent="Height"
|
||||
@@ -13,7 +14,11 @@
|
||||
<WindowChrome.WindowChrome>
|
||||
<WindowChrome CaptionHeight="0" ResizeBorderThickness="0" />
|
||||
</WindowChrome.WindowChrome>
|
||||
|
||||
|
||||
<Window.DataContext>
|
||||
<viewModels:MainViewModel/>
|
||||
</Window.DataContext>
|
||||
|
||||
<Grid>
|
||||
<StackPanel Orientation="Vertical">
|
||||
<Grid Margin="0,2,0,0">
|
||||
@@ -35,7 +40,7 @@
|
||||
Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
|
||||
Foreground="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"
|
||||
Template="{DynamicResource CustomMenuItemTemplate}">
|
||||
<MenuItem x:Name="AppExitMenuItem" Header="E_xit" HorizontalAlignment="Left" Width="185" Click="AppExitClick"
|
||||
<MenuItem x:Name="AppExitMenuItem" Header="E_xit" HorizontalAlignment="Left" Width="185"
|
||||
Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
|
||||
Foreground="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"
|
||||
Template="{DynamicResource CustomMenuItemTemplate}" />
|
||||
@@ -44,20 +49,24 @@
|
||||
Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
|
||||
Foreground="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"
|
||||
Template="{DynamicResource CustomMenuItemTemplate}">
|
||||
<MenuItem x:Name="OptionsMenuItem" Header="_Options" HorizontalAlignment="Left" Width="185" Click="OptionsMenuItemClick"
|
||||
<MenuItem x:Name="OptionsMenuItem" Header="_Options" HorizontalAlignment="Left" Width="185"
|
||||
Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
|
||||
Foreground="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"
|
||||
Template="{DynamicResource CustomMenuItemTemplate}" />
|
||||
<MenuItem x:Name="DebugViewMenuItem" Header="_Debug Info Window" HorizontalAlignment="Left" Width="185"
|
||||
Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
|
||||
Foreground="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"
|
||||
Template="{DynamicResource CustomMenuItemTemplate}" Visibility="Collapsed" />
|
||||
</MenuItem>
|
||||
<MenuItem x:Name="HelpMenuItem" Header="_Help"
|
||||
Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
|
||||
Foreground="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"
|
||||
Template="{DynamicResource CustomMenuItemTemplate}">
|
||||
<MenuItem x:Name="AboutMenuItem" Header="_About" HorizontalAlignment="Left" Width="185" Click="AboutClick"
|
||||
<MenuItem x:Name="AboutMenuItem" Header="_About" HorizontalAlignment="Left" Width="185"
|
||||
Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
|
||||
Foreground="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"
|
||||
Template="{DynamicResource CustomMenuItemTemplate}" />
|
||||
<MenuItem x:Name="CheckForUpdatesMenuItem" Header="_Check for Updates" HorizontalAlignment="Left" Width="185" Click="CheckForUpdatesClick"
|
||||
<MenuItem x:Name="CheckForUpdatesMenuItem" Header="_Check for Updates" HorizontalAlignment="Left" Width="185"
|
||||
Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
|
||||
Foreground="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"
|
||||
Template="{DynamicResource CustomMenuItemTemplate}" />
|
||||
@@ -133,7 +142,7 @@
|
||||
<Label x:Name="OutputDirectoryLabel" Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" Content="Output Directory"/>
|
||||
<TextBox x:Name="OutputDirectoryTextBox" Grid.Row="2" Grid.Column="1" Height="22" Width="345" HorizontalAlignment="Left" VerticalContentAlignment="Center" />
|
||||
<Button x:Name="OutputDirectoryBrowseButton" Grid.Row="2" Grid.Column="1" Height="22" Width="50" HorizontalAlignment="Right" Content="Browse"
|
||||
Click="OutputDirectoryBrowseButtonClick" Style="{DynamicResource CustomButtonStyle}"/>
|
||||
Style="{DynamicResource CustomButtonStyle}"/>
|
||||
|
||||
<Label x:Name="DriveLetterLabel" Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" Content="Drive Letter"/>
|
||||
<ComboBox x:Name="DriveLetterComboBox" Grid.Row="3" Grid.Column="1" Height="22" Width="60" HorizontalAlignment="Left" Style="{DynamicResource CustomComboBoxStyle}">
|
||||
@@ -149,18 +158,18 @@
|
||||
|
||||
<Label x:Name="ParametersLabel" Grid.Row="5" Grid.Column="0" VerticalAlignment="Center" Content="Parameters"/>
|
||||
<TextBox x:Name="ParametersTextBox" Grid.Row="5" Grid.Column="1" Height="22" Width="370" HorizontalAlignment="Left" IsEnabled="False" VerticalContentAlignment="Center" />
|
||||
<CheckBox x:Name="EnableParametersCheckBox" Grid.Row="5" Grid.Column="1" Height="22" HorizontalAlignment="Right" IsChecked="False" Click="EnableParametersCheckBoxClick" />
|
||||
<CheckBox x:Name="EnableParametersCheckBox" Grid.Row="5" Grid.Column="1" Height="22" HorizontalAlignment="Right" IsChecked="False" />
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Margin="5,5,5,5" HorizontalAlignment="Stretch" Header="Controls">
|
||||
<UniformGrid Columns="3" Margin="5,5,5,5">
|
||||
<Button x:Name="StartStopButton" Height="22" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" IsDefault="True" Content="Start Dumping"
|
||||
Click="StartStopButtonClick" IsEnabled="False" Style="{DynamicResource CustomButtonStyle}" />
|
||||
<Button x:Name="MediaScanButton" Height="22" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Scan for disks"
|
||||
Click="MediaScanButtonClick" Style="{DynamicResource CustomButtonStyle}" />
|
||||
IsEnabled="False" Style="{DynamicResource CustomButtonStyle}" />
|
||||
<Button x:Name="MediaScanButton" Height="22" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Scan for discs"
|
||||
Style="{DynamicResource CustomButtonStyle}" />
|
||||
<Button x:Name="CopyProtectScanButton" Height="22" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Scan for protection"
|
||||
Click="CopyProtectScanButtonClick" Style="{DynamicResource CustomButtonStyle}" />
|
||||
Style="{DynamicResource CustomButtonStyle}" />
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
|
||||
@@ -175,4 +184,4 @@
|
||||
</Expander>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
</windows:WindowBase>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,10 @@
|
||||
<Window x:Class="MPF.Windows.OptionsWindow"
|
||||
<windows:WindowBase x:Class="MPF.Windows.OptionsWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:MPF"
|
||||
xmlns:controls="clr-namespace:MPF.UserControls"
|
||||
xmlns:windows="clr-namespace:MPF.Windows"
|
||||
mc:Ignorable="d"
|
||||
Title="Options" Width="515.132" WindowStyle="None"
|
||||
WindowStartupLocation="CenterOwner" ResizeMode="CanMinimize" SizeToContent="Height"
|
||||
@@ -71,6 +71,11 @@
|
||||
IsChecked="{Binding Options.EnableDarkMode}"
|
||||
ToolTip="(Experimental) Enable dark mode across the entire application" Margin="0,4"
|
||||
/>
|
||||
|
||||
<CheckBox VerticalAlignment="Center" Content="Check for Updates on Startup"
|
||||
IsChecked="{Binding Options.CheckForUpdatesOnStartup}"
|
||||
ToolTip="Check for updates when the application starts" Margin="0,4"
|
||||
/>
|
||||
</UniformGrid>
|
||||
</TabItem>
|
||||
|
||||
@@ -92,17 +97,17 @@
|
||||
<Label Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Aaru Path" />
|
||||
<TextBox x:Name="AaruPathTextBox" Grid.Row="0" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" Text="{Binding Options.AaruPath}" VerticalContentAlignment="Center" />
|
||||
<Button x:Name="AaruPathButton" Grid.Row="0" Grid.Column="2" Height="22" Width="22" Content="..."
|
||||
Click="BrowseForPathClick" Style="{DynamicResource CustomButtonStyle}" />
|
||||
Style="{DynamicResource CustomButtonStyle}" />
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="DiscImageCreator Path" />
|
||||
<TextBox x:Name="DiscImageCreatorPathTextBox" Grid.Row="1" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" Text="{Binding Options.DiscImageCreatorPath}" VerticalContentAlignment="Center" />
|
||||
<Button x:Name="DiscImageCreatorPathButton" Grid.Row="1" Grid.Column="2" Height="22" Width="22" Content="..."
|
||||
Click="BrowseForPathClick" Style="{DynamicResource CustomButtonStyle}" />
|
||||
Style="{DynamicResource CustomButtonStyle}" />
|
||||
|
||||
<Label Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="DD Path" />
|
||||
<TextBox x:Name="DDPathTextBox" Grid.Row="2" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" Text="{Binding Options.DDPath}" VerticalContentAlignment="Center" />
|
||||
<Button x:Name="DDPathButton" Grid.Row="2" Grid.Column="2" Height="22" Width="22" Content="..."
|
||||
Click="BrowseForPathClick" Style="{DynamicResource CustomButtonStyle}" />
|
||||
Style="{DynamicResource CustomButtonStyle}" />
|
||||
|
||||
<Label Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Dumping Program" />
|
||||
<ComboBox x:Name="InternalProgramComboBox" Grid.Row="3" Grid.Column="1" Height="22" HorizontalAlignment="Stretch"
|
||||
@@ -111,14 +116,14 @@
|
||||
<Label Grid.Row="4" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Default Output Path" />
|
||||
<TextBox x:Name="DefaultOutputPathTextBox" Grid.Row="4" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" Text="{Binding Options.DefaultOutputPath}" VerticalContentAlignment="Center" />
|
||||
<Button x:Name="DefaultOutputPathButton" Grid.Row="4" Grid.Column="2" Height="22" Width="22" Content="..."
|
||||
Click="BrowseForPathClick" Style="{DynamicResource CustomButtonStyle}" />
|
||||
Style="{DynamicResource CustomButtonStyle}" />
|
||||
</Grid>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="Dumping" Style="{DynamicResource CustomTabItemStyle}">
|
||||
<StackPanel>
|
||||
<GroupBox Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Header="Dumping">
|
||||
<UniformGrid Columns="2" Rows="7">
|
||||
<UniformGrid Columns="2" Rows="8">
|
||||
<CheckBox 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"
|
||||
@@ -167,9 +172,19 @@
|
||||
ToolTip="Enable showing the disc information output after dumping" Margin="0,4"
|
||||
/>
|
||||
|
||||
<CheckBox VerticalAlignment="Center" Content="Enable Tab Input"
|
||||
IsChecked="{Binding Options.EnableTabsInInputFields}"
|
||||
ToolTip="Enable entering tabs in supported input fields instead of tab navigation" Margin="0,4"
|
||||
/>
|
||||
|
||||
<CheckBox VerticalAlignment="Center" Content="Show Eject Reminder"
|
||||
IsChecked="{Binding Options.ShowDiscEjectReminder}"
|
||||
ToolTip="Enable showing the disc eject reminder after information is gathered" Margin="0,4"
|
||||
/>
|
||||
|
||||
<CheckBox VerticalAlignment="Center" Content="Add Placeholders"
|
||||
IsChecked="{Binding Options.AddPlaceholders}"
|
||||
ToolTip="Enable adding placeholder text in the submissioninfo output for required and optional fields" Margin="0,4"
|
||||
ToolTip="Enable adding placeholder text in the output for required and optional fields" Margin="0,4"
|
||||
/>
|
||||
|
||||
<CheckBox VerticalAlignment="Center" Content="Output Submission JSON"
|
||||
@@ -350,7 +365,7 @@
|
||||
<PasswordBox x:Name="RedumpPasswordBox" Height="22" HorizontalAlignment="Stretch" PasswordChar="*" />
|
||||
|
||||
<Button x:Name="RedumpLoginTestButton" Height="22" Width="80" Content="Test Login"
|
||||
Click="OnRedumpTestClick" Style="{DynamicResource CustomButtonStyle}" />
|
||||
Style="{DynamicResource CustomButtonStyle}" />
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
@@ -362,12 +377,12 @@
|
||||
<UniformGrid Columns="4" Margin="5,5,5,5" Height="28">
|
||||
<Label/> <!-- Empty label for padding -->
|
||||
<Button Name="AcceptButton" Height="25" Width="80" IsDefault="True" Content="Accept"
|
||||
Click="OnAcceptClick" Style="{DynamicResource CustomButtonStyle}" />
|
||||
Style="{DynamicResource CustomButtonStyle}" />
|
||||
<Button Name="CancelButton" Height="25" Width="80" IsCancel="True" Content="Cancel"
|
||||
Click="OnCancelClick" Style="{DynamicResource CustomButtonStyle}" />
|
||||
Style="{DynamicResource CustomButtonStyle}" />
|
||||
<Label/> <!-- Empty label for padding -->
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
</windows:WindowBase>
|
||||
|
||||
@@ -1,232 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Input;
|
||||
using MPF.Data;
|
||||
using MPF.Redump;
|
||||
using WPFCustomMessageBox;
|
||||
using Button = System.Windows.Controls.Button;
|
||||
using TextBox = System.Windows.Controls.TextBox;
|
||||
using MPF.GUI.ViewModels;
|
||||
|
||||
namespace MPF.Windows
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for OptionsWindow.xaml
|
||||
/// </summary>
|
||||
public partial class OptionsWindow : Window
|
||||
public partial class OptionsWindow : WindowBase
|
||||
{
|
||||
#region Fields
|
||||
/// <summary>
|
||||
/// Read-only access to the current options view model
|
||||
/// </summary>
|
||||
public OptionsViewModel OptionsViewModel => DataContext as OptionsViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// Current set of options
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public Options Options { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of available internal programs
|
||||
/// </summary>
|
||||
public List<Element<InternalProgram>> InternalPrograms { get; private set; } = PopulateInternalPrograms();
|
||||
|
||||
/// <summary>
|
||||
/// Current list of supported system profiles
|
||||
/// </summary>
|
||||
public List<KnownSystemComboBoxItem> Systems { get; private set; } = KnownSystemComboBoxItem.GenerateElements().ToList();
|
||||
|
||||
/// <summary>
|
||||
/// Flag for if settings were saved or not
|
||||
/// </summary>
|
||||
public bool SavedSettings { get; private set; } = false;
|
||||
|
||||
#endregion
|
||||
|
||||
public OptionsWindow(Options options)
|
||||
public OptionsWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = this;
|
||||
|
||||
Options = options.Clone() as Options;
|
||||
Load();
|
||||
DataContext = new OptionsViewModel(this);
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
private FolderBrowserDialog CreateFolderBrowserDialog()
|
||||
{
|
||||
FolderBrowserDialog dialog = new FolderBrowserDialog();
|
||||
return dialog;
|
||||
}
|
||||
|
||||
private OpenFileDialog CreateOpenFileDialog()
|
||||
{
|
||||
OpenFileDialog dialog = new OpenFileDialog();
|
||||
|
||||
dialog.InitialDirectory = AppDomain.CurrentDomain.BaseDirectory;
|
||||
dialog.Filter = "Executables (*.exe)|*.exe";
|
||||
dialog.FilterIndex = 0;
|
||||
dialog.RestoreDirectory = true;
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load any options-related elements
|
||||
/// </summary>
|
||||
private void Load()
|
||||
{
|
||||
InternalProgramComboBox.SelectedIndex = InternalPrograms.FindIndex(r => r == Options.InternalProgram);
|
||||
DefaultSystemComboBox.SelectedIndex = Systems.FindIndex(r => r == Options.DefaultSystem);
|
||||
RedumpPasswordBox.Password = Options.RedumpPassword;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a complete list of supported internal programs
|
||||
/// </summary>
|
||||
private static List<Element<InternalProgram>> PopulateInternalPrograms()
|
||||
{
|
||||
var internalPrograms = new List<InternalProgram> { InternalProgram.DiscImageCreator, InternalProgram.Aaru, InternalProgram.DD };
|
||||
return internalPrograms.Select(ip => new Element<InternalProgram>(ip)).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save any options-related elements
|
||||
/// </summary>
|
||||
private void Save()
|
||||
{
|
||||
var selectedInternalProgram = InternalProgramComboBox.SelectedItem as Element<InternalProgram>;
|
||||
Options.InternalProgram = selectedInternalProgram?.Value ?? InternalProgram.DiscImageCreator;
|
||||
var selectedDefaultSystem = DefaultSystemComboBox.SelectedItem as KnownSystemComboBoxItem;
|
||||
Options.DefaultSystem = selectedDefaultSystem?.Value ?? KnownSystem.NONE;
|
||||
Options.RedumpPassword = RedumpPasswordBox.Password;
|
||||
|
||||
SavedSettings = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find a TextBox by setting name
|
||||
/// </summary>
|
||||
/// <param name="name">Setting name to find</param>
|
||||
/// <returns>TextBox for that setting</returns>
|
||||
private TextBox TextBoxForPathSetting(string name)
|
||||
{
|
||||
return FindName(name + "TextBox") as TextBox;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
/// <summary>
|
||||
/// Handler for generic Click event
|
||||
/// </summary>
|
||||
private void BrowseForPathClick(object sender, EventArgs e)
|
||||
{
|
||||
Button button = sender as Button;
|
||||
// strips button prefix to obtain the setting name
|
||||
string pathSettingName = button.Name.Substring(0, button.Name.IndexOf("Button"));
|
||||
|
||||
// TODO: hack for now, then we'll see
|
||||
bool shouldBrowseForPath = pathSettingName == "DefaultOutputPath";
|
||||
|
||||
CommonDialog dialog = shouldBrowseForPath ? (CommonDialog)CreateFolderBrowserDialog() : CreateOpenFileDialog();
|
||||
using (dialog)
|
||||
{
|
||||
DialogResult result = dialog.ShowDialog();
|
||||
|
||||
if (result == System.Windows.Forms.DialogResult.OK)
|
||||
{
|
||||
string path;
|
||||
bool exists;
|
||||
|
||||
if (shouldBrowseForPath)
|
||||
{
|
||||
path = (dialog as FolderBrowserDialog).SelectedPath;
|
||||
exists = Directory.Exists(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
path = (dialog as OpenFileDialog).FileName;
|
||||
exists = File.Exists(path);
|
||||
}
|
||||
|
||||
if (exists)
|
||||
{
|
||||
TextBoxForPathSetting(pathSettingName).Text = path;
|
||||
}
|
||||
else
|
||||
{
|
||||
CustomMessageBox.Show(
|
||||
"Specified path doesn't exists!",
|
||||
"Error",
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Error
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for CloseButton Click event
|
||||
/// </summary>
|
||||
private void CloseButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for MinimizeButton Click event
|
||||
/// </summary>
|
||||
private void MinimizeButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.WindowState = WindowState.Minimized;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for AcceptButton Click event
|
||||
/// </summary>
|
||||
private void OnAcceptClick(object sender, EventArgs e)
|
||||
{
|
||||
Save();
|
||||
Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for CancelButtom Click event
|
||||
/// </summary>
|
||||
private void OnCancelClick(object sender, EventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test Redump credentials for validity
|
||||
/// </summary>
|
||||
private void OnRedumpTestClick(object sender, EventArgs e)
|
||||
{
|
||||
using (RedumpWebClient wc = new RedumpWebClient())
|
||||
{
|
||||
bool? loggedIn = wc.Login(RedumpUsernameTextBox.Text, RedumpPasswordBox.Password);
|
||||
if (loggedIn == true)
|
||||
CustomMessageBox.Show(this, "Redump login credentials accepted!", "Success", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
else if (loggedIn == false)
|
||||
CustomMessageBox.Show(this, "Redump login credentials denied!", "Failure", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
else
|
||||
CustomMessageBox.Show(this, "Error validating credentials!", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for Title MouseDown event
|
||||
/// </summary>
|
||||
private void TitleMouseDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.ChangedButton == MouseButton.Left)
|
||||
this.DragMove();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user