Compare commits

..

54 Commits
2.6.6 ... 2.7.0

Author SHA1 Message Date
Matt Nadareski
ad37c573b6 Bump version 2023-10-10 20:25:11 -04:00
Matt Nadareski
b6cb3104ae Update changelog 2023-10-10 16:16:06 -04:00
Deterous
af9b0dc214 Fix media combobox not updating (#568)
* Fix media combobox not updating

* Don't call SetCurrentDiscType rather than clear the variable
2023-10-10 13:15:47 -07:00
Matt Nadareski
b5440032de Recentralize some Check functionality 2023-10-10 15:15:42 -04:00
Matt Nadareski
a8e783235c Fix dumping button not enabling 2023-10-10 02:03:18 -04:00
Matt Nadareski
fc97fe99e3 Fix media type ordering 2023-10-10 01:52:47 -04:00
Matt Nadareski
1c73b1133f Consolidate some constants 2023-10-09 11:49:26 -04:00
Matt Nadareski
908eccaafa Remove LogOutputViewModel 2023-10-09 11:44:06 -04:00
Matt Nadareski
e114d126c5 Move MainViewModel to Core 2023-10-09 11:35:49 -04:00
Matt Nadareski
c07b4e4a28 Remove message boxes from MainViewModel 2023-10-09 11:01:43 -04:00
Matt Nadareski
06491a6611 Detected type and selected type are different 2023-10-09 10:35:44 -04:00
Matt Nadareski
b9a35850ad Fix null reference exception in disc type 2023-10-09 00:42:33 -04:00
Matt Nadareski
17a0c5d083 Remove more Windows from MainViewModel 2023-10-09 00:13:40 -04:00
Matt Nadareski
1b9523c799 Remove some message boxes from MainViewModel 2023-10-09 00:03:02 -04:00
Matt Nadareski
ae80ecefc8 Remove WinForms from MainViewModel 2023-10-08 23:46:24 -04:00
Matt Nadareski
50ae32e3db Use callback for logging, fix Options window 2023-10-08 23:40:56 -04:00
Matt Nadareski
2d43873398 Remove MainWindow from MainViewModel 2023-10-08 23:15:24 -04:00
Matt Nadareski
a3df433fef Small updtes to MainViewModel 2023-10-08 23:06:17 -04:00
Matt Nadareski
35e71d8527 Perform most of MainViewModel changes 2023-10-08 22:49:46 -04:00
Matt Nadareski
c5d07e4be1 Start migrating MainViewModel 2023-10-08 20:52:29 -04:00
Matt Nadareski
0df5093b45 Fix log output 2023-10-08 00:39:31 -04:00
Matt Nadareski
05d920d095 Move decoupled view models 2023-10-07 23:37:01 -04:00
Matt Nadareski
d2f7ac9843 Refine info window bindings further 2023-10-07 23:12:40 -04:00
Matt Nadareski
857a302aad Refine options window bindings further 2023-10-07 22:48:43 -04:00
Matt Nadareski
46de589791 Refine options window bindings 2023-10-07 22:40:51 -04:00
Matt Nadareski
f14961061c Handle Redump password changing better 2023-10-07 21:31:39 -04:00
Matt Nadareski
453fcf5cb1 Use binding for more disc info textboxes 2023-10-07 21:23:14 -04:00
Matt Nadareski
24cdb27cdb Split options window code a bit more 2023-10-07 11:47:24 -04:00
Matt Nadareski
24235c5896 Update changelog 2023-10-07 11:32:19 -04:00
Deterous
c226f8cf58 Clarify build instructions in README (#566)
* Update README.md

* publish-win.bat requirements

* Mention publish-nix.sh and its requirements
2023-10-07 08:31:59 -07:00
Matt Nadareski
b8f6c9f65f Split info window code a bit more 2023-10-07 02:19:04 -04:00
Matt Nadareski
bb42e2db10 Split logging code a bit more 2023-10-07 01:59:28 -04:00
Matt Nadareski
db544fd4b7 Move LogLevel enumeration 2023-10-07 01:34:59 -04:00
Matt Nadareski
370c6bde5a Move element items to Core 2023-10-07 01:30:11 -04:00
Matt Nadareski
d7965ee37f Remove unnecessary include 2023-10-07 01:22:50 -04:00
Matt Nadareski
b2c6e07ed1 Fix failing tests 2023-10-07 01:11:56 -04:00
Matt Nadareski
19cef20ceb Allow nullability for modern .NET 2023-10-07 01:02:21 -04:00
Deterous
058a1aeeaa Remove debug symbols in release builds (#565)
* Remove debugging symbols from appveyor builds

* Remove debugging symbols from release build with nix build script

* Remove debug symbols from release build with win build script

* Explicitly define Debug profile

* Add missing Debug profile flag
2023-10-06 18:35:20 -07:00
Matt Nadareski
d185077925 Fix failing tests 2023-10-06 20:42:34 -04:00
Matt Nadareski
e3948ba91b Consolidate into MPF.Core 2023-10-06 20:39:59 -04:00
Matt Nadareski
4a30f94007 Remove IMAPI2 as a dependency (#563)
* Remove IMAPI2 with no substitution

* Remove framework exceptions

* Slight reorganization of code

* Update README with support information

* Remove msbuild-specific AppVeyor items

* Be trickier when it comes to type from size

* Fix formatting of changelist

* Fix "detected" message

* Be smarter about media type based on system
2023-10-06 17:22:09 -07:00
Matt Nadareski
1ae27bf9e3 Fix missing comma 2023-10-04 20:53:33 -04:00
Matt Nadareski
bc88103471 Add submission info preamble 2023-10-04 20:51:07 -04:00
Matt Nadareski
9ec6fbfe52 Don't reverse the CRC32 output 2023-10-04 16:40:46 -04:00
Matt Nadareski
ebdb8de6b3 Use System.IO.Hashing for CRC32 2023-10-04 16:37:33 -04:00
Matt Nadareski
b8b56f6308 Build number not job number 2023-10-04 16:03:11 -04:00
Matt Nadareski
0726f5a402 Undo accidential temp commit 2023-10-04 15:51:10 -04:00
Matt Nadareski
90da5d1a7e Fix errant space in variable name 2023-10-04 15:50:56 -04:00
Matt Nadareski
bd3c518fa0 Job number not build ID 2023-10-04 15:39:11 -04:00
Matt Nadareski
44272f60bf Try out using version number in AppVeyor 2023-10-04 15:31:43 -04:00
Matt Nadareski
640ce8d854 Add note about git being required 2023-10-04 14:53:55 -04:00
Matt Nadareski
74732058f2 Publish, but don't package, release builds 2023-10-04 14:48:56 -04:00
Matt Nadareski
22e480ccd1 Try alternate archive naming 2023-10-04 14:35:46 -04:00
Matt Nadareski
32a0cb0394 Attempt to replace NRT 2023-10-04 14:26:13 -04:00
75 changed files with 6454 additions and 4702 deletions

15
.vscode/tasks.json vendored
View File

@@ -3,22 +3,11 @@
"tasks": [
{
"label": "build",
"command": "msbuild",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/MPF.sln",
"-property:RuntimeIdentifiers=win7-x64"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "msbuild",
"type": "process",
"args": [
"${workspaceFolder}/MPF/MPF.csproj",
"-target:Publish",
"-property:RuntimeIdentifiers=win7-x64"
],
"problemMatcher": "$msCompile"
},

View File

@@ -1,3 +1,63 @@
### 2.7.0 (2023-10-11)
- Attempt to replace NRT
- Try alternate archive naming
- Publish, but don't package, release builds
- Add note about git being required
- Try out using version number in AppVeyor
- Job number not build ID
- Fix errant space in variable name
- Build number not job number
- Use System.IO.Hashing for CRC32
- Don't reverse the CRC32 output
- Add submission info preamble
- Fix missing comma
- Remove IMAPI2 with no substitution
- Remove framework exceptions
- Slight reorganization of code
- Update README with support information
- Remove msbuild-specific AppVeyor items
- Be trickier when it comes to type from size
- Fix "detected" message
- Be smarter about media type based on system
- Consolidate into MPF.Core
- Fix failing tests
- Remove debug symbols in release builds (Deterous)
- Allow nullability for modern .NET
- Fix failing tests
- Remove unnecessary include
- Move element items to Core
- Move LogLevel enumeration
- Split logging code a bit more
- Split info window code a bit more
- Clarify build instructions in README (Deterous)
- Split options window code a bit more
- Use binding for more disc info textboxes
- Handle Redump password changing better
- Refine options window bindings
- Refine options window bindings further
- Refine info window bindings further
- Move decoupled view models
- Fix log output
- Start migrating MainViewModel
- Perform most of MainViewModel changes
- Small updtes to MainViewModel
- Remove MainWindow from MainViewModel
- Use callback for logging, fix Options window
- Remove WinForms from MainViewModel
- Remove some message boxes from MainViewModel
- Remove more Windows from MainViewModel
- Fix null reference exception in disc type
- Detected type and selected type are different
- Remove message boxes from MainViewModel
- Move MainViewModel to Core
- Remove LogOutputViewModel
- Consolidate some constants
- Fix media type ordering
- Fix dumping button not enabling
- Recentralize some Check functionality
- Fix media combobox not updating (Deterous)
### 2.6.6 (2023-10-04)
- Update Nuget packages

View File

@@ -8,13 +8,7 @@
<Description>Validator for various dumping programs</Description>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Copyright>Copyright (c)2019-2023</Copyright>
<Version>2.6.6</Version>
</PropertyGroup>
<PropertyGroup>
<NrtRevisionFormat>$(Version)-{chash:8}</NrtRevisionFormat>
<NrtResolveSimpleAttributes>true</NrtResolveSimpleAttributes>
<NrtShowRevision>false</NrtShowRevision>
<VersionPrefix>2.7.0</VersionPrefix>
</PropertyGroup>
<ItemGroup>
@@ -23,7 +17,6 @@
<ItemGroup>
<ProjectReference Include="..\MPF.Core\MPF.Core.csproj" />
<ProjectReference Include="..\MPF.Library\MPF.Library.csproj" />
</ItemGroup>
<ItemGroup>
@@ -31,10 +24,6 @@
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="SabreTools.RedumpLib" Version="1.1.1" />
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>

View File

@@ -1,10 +1,9 @@
using System;
using System.IO;
using BurnOutSharp;
using MPF.Core.Converters;
using MPF.Core;
using MPF.Core.Data;
using MPF.Core.Utilities;
using MPF.Library;
using SabreTools.RedumpLib.Data;
using SabreTools.RedumpLib.Web;
@@ -15,13 +14,19 @@ namespace MPF.Check
public static void Main(string[] args)
{
// Try processing the standalone arguments
if (ProcessStandaloneArguments(args))
if (!OptionsLoader.ProcessStandaloneArguments(args))
{
DisplayHelp();
return;
}
// Try processing the common arguments
(bool success, MediaType mediaType, RedumpSystem? knownSystem) = ProcessCommonArguments(args);
(bool success, MediaType mediaType, RedumpSystem? knownSystem, string error) = OptionsLoader.ProcessCommonArguments(args);
if (!success)
{
DisplayHelp(error);
return;
}
// Loop through and process options
(Core.Data.Options options, string path, int startIndex) = OptionsLoader.LoadFromArguments(args, startIndex: 2);
@@ -33,9 +38,9 @@ namespace MPF.Check
// Make new Progress objects
var resultProgress = new Progress<Result>();
resultProgress.ProgressChanged += ProgressUpdated;
resultProgress.ProgressChanged += ConsoleLogger.ProgressUpdated;
var protectionProgress = new Progress<ProtectionProgress>();
protectionProgress.ProgressChanged += ProgressUpdated;
protectionProgress.ProgressChanged += ConsoleLogger.ProgressUpdated;
// Validate the supplied credentials
#if NET48
@@ -99,101 +104,5 @@ namespace MPF.Check
}
Console.WriteLine();
}
/// <summary>
/// Process common arguments for all functionality
/// </summary>
/// <returns>True if all arguments pass, false otherwise</returns>
private static (bool, MediaType, RedumpSystem?) ProcessCommonArguments(string[] args)
{
// All other use requires at least 3 arguments
if (args.Length < 3)
{
DisplayHelp("Invalid number of arguments");
return (false, MediaType.NONE, null);
}
// Check the MediaType
var mediaType = EnumConverter.ToMediaType(args[0].Trim('"'));
if (mediaType == MediaType.NONE)
{
DisplayHelp($"{args[0]} is not a recognized media type");
return (false, MediaType.NONE, null);
}
// Check the RedumpSystem
var knownSystem = Extensions.ToRedumpSystem(args[1].Trim('"'));
if (knownSystem == null)
{
DisplayHelp($"{args[1]} is not a recognized system");
return (false, MediaType.NONE, null);
}
return (true, mediaType, knownSystem);
}
/// <summary>
/// Process any standalone arguments for the program
/// </summary>
/// <returns>True if one of the arguments was processed, false otherwise</returns>
private static bool ProcessStandaloneArguments(string[] args)
{
// Help options
if (args.Length == 0 || args[0] == "-h" || args[0] == "-?")
{
DisplayHelp();
return true;
}
// List options
if (args[0] == "-lm" || args[0] == "--listmedia")
{
Console.WriteLine("Supported Media Types:");
foreach (string mediaType in Extensions.ListMediaTypes())
{
Console.WriteLine(mediaType);
}
Console.ReadLine();
return true;
}
else if (args[0] == "-lp" || args[0] == "--listprograms")
{
Console.WriteLine("Supported Programs:");
foreach (string program in EnumExtensions.ListPrograms())
{
Console.WriteLine(program);
}
Console.ReadLine();
return true;
}
else if (args[0] == "-ls" || args[0] == "--listsystems")
{
Console.WriteLine("Supported Systems:");
foreach (string system in Extensions.ListSystems())
{
Console.WriteLine(system);
}
Console.ReadLine();
return true;
}
return false;
}
/// <summary>
/// Simple process counter to write to console
/// </summary>
private static void ProgressUpdated(object sender, Result value)
{
Console.WriteLine(value.Message);
}
/// <summary>
/// Simple process counter to write to console
/// </summary>
private static void ProgressUpdated(object sender, ProtectionProgress value)
{
Console.WriteLine($"{value.Percentage * 100:N2}%: {value.Filename} - {value.Protection}");
}
}
}

View File

@@ -1,4 +0,0 @@
using System.Runtime.CompilerServices;
// Anything marked as internal can be used by the test methods
[assembly: InternalsVisibleTo("MPF.Test")]

25
MPF.Core/ConsoleLogger.cs Normal file
View File

@@ -0,0 +1,25 @@
using System;
using BurnOutSharp;
using MPF.Core.Data;
namespace MPF.Core
{
public static class ConsoleLogger
{
/// <summary>
/// Simple process counter to write to console
/// </summary>
public static void ProgressUpdated(object sender, Result value)
{
Console.WriteLine(value.Message);
}
/// <summary>
/// Simple process counter to write to console
/// </summary>
public static void ProgressUpdated(object sender, ProtectionProgress value)
{
Console.WriteLine($"{value.Percentage * 100:N2}%: {value.Filename} - {value.Protection}");
}
}
}

View File

@@ -2,9 +2,6 @@
using System.Collections.Concurrent;
using System.IO;
using System.Reflection;
#if NETFRAMEWORK
using IMAPI2;
#endif
using MPF.Core.Data;
using SabreTools.RedumpLib.Data;
@@ -34,47 +31,6 @@ namespace MPF.Core.Converters
}
}
#if NETFRAMEWORK
/// <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
@@ -82,7 +38,11 @@ namespace MPF.Core.Converters
/// <summary>
/// Long name method cache
/// </summary>
#if NET48
private static readonly ConcurrentDictionary<Type, MethodInfo> LongNameMethods = new ConcurrentDictionary<Type, MethodInfo>();
#else
private static readonly ConcurrentDictionary<Type, MethodInfo?> LongNameMethods = new ConcurrentDictionary<Type, MethodInfo?>();
#endif
/// <summary>
/// Get the string representation of a generic enumerable value
@@ -93,12 +53,12 @@ namespace MPF.Core.Converters
{
try
{
var sourceType = value?.GetType();
var sourceType = value.GetType();
sourceType = Nullable.GetUnderlyingType(sourceType) ?? sourceType;
if (!LongNameMethods.TryGetValue(sourceType, out MethodInfo method))
if (!LongNameMethods.TryGetValue(sourceType, out var method))
{
method = typeof(SabreTools.RedumpLib.Data.Extensions).GetMethod("LongName", new[] { typeof(Nullable<>).MakeGenericType(sourceType) });
method = typeof(Extensions).GetMethod("LongName", new[] { typeof(Nullable<>).MakeGenericType(sourceType) });
if (method == null)
method = typeof(EnumConverter).GetMethod("LongName", new[] { typeof(Nullable<>).MakeGenericType(sourceType) });
@@ -106,7 +66,7 @@ namespace MPF.Core.Converters
}
if (method != null)
return method.Invoke(null, new[] { value }) as string;
return method.Invoke(null, new[] { value }) as string ?? string.Empty;
else
return string.Empty;
}
@@ -156,7 +116,7 @@ namespace MPF.Core.Converters
}
}
#endregion
#endregion
#region Convert From String
@@ -165,9 +125,13 @@ namespace MPF.Core.Converters
/// </summary>
/// <param name="internalProgram">String value to convert</param>
/// <returns>InternalProgram represented by the string, if possible</returns>
#if NET48
public static InternalProgram ToInternalProgram(string internalProgram)
#else
public static InternalProgram ToInternalProgram(string? internalProgram)
#endif
{
switch (internalProgram.ToLowerInvariant())
switch (internalProgram?.ToLowerInvariant())
{
// Dumping support
case "aaru":

View File

@@ -16,12 +16,12 @@ namespace MPF.Core.Data
// Byte arrays for signatures
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> HDDVD { 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 };
// Lists of known drive speed ranges
public 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 };
public static IReadOnlyList<int> DVD { get; } = CD.Where(s => s <= 24).ToList();
public static IReadOnlyList<int> HDDVD { get; } = CD.Where(s => s <= 24).ToList();
public static IReadOnlyList<int> BD { get; } = CD.Where(s => s <= 16).ToList();
public static IReadOnlyList<int> Unknown { get; } = new List<int> { 1 };
/// <summary>
/// Get list of all drive speeds for a given MediaType

View File

@@ -7,9 +7,6 @@ using Microsoft.Management.Infrastructure.Generic;
using MPF.Core.Converters;
using MPF.Core.Utilities;
using SabreTools.RedumpLib.Data;
#if NETFRAMEWORK
using IMAPI2;
#endif
namespace MPF.Core.Data
{
@@ -32,12 +29,20 @@ namespace MPF.Core.Data
/// <summary>
/// Drive partition format
/// </summary>
#if NET48
public string DriveFormat { get; private set; } = null;
#else
public string? DriveFormat { get; private set; } = null;
#endif
/// <summary>
/// Windows drive path
/// </summary>
#if NET48
public string Name { get; private set; } = null;
#else
public string? Name { get; private set; } = null;
#endif
/// <summary>
/// Represents if Windows has marked the drive as active
@@ -53,7 +58,11 @@ namespace MPF.Core.Data
/// 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>
#if NET48
public string VolumeLabel { get; private set; } = null;
#else
public string? VolumeLabel { get; private set; } = null;
#endif
#endregion
@@ -62,7 +71,11 @@ namespace MPF.Core.Data
/// <summary>
/// Media label as read by Windows, formatted to avoid odd outputs
/// </summary>
#if NET48
public string FormattedVolumeLabel
#else
public string? FormattedVolumeLabel
#endif
{
get
{
@@ -99,7 +112,11 @@ namespace MPF.Core.Data
/// </summary>
/// <param name="driveType">InternalDriveType value representing the drive type</param>
/// <param name="devicePath">Path to the device according to the local machine</param>
#if NET48
public static Drive Create(InternalDriveType? driveType, string devicePath)
#else
public static Drive? Create(InternalDriveType? driveType, string devicePath)
#endif
{
// Create a new, empty drive object
var drive = new Drive()
@@ -134,7 +151,11 @@ namespace MPF.Core.Data
/// Populate all fields from a DriveInfo object
/// </summary>
/// <param name="driveInfo">DriveInfo object to populate from</param>
#if NET48
private void PopulateFromDriveInfo(DriveInfo driveInfo)
#else
private void PopulateFromDriveInfo(DriveInfo? driveInfo)
#endif
{
// If we have an invalid DriveInfo, just return
if (driveInfo == null || driveInfo == default)
@@ -167,84 +188,94 @@ namespace MPF.Core.Data
public static List<Drive> CreateListOfDrives(bool ignoreFixedDrives)
{
var drives = GetDriveList(ignoreFixedDrives);
drives = drives?.OrderBy(i => i.Letter)?.ToList();
drives = drives.OrderBy(i => i == null ? '\0' : i.Letter).ToList();
return drives;
}
/// <summary>
/// Get the current media type from drive letter
/// </summary>
/// <param name="system"></param>
/// <returns></returns>
public (MediaType?, string) GetMediaType()
#if NET48
public (MediaType?, string) GetMediaType(RedumpSystem? system)
#else
public (MediaType?, string?) GetMediaType(RedumpSystem? system)
#endif
{
// 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 NET6_0_OR_GREATER
else
return GetMediaTypeFromSize();
#else
// Get the current drive information
string deviceId = null;
bool loaded = false;
try
switch (this.InternalDriveType)
{
// Get the device ID first
CimSession session = CimSession.Create(null);
var collection = session.QueryInstances("root\\CIMV2", "WQL", $"SELECT * FROM Win32_CDROMDrive WHERE Id = '{this.Letter}:\'");
foreach (CimInstance instance in collection)
{
CimKeyedCollection<CimProperty> properties = instance.CimInstanceProperties;
deviceId = (string)properties["DeviceID"]?.Value;
loaded = (bool)properties["MediaLoaded"]?.Value;
}
// 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);
case Data.InternalDriveType.Floppy:
return (MediaType.FloppyDisk, null);
case Data.InternalDriveType.HardDisk:
return (MediaType.HardDisk, null);
case Data.InternalDriveType.Removable:
return (MediaType.FlashDrive, null);
}
catch (Exception ex)
// Some systems should default to certain media types
switch (system)
{
return (null, ex.Message);
// CD
case RedumpSystem.Panasonic3DOInteractiveMultiplayer:
case RedumpSystem.PhilipsCDi:
case RedumpSystem.SegaDreamcast:
case RedumpSystem.SegaSaturn:
case RedumpSystem.SonyPlayStation:
case RedumpSystem.VideoCD:
return (MediaType.CDROM, null);
// DVD
case RedumpSystem.DVDAudio:
case RedumpSystem.DVDVideo:
case RedumpSystem.MicrosoftXbox:
case RedumpSystem.MicrosoftXbox360:
return (MediaType.DVD, null);
// HD-DVD
case RedumpSystem.HDDVDVideo:
return (MediaType.HDDVD, null);
// Blu-ray
case RedumpSystem.BDVideo:
case RedumpSystem.MicrosoftXboxOne:
case RedumpSystem.MicrosoftXboxSeriesXS:
case RedumpSystem.SonyPlayStation3:
case RedumpSystem.SonyPlayStation4:
case RedumpSystem.SonyPlayStation5:
return (MediaType.BluRay, null);
// GameCube
case RedumpSystem.NintendoGameCube:
return (MediaType.NintendoGameCubeGameDisc, null);
// Wii
case RedumpSystem.NintendoWii:
return (MediaType.NintendoWiiOpticalDisc, null);
// WiiU
case RedumpSystem.NintendoWiiU:
return (MediaType.NintendoWiiUOpticalDisc, null);
// PSP
case RedumpSystem.SonyPlayStationPortable:
return (MediaType.UMD, null);
}
#endif
// Handle optical media by size and filesystem
if (this.TotalSize >= 0 && this.TotalSize < 800_000_000 && this.DriveFormat == "CDFS")
return (MediaType.CDROM, null);
else if (this.TotalSize >= 0 && this.TotalSize < 400_000_000 && this.DriveFormat == "UDF")
return (MediaType.CDROM, null);
else if (this.TotalSize >= 800_000_000 && this.TotalSize <= 8_540_000_000 && this.DriveFormat == "CDFS")
return (MediaType.DVD, null);
else if (this.TotalSize >= 400_000_000 && this.TotalSize <= 8_540_000_000 && this.DriveFormat == "UDF")
return (MediaType.DVD, null);
else if (this.TotalSize > 8_540_000_000)
return (MediaType.BluRay, null);
return (null, "Could not determine media type!");
}
/// <summary>
@@ -333,7 +364,7 @@ namespace MPF.Core.Data
// Sega Saturn
try
{
byte[] sector = ReadSector(0);
var sector = ReadSector(0);
if (sector != null)
{
if (sector.StartsWith(Interface.SaturnSectorZeroStart))
@@ -517,7 +548,11 @@ namespace MPF.Core.Data
/// <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>
#if NET48
public byte[] ReadSector(long num, int size = 2048)
#else
public byte[]? ReadSector(long num, int size = 2048)
#endif
{
// Missing drive leter is not supported
if (string.IsNullOrEmpty(this.Name))
@@ -528,7 +563,11 @@ namespace MPF.Core.Data
return null;
// Wrap the following in case of device access errors
#if NET48
Stream fs = null;
#else
Stream? fs = null;
#endif
try
{
// Open the drive as a device
@@ -566,20 +605,6 @@ namespace MPF.Core.Data
#region Helpers
/// <summary>
/// Get the media type for a device path based on size
/// </summary>
/// <returns>MediaType, null on error</returns>
private (MediaType?, string) GetMediaTypeFromSize()
{
if (this.TotalSize >= 0 && this.TotalSize < 800_000_000 && this.DriveFormat == "CDFS")
return (MediaType.CDROM, null);
else if (this.TotalSize >= 400_000_000 && this.TotalSize <= 8_540_000_000 && this.DriveFormat == "UDF")
return (MediaType.DVD, null);
else
return (MediaType.BluRay, null);
}
/// <summary>
/// Get all current attached Drives
/// </summary>
@@ -609,7 +634,7 @@ namespace MPF.Core.Data
{
drives = DriveInfo.GetDrives()
.Where(d => desiredDriveTypes.Contains(d.DriveType))
.Select(d => Create(EnumConverter.ToInternalDriveType(d.DriveType), d.Name))
.Select(d => Create(EnumConverter.ToInternalDriveType(d.DriveType), d.Name) ?? new Drive())
.ToList();
}
catch
@@ -629,8 +654,8 @@ namespace MPF.Core.Data
uint? mediaType = properties["MediaType"]?.Value as uint?;
if (mediaType != null && ((mediaType > 0 && mediaType < 11) || (mediaType > 12 && mediaType < 22)))
{
char devId = (properties["Caption"].Value as string)[0];
drives.ForEach(d => { if (d.Letter == devId) { d.InternalDriveType = Data.InternalDriveType.Floppy; } });
char devId = (properties["Caption"].Value as string ?? string.Empty)[0];
drives.ForEach(d => { if (d?.Letter == devId) { d.InternalDriveType = Data.InternalDriveType.Floppy; } });
}
}
}

View File

@@ -28,4 +28,15 @@
DCDumper,
UmdImageCreator,
}
/// <summary>
/// Log level for output
/// </summary>
public enum LogLevel
{
USER,
VERBOSE,
ERROR,
SECRET,
}
}

View File

@@ -21,7 +21,7 @@ namespace MPF.Core.Data
if (_keyValuePairs.ContainsKey(key))
return _keyValuePairs[key];
return null;
return string.Empty;
}
set
{
@@ -104,10 +104,16 @@ namespace MPF.Core.Data
string section = string.Empty;
while (!sr.EndOfStream)
{
string line = sr.ReadLine().Trim();
var line = sr.ReadLine()?.Trim();
// Empty lines are skipped
if (string.IsNullOrWhiteSpace(line))
{
// No-op, we don't process empty lines
}
// Comments start with ';'
if (line.StartsWith(";"))
else if (line.StartsWith(";"))
{
// No-op, we don't process comments
}
@@ -245,7 +251,9 @@ namespace MPF.Core.Data
public bool TryGetValue(string key, out string value)
{
return ((IDictionary<string, string>)_keyValuePairs).TryGetValue(key.ToLowerInvariant(), out value);
bool result = ((IDictionary<string, string>)_keyValuePairs).TryGetValue(key.ToLowerInvariant(), out var temp);
value = temp ?? string.Empty;
return result;
}
public void Add(KeyValuePair<string, string> item)

View File

@@ -1,24 +1,34 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Generic;
using MPF.Core.Converters;
using SabreTools.RedumpLib.Data;
namespace MPF.Core.Data
{
public class Options : IDictionary<string, string>
#if NET48
public class Options
#else
public class Options
#endif
{
/// <summary>
/// All settings in the form of a dictionary
/// </summary>
#if NET48
public Dictionary<string, string> Settings { get; private set; }
#else
public Dictionary<string, string?> Settings { get; private set; }
#endif
#region Internal Program
/// <summary>
/// Path to Aaru
/// </summary>
#if NET48
public string AaruPath
#else
public string? AaruPath
#endif
{
get { return GetStringSetting(Settings, "AaruPath", "Programs\\Aaru\\Aaru.exe"); }
set { Settings["AaruPath"] = value; }
@@ -27,7 +37,11 @@ namespace MPF.Core.Data
/// <summary>
/// Path to DiscImageCreator
/// </summary>
#if NET48
public string DiscImageCreatorPath
#else
public string? DiscImageCreatorPath
#endif
{
get { return GetStringSetting(Settings, "DiscImageCreatorPath", "Programs\\Creator\\DiscImageCreator.exe"); }
set { Settings["DiscImageCreatorPath"] = value; }
@@ -36,7 +50,11 @@ namespace MPF.Core.Data
/// <summary>
/// Path to Redumper
/// </summary>
#if NET48
public string RedumperPath
#else
public string? RedumperPath
#endif
{
get { return GetStringSetting(Settings, "RedumperPath", "Programs\\Redumper\\redumper.exe"); }
set { Settings["RedumperPath"] = value; }
@@ -49,7 +67,7 @@ namespace MPF.Core.Data
{
get
{
string valueString = GetStringSetting(Settings, "InternalProgram", InternalProgram.DiscImageCreator.ToString());
var valueString = GetStringSetting(Settings, "InternalProgram", InternalProgram.DiscImageCreator.ToString());
var valueEnum = EnumConverter.ToInternalProgram(valueString);
return valueEnum == InternalProgram.NONE ? InternalProgram.DiscImageCreator : valueEnum;
}
@@ -93,7 +111,11 @@ namespace MPF.Core.Data
/// <summary>
/// Default output path for dumps
/// </summary>
#if NET48
public string DefaultOutputPath
#else
public string? DefaultOutputPath
#endif
{
get { return GetStringSetting(Settings, "DefaultOutputPath", "ISO"); }
set { Settings["DefaultOutputPath"] = value; }
@@ -106,8 +128,8 @@ namespace MPF.Core.Data
{
get
{
string valueString = GetStringSetting(Settings, "DefaultSystem", null);
var valueEnum = Extensions.ToRedumpSystem(valueString);
var valueString = GetStringSetting(Settings, "DefaultSystem", null);
var valueEnum = Extensions.ToRedumpSystem(valueString ?? string.Empty);
return valueEnum;
}
set
@@ -536,16 +558,27 @@ namespace MPF.Core.Data
#region Redump Login Information
#if NET48
public string RedumpUsername
#else
public string? RedumpUsername
#endif
{
get { return GetStringSetting(Settings, "RedumpUsername", ""); }
set { Settings["RedumpUsername"] = value; }
}
// TODO: Figure out a way to keep this encrypted in some way, BASE64 to start?
#if NET48
public string RedumpPassword
#else
public string? RedumpPassword
#endif
{
get { return GetStringSetting(Settings, "RedumpPassword", ""); }
get
{
return GetStringSetting(Settings, "RedumpPassword", "");
}
set { Settings["RedumpPassword"] = value; }
}
@@ -560,9 +593,17 @@ namespace MPF.Core.Data
/// Constructor taking a dictionary for settings
/// </summary>
/// <param name="settings"></param>
#if NET48
public Options(Dictionary<string, string> settings = null)
#else
public Options(Dictionary<string, string?>? settings = null)
#endif
{
#if NET48
this.Settings = settings ?? new Dictionary<string, string>();
#else
this.Settings = settings ?? new Dictionary<string, string?>();
#endif
}
/// <summary>
@@ -571,7 +612,24 @@ namespace MPF.Core.Data
/// <param name="source"></param>
public Options(Options source)
{
#if NET48
Settings = new Dictionary<string, string>(source.Settings);
#else
Settings = new Dictionary<string, string?>(source.Settings);
#endif
}
/// <summary>
/// Accessor for the internal dictionary
/// </summary>
#if NET48
public string this[string key]
#else
public string? this[string key]
#endif
{
get => this.Settings[key];
set => this.Settings[key] = value;
}
#region Helpers
@@ -583,11 +641,15 @@ namespace MPF.Core.Data
/// <param name="key">Setting key to get a value for</param>
/// <param name="defaultValue">Default value to return if no value is found</param>
/// <returns>Setting value if possible, default value otherwise</returns>
#if NET48
private bool GetBooleanSetting(Dictionary<string, string> settings, string key, bool defaultValue)
#else
private bool GetBooleanSetting(Dictionary<string, string?> settings, string key, bool defaultValue)
#endif
{
if (settings.ContainsKey(key))
{
if (Boolean.TryParse(settings[key], out bool value))
if (bool.TryParse(settings[key], out bool value))
return value;
else
return defaultValue;
@@ -605,11 +667,15 @@ namespace MPF.Core.Data
/// <param name="key">Setting key to get a value for</param>
/// <param name="defaultValue">Default value to return if no value is found</param>
/// <returns>Setting value if possible, default value otherwise</returns>
#if NET48
private int GetInt32Setting(Dictionary<string, string> settings, string key, int defaultValue)
#else
private int GetInt32Setting(Dictionary<string, string?> settings, string key, int defaultValue)
#endif
{
if (settings.ContainsKey(key))
{
if (Int32.TryParse(settings[key], out int value))
if (int.TryParse(settings[key], out int value))
return value;
else
return defaultValue;
@@ -627,7 +693,11 @@ namespace MPF.Core.Data
/// <param name="key">Setting key to get a value for</param>
/// <param name="defaultValue">Default value to return if no value is found</param>
/// <returns>Setting value if possible, default value otherwise</returns>
#if NET48
private string GetStringSetting(Dictionary<string, string> settings, string key, string defaultValue)
#else
private string? GetStringSetting(Dictionary<string, string?> settings, string key, string? defaultValue)
#endif
{
if (settings.ContainsKey(key))
return settings[key];
@@ -636,45 +706,5 @@ namespace MPF.Core.Data
}
#endregion
#region IDictionary implementations
public ICollection<string> Keys => Settings.Keys;
public ICollection<string> Values => Settings.Values;
public int Count => Settings.Count;
public bool IsReadOnly => ((IDictionary<string, string>)Settings).IsReadOnly;
public string this[string key]
{
get { return (Settings.ContainsKey(key) ? Settings[key] : null); }
set { Settings[key] = value; }
}
public bool ContainsKey(string key) => Settings.ContainsKey(key);
public void Add(string key, string value) => Settings.Add(key, value);
public bool Remove(string key) => Settings.Remove(key);
public bool TryGetValue(string key, out string value) => Settings.TryGetValue(key, out value);
public void Add(KeyValuePair<string, string> item) => Settings.Add(item.Key, item.Value);
public void Clear() => Settings.Clear();
public bool Contains(KeyValuePair<string, string> item) => ((IDictionary<string, string>)Settings).Contains(item);
public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex) => ((IDictionary<string, string>)Settings).CopyTo(array, arrayIndex);
public bool Remove(KeyValuePair<string, string> item) => ((IDictionary<string, string>)Settings).Remove(item);
public IEnumerator<KeyValuePair<string, string>> GetEnumerator() => Settings.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => Settings.GetEnumerator();
#endregion
}
}

View File

@@ -42,7 +42,7 @@ namespace MPF.Core.Data
public void Enqueue(T item)
{
// Only accept new data when not cancelled
if (!this.TokenSource.IsCancellationRequested)
if (item != null && !this.TokenSource.IsCancellationRequested)
this.InternalQueue.Enqueue(item);
}
@@ -64,7 +64,7 @@ namespace MPF.Core.Data
}
// Get the next item from the queue
if (!this.InternalQueue.TryDequeue(out T nextItem))
if (!this.InternalQueue.TryDequeue(out var nextItem))
continue;
// Invoke the lambda, if possible

View File

@@ -30,7 +30,11 @@
/// Create a success result with a custom message
/// </summary>
/// <param name="message">String to add as a message</param>
#if NET48
public static Result Success(string message) => new Result(true, message);
#else
public static Result Success(string? message) => new Result(true, message ?? string.Empty);
#endif
/// <summary>
/// Create a default failure result with no message
@@ -42,7 +46,11 @@
/// Create a failure result with a custom message
/// </summary>
/// <param name="message">String to add as a message</param>
#if NET48
public static Result Failure(string message) => new Result(false, message);
#else
public static Result Failure(string? message) => new Result(false, message ?? string.Empty);
#endif
/// <summary>
/// Results can be compared to boolean values based on the success value

View File

@@ -17,17 +17,29 @@ namespace MPF.Core.Data
/// <summary>
/// Raw XMID/XeMID string that all other information is derived from
/// </summary>
#if NET48
public string RawXMID { get; private set; }
#else
public string? RawXMID { get; private set; }
#endif
/// <summary>
/// XGD1 XMID
/// </summary>
#if NET48
public SabreTools.Models.Xbox.XMID XMID { get; private set; }
#else
public SabreTools.Models.Xbox.XMID? XMID { get; private set; }
#endif
/// <summary>
/// XGD2/3 XeMID
/// </summary>
#if NET48
public SabreTools.Models.Xbox.XeMID XeMID { get; private set; }
#else
public SabreTools.Models.Xbox.XeMID? XeMID { get; private set; }
#endif
#endregion
@@ -58,7 +70,11 @@ namespace MPF.Core.Data
/// Get the human-readable serial string
/// </summary>
/// <returns>Formatted serial string, null on error</returns>
#if NET48
public string GetSerial()
#else
public string? GetSerial()
#endif
{
if (!this.Initialized)
return null;
@@ -86,7 +102,11 @@ namespace MPF.Core.Data
/// </summary>
/// <returns>Formatted version string, null on error</returns>
/// <remarks>This may differ for XGD2/3 in the future</remarks>
#if NET48
public string GetVersion()
#else
public string? GetVersion()
#endif
{
if (!this.Initialized)
return null;
@@ -160,7 +180,7 @@ namespace MPF.Core.Data
/// </summary>
/// <param name="region">Character denoting the region</param>
/// <returns>Region, if possible</returns>
public static Region? GetRegion(char region)
public static Region? GetRegion(char? region)
{
switch (region)
{

View File

@@ -6,10 +6,10 @@ using System.Threading.Tasks;
using BurnOutSharp;
using MPF.Core.Data;
using MPF.Core.Utilities;
using MPF.Modules;
using MPF.Core.Modules;
using SabreTools.RedumpLib.Data;
namespace MPF.Library
namespace MPF.Core
{
/// <summary>
/// Represents the state of all settings to be used during dumping
@@ -30,7 +30,11 @@ namespace MPF.Library
/// <summary>
/// Drive object representing the current drive
/// </summary>
#if NET48
public Drive Drive { get; private set; }
#else
public Drive? Drive { get; private set; }
#endif
/// <summary>
/// Currently selected system
@@ -50,36 +54,52 @@ namespace MPF.Library
/// <summary>
/// Options object representing user-defined options
/// </summary>
public Core.Data.Options Options { get; private set; }
public Data.Options Options { get; private set; }
/// <summary>
/// Parameters object representing what to send to the internal program
/// </summary>
#if NET48
public BaseParameters Parameters { get; private set; }
#else
public BaseParameters? Parameters { get; private set; }
#endif
#endregion
#endregion
#region Event Handlers
/// <summary>
/// Generic way of reporting a message
/// </summary>
#if NET48
public EventHandler<string> ReportStatus;
#else
public EventHandler<string>? ReportStatus;
#endif
/// <summary>
/// Queue of items that need to be logged
/// </summary>
#if NET48
private ProcessingQueue<string> outputQueue;
#else
private ProcessingQueue<string>? outputQueue;
#endif
/// <summary>
/// Event handler for data returned from a process
/// </summary>
private void OutputToLog(object proc, string args) => outputQueue.Enqueue(args);
#if NET48
private void OutputToLog(object proc, string args) => outputQueue?.Enqueue(args);
#else
private void OutputToLog(object? proc, string args) => outputQueue?.Enqueue(args);
#endif
/// <summary>
/// Process the outputs in the queue
/// </summary>
private void ProcessOutputs(string nextOutput) => ReportStatus.Invoke(this, nextOutput);
private void ProcessOutputs(string nextOutput) => ReportStatus?.Invoke(this, nextOutput);
#endregion
@@ -93,9 +113,13 @@ namespace MPF.Library
/// <param name="type"></param>
/// <param name="internalProgram"></param>
/// <param name="parameters"></param>
public DumpEnvironment(Core.Data.Options options,
public DumpEnvironment(Data.Options options,
string outputPath,
#if NET48
Drive drive,
#else
Drive? drive,
#endif
RedumpSystem? system,
MediaType? type,
InternalProgram? internalProgram,
@@ -112,7 +136,7 @@ namespace MPF.Library
this.System = system ?? options.DefaultSystem;
this.Type = type ?? MediaType.NONE;
this.InternalProgram = internalProgram ?? options.InternalProgram;
// Dumping program
SetParameters(parameters);
}
@@ -125,7 +149,7 @@ namespace MPF.Library
public void AdjustPathsForDiscImageCreator()
{
// Only DiscImageCreator has issues with paths
if (this.Parameters.InternalProgram != InternalProgram.DiscImageCreator)
if (this.Parameters?.InternalProgram != InternalProgram.DiscImageCreator)
return;
try
@@ -134,8 +158,8 @@ namespace MPF.Library
string outputPath = InfoTool.NormalizeOutputPaths(this.OutputPath, true);
// Replace all instances in the output directory
string outputDirectory = Path.GetDirectoryName(outputPath);
outputDirectory = outputDirectory.Replace(".", "_");
var outputDirectory = Path.GetDirectoryName(outputPath);
outputDirectory = outputDirectory?.Replace(".", "_");
// Replace all instances in the output filename
string outputFilename = Path.GetFileNameWithoutExtension(outputPath);
@@ -145,10 +169,20 @@ namespace MPF.Library
string outputExtension = Path.GetExtension(outputPath).TrimStart('.');
// Rebuild the output path
if (!string.IsNullOrWhiteSpace(outputExtension))
this.OutputPath = Path.Combine(outputDirectory, $"{outputFilename}.{outputExtension}");
if (string.IsNullOrWhiteSpace(outputDirectory))
{
if (string.IsNullOrWhiteSpace(outputExtension))
this.OutputPath = outputFilename;
else
this.OutputPath = $"{outputFilename}.{outputExtension}";
}
else
this.OutputPath = Path.Combine(outputDirectory, outputFilename);
{
if (string.IsNullOrWhiteSpace(outputExtension))
this.OutputPath = Path.Combine(outputDirectory, outputFilename);
else
this.OutputPath = Path.Combine(outputDirectory, $"{outputFilename}.{outputExtension}");
}
// Assign the path to the filename as well for dumping
((Modules.DiscImageCreator.Parameters)this.Parameters).Filename = this.OutputPath;
@@ -197,8 +231,11 @@ namespace MPF.Library
}
// Set system and type
this.Parameters.System = this.System;
this.Parameters.Type = this.Type;
if (this.Parameters != null)
{
this.Parameters.System = this.System;
this.Parameters.Type = this.Type;
}
}
/// <summary>
@@ -206,7 +243,11 @@ namespace MPF.Library
/// </summary>
/// <param name="driveSpeed">Nullable int representing the drive speed</param>
/// <returns>String representing the params, null on error</returns>
#if NET48
public string GetFullParameters(int? driveSpeed)
#else
public string? GetFullParameters(int? driveSpeed)
#endif
{
// Populate with the correct params for inputs (if we're not on the default option)
if (System != null && Type != MediaType.NONE)
@@ -250,26 +291,42 @@ namespace MPF.Library
/// <summary>
/// Cancel an in-progress dumping process
/// </summary>
public void CancelDumping() => Parameters.KillInternalProgram();
public void CancelDumping() => Parameters?.KillInternalProgram();
/// <summary>
/// Eject the disc using DiscImageCreator
/// </summary>
#if NET48
public async Task<string> EjectDisc() =>
await RunStandaloneDiscImageCreatorCommand(Modules.DiscImageCreator.CommandStrings.Eject);
#else
public async Task<string?> EjectDisc() =>
#endif
await RunStandaloneDiscImageCreatorCommand(Modules.DiscImageCreator.CommandStrings.Eject);
/// <summary>
/// Reset the current drive using DiscImageCreator
/// </summary>
#if NET48
public async Task<string> ResetDrive() =>
#else
public async Task<string?> ResetDrive() =>
#endif
await RunStandaloneDiscImageCreatorCommand(Modules.DiscImageCreator.CommandStrings.Reset);
/// <summary>
/// Execute the initial invocation of the dumping programs
/// </summary>
/// <param name="progress">Optional result progress callback</param>
#if NET48
public async Task<Result> Run(IProgress<Result> progress = null)
#else
public async Task<Result> Run(IProgress<Result>? progress = null)
#endif
{
// If we don't have parameters
if (this.Parameters == null)
return Result.Failure("Error! Current configuration is not supported!");
// Check that we have the basics for dumping
Result result = IsValidForDump();
if (!result)
@@ -279,12 +336,17 @@ namespace MPF.Library
if (!Options.ToolsInSeparateWindow)
{
outputQueue = new ProcessingQueue<string>(ProcessOutputs);
Parameters.ReportStatus += OutputToLog;
if (Parameters.ReportStatus != null)
Parameters.ReportStatus += OutputToLog;
}
// Execute internal tool
progress?.Report(Result.Success($"Executing {this.InternalProgram}... {(Options.ToolsInSeparateWindow ? "please wait!" : "see log for output!")}"));
Directory.CreateDirectory(Path.GetDirectoryName(this.OutputPath));
var directoryName = Path.GetDirectoryName(this.OutputPath);
if (!string.IsNullOrWhiteSpace(directoryName))
Directory.CreateDirectory(directoryName);
await Task.Run(() => Parameters.ExecuteInternalProgram(Options.ToolsInSeparateWindow));
progress?.Report(Result.Success($"{this.InternalProgram} has finished!"));
@@ -296,7 +358,7 @@ namespace MPF.Library
// Remove event handler if needed
if (!Options.ToolsInSeparateWindow)
{
outputQueue.Dispose();
outputQueue?.Dispose();
Parameters.ReportStatus -= OutputToLog;
}
@@ -311,15 +373,21 @@ namespace MPF.Library
/// <param name="processUserInfo">Optional user prompt to deal with submission information</param>
/// <returns>Result instance with the outcome</returns>
public async Task<Result> VerifyAndSaveDumpOutput(
#if NET48
IProgress<Result> resultProgress = null,
IProgress<ProtectionProgress> protectionProgress = null,
Func<SubmissionInfo, (bool?, SubmissionInfo)> processUserInfo = null)
#else
IProgress<Result>? resultProgress = null,
IProgress<ProtectionProgress>? protectionProgress = null,
Func<SubmissionInfo?, (bool?, SubmissionInfo?)>? processUserInfo = null)
#endif
{
resultProgress?.Report(Result.Success("Gathering submission information... please wait!"));
// Get the output directory and filename separately
string outputDirectory = Path.GetDirectoryName(this.OutputPath);
string outputFilename = Path.GetFileName(this.OutputPath);
var outputDirectory = Path.GetDirectoryName(this.OutputPath);
var outputFilename = Path.GetFileName(this.OutputPath);
// Check to make sure that the output had all the correct files
(bool foundFiles, List<string> missingFiles) = InfoTool.FoundAllFiles(outputDirectory, outputFilename, this.Parameters, false);
@@ -331,7 +399,7 @@ namespace MPF.Library
// Extract the information from the output files
resultProgress?.Report(Result.Success("Extracting output information from output files..."));
SubmissionInfo submissionInfo = await InfoTool.ExtractOutputInformation(
var submissionInfo = await InfoTool.ExtractOutputInformation(
this.OutputPath,
this.Drive,
this.System,
@@ -345,14 +413,14 @@ namespace MPF.Library
// Eject the disc automatically if configured to
if (Options.EjectAfterDump == true)
{
resultProgress?.Report(Result.Success($"Ejecting disc in drive {Drive.Letter}"));
resultProgress?.Report(Result.Success($"Ejecting disc in drive {Drive?.Letter}"));
await EjectDisc();
}
// Reset the drive automatically if configured to
if (this.InternalProgram == InternalProgram.DiscImageCreator && Options.DICResetDriveAfterDump)
{
resultProgress?.Report(Result.Success($"Resetting drive {Drive.Letter}"));
resultProgress?.Report(Result.Success($"Resetting drive {Drive?.Letter}"));
await ResetDrive();
}
@@ -377,7 +445,7 @@ namespace MPF.Library
// Format the information for the text output
resultProgress?.Report(Result.Success("Formatting information..."));
(List<string> formattedValues, string formatResult) = InfoTool.FormatOutputData(submissionInfo, this.Options);
(var formattedValues, var formatResult) = InfoTool.FormatOutputData(submissionInfo, this.Options);
if (formattedValues == null)
resultProgress?.Report(Result.Success(formatResult));
else
@@ -434,7 +502,11 @@ namespace MPF.Library
/// <returns>True if the configuration is valid, false otherwise</returns>
internal bool ParametersValid()
{
bool parametersValid = Parameters.IsValid();
// Missing drive means it can never be valid
if (Drive == null)
return false;
bool parametersValid = Parameters?.IsValid() ?? false;
bool floppyValid = !(Drive.InternalDriveType == InternalDriveType.Floppy ^ Type == MediaType.FloppyDisk);
// TODO: HardDisk being in the Removable category is a hack, fix this later
@@ -494,14 +566,14 @@ namespace MPF.Library
private Result IsValidForDump()
{
// Validate that everything is good
if (!ParametersValid())
if (this.Parameters == null || !ParametersValid())
return Result.Failure("Error! Current configuration is not supported!");
// Fix the output paths, just in case
this.OutputPath = InfoTool.NormalizeOutputPaths(this.OutputPath, true);
// Validate that the output path isn't on the dumping drive
if (this.OutputPath[0] == Drive.Letter)
if (Drive != null && this.OutputPath[0] == Drive.Letter)
return Result.Failure("Error! Cannot output to same drive that is being dumped!");
// Validate that the required program exists
@@ -510,7 +582,7 @@ namespace MPF.Library
// Validate that the dumping drive doesn't contain the executable
string fullExecutablePath = Path.GetFullPath(Parameters.ExecutablePath);
if (fullExecutablePath[0] == Drive.Letter)
if (Drive != null && fullExecutablePath[0] == Drive.Letter)
return Result.Failure("Error! Cannot dump same drive that executable resides on!");
// Validate that the current configuration is supported
@@ -539,14 +611,18 @@ namespace MPF.Library
/// </summary>
/// <param name="command">Command string to run</param>
/// <returns>The output of the command on success, null on error</returns>
#if NET48
private async Task<string> RunStandaloneDiscImageCreatorCommand(string command)
#else
private async Task<string?> RunStandaloneDiscImageCreatorCommand(string command)
#endif
{
// 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)
if (Drive == null || Drive.InternalDriveType != InternalDriveType.Optical)
return null;
CancelDumping();
@@ -561,6 +637,6 @@ namespace MPF.Library
return await ExecuteInternalProgram(parameters);
}
#endregion
#endregion
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.IO.Hashing;
using System.Linq;
using System.Security.Cryptography;
@@ -10,7 +11,7 @@ namespace MPF.Core.Hashing
[Flags]
public enum Hash
{
CRC = 1 << 0,
CRC32 = 1 << 0,
MD5 = 1 << 1,
SHA1 = 1 << 2,
SHA256 = 1 << 3,
@@ -18,8 +19,8 @@ namespace MPF.Core.Hashing
SHA512 = 1 << 5,
// Special combinations
Standard = CRC | MD5 | SHA1,
All = CRC | MD5 | SHA1 | SHA256 | SHA384 | SHA512,
Standard = CRC32 | MD5 | SHA1,
All = CRC32 | MD5 | SHA1 | SHA256 | SHA384 | SHA512,
}
/// <summary>
@@ -28,7 +29,12 @@ namespace MPF.Core.Hashing
public class Hasher
{
public Hash HashType { get; private set; }
private IDisposable _hasher;
#if NET48
private object _hasher;
#else
private object? _hasher;
#endif
public Hasher(Hash hashType)
{
@@ -43,8 +49,8 @@ namespace MPF.Core.Hashing
{
switch (HashType)
{
case Hash.CRC:
_hasher = new OptimizedCRC();
case Hash.CRC32:
_hasher = new Crc32();
break;
case Hash.MD5:
@@ -71,7 +77,8 @@ namespace MPF.Core.Hashing
public void Dispose()
{
_hasher.Dispose();
if (_hasher is IDisposable disposable)
disposable.Dispose();
}
/// <summary>
@@ -81,8 +88,8 @@ namespace MPF.Core.Hashing
{
switch (HashType)
{
case Hash.CRC:
(_hasher as OptimizedCRC).Update(buffer, 0, size);
case Hash.CRC32:
(_hasher as NonCryptographicHashAlgorithm)?.Append(buffer);
break;
case Hash.MD5:
@@ -90,7 +97,7 @@ namespace MPF.Core.Hashing
case Hash.SHA256:
case Hash.SHA384:
case Hash.SHA512:
(_hasher as HashAlgorithm).TransformBlock(buffer, 0, size, null, 0);
(_hasher as HashAlgorithm)?.TransformBlock(buffer, 0, size, null, 0);
break;
}
}
@@ -103,8 +110,8 @@ namespace MPF.Core.Hashing
byte[] emptyBuffer = new byte[0];
switch (HashType)
{
case Hash.CRC:
(_hasher as OptimizedCRC).Update(emptyBuffer, 0, 0);
case Hash.CRC32:
(_hasher as NonCryptographicHashAlgorithm)?.Append(emptyBuffer);
break;
case Hash.MD5:
@@ -112,7 +119,7 @@ namespace MPF.Core.Hashing
case Hash.SHA256:
case Hash.SHA384:
case Hash.SHA512:
(_hasher as HashAlgorithm).TransformFinalBlock(emptyBuffer, 0, 0);
(_hasher as HashAlgorithm)?.TransformFinalBlock(emptyBuffer, 0, 0);
break;
}
}
@@ -120,19 +127,26 @@ namespace MPF.Core.Hashing
/// <summary>
/// Get internal hash as a byte array
/// </summary>
#if NET48
public byte[] GetHash()
#else
public byte[]? GetHash()
#endif
{
if (_hasher == null)
return null;
switch (HashType)
{
case Hash.CRC:
return BitConverter.GetBytes((_hasher as OptimizedCRC).Value).Reverse().ToArray();
case Hash.CRC32:
return (_hasher as NonCryptographicHashAlgorithm)?.GetCurrentHash();
case Hash.MD5:
case Hash.SHA1:
case Hash.SHA256:
case Hash.SHA384:
case Hash.SHA512:
return (_hasher as HashAlgorithm).Hash;
return (_hasher as HashAlgorithm)?.Hash;
}
return null;
@@ -141,12 +155,16 @@ namespace MPF.Core.Hashing
/// <summary>
/// Get internal hash as a string
/// </summary>
#if NET48
public string GetHashString()
#else
public string? GetHashString()
#endif
{
byte[] hash = GetHash();
var hash = GetHash();
if (hash == null)
return null;
return ByteArrayToString(hash);
}
@@ -156,7 +174,11 @@ namespace MPF.Core.Hashing
/// <param name="bytes">Byte array to convert</param>
/// <returns>Hex string representing the byte array</returns>
/// <link>http://stackoverflow.com/questions/311165/how-do-you-convert-byte-array-to-hexadecimal-string-and-vice-versa</link>
#if NET48
private static string ByteArrayToString(byte[] bytes)
#else
private static string? ByteArrayToString(byte[]? bytes)
#endif
{
// If we get null in, we send null out
if (bytes == null)

View File

@@ -1,154 +0,0 @@
/*
Copyright (c) 2012-2015 Eugene Larchenko (spct@mail.ru)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
using System;
//namespace OptimizedCRC
namespace MPF.Core.Hashing
{
internal class OptimizedCRC : IDisposable
{
private const uint kCrcPoly = 0xEDB88320;
private const uint kInitial = 0xFFFFFFFF;
private const int CRC_NUM_TABLES = 8;
private static readonly uint[] Table;
static OptimizedCRC()
{
unchecked
{
Table = new uint[256 * CRC_NUM_TABLES];
int i;
for (i = 0; i < 256; i++)
{
uint r = (uint)i;
for (int j = 0; j < 8; j++)
{
r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
}
Table[i] = r;
}
for (; i < 256 * CRC_NUM_TABLES; i++)
{
uint r = Table[i - 256];
Table[i] = Table[r & 0xFF] ^ (r >> 8);
}
}
}
public uint UnsignedValue;
public OptimizedCRC()
{
Init();
}
/// <summary>
/// Reset CRC
/// </summary>
public void Init()
{
UnsignedValue = kInitial;
}
public int Value
{
get { return (int)~UnsignedValue; }
}
public void Update(byte[] data, int offset, int count)
{
new ArraySegment<byte>(data, offset, count); // check arguments
if (count == 0)
{
return;
}
var table = OptimizedCRC.Table;
uint crc = UnsignedValue;
for (; (offset & 7) != 0 && count != 0; count--)
{
crc = (crc >> 8) ^ table[(byte)crc ^ data[offset++]];
}
if (count >= 8)
{
/*
* Idea from 7-zip project sources (http://7-zip.org/sdk.html)
*/
int end = (count - 8) & ~7;
count -= end;
end += offset;
while (offset != end)
{
crc ^= (uint)(data[offset] + (data[offset + 1] << 8) + (data[offset + 2] << 16) + (data[offset + 3] << 24));
uint high = (uint)(data[offset + 4] + (data[offset + 5] << 8) + (data[offset + 6] << 16) + (data[offset + 7] << 24));
offset += 8;
crc = table[(byte)crc + 0x700]
^ table[(byte)(crc >>= 8) + 0x600]
^ table[(byte)(crc >>= 8) + 0x500]
^ table[/*(byte)*/(crc >> 8) + 0x400]
^ table[(byte)(high) + 0x300]
^ table[(byte)(high >>= 8) + 0x200]
^ table[(byte)(high >>= 8) + 0x100]
^ table[/*(byte)*/(high >> 8) + 0x000];
}
}
while (count-- != 0)
{
crc = (crc >> 8) ^ table[(byte)crc ^ data[offset++]];
}
UnsignedValue = crc;
}
static public int Compute(byte[] data, int offset, int count)
{
var crc = new OptimizedCRC();
crc.Update(data, offset, count);
return crc.Value;
}
static public int Compute(byte[] data)
{
return Compute(data, 0, data.Length);
}
static public int Compute(ArraySegment<byte> block)
{
return Compute(block.Array, block.Offset, block.Count);
}
public void Dispose()
{
UnsignedValue = 0;
}
}
}

View File

@@ -11,7 +11,11 @@ namespace MPF.Core.Hashing
private readonly AutoResetEvent _outEvent;
private readonly Thread _tWorker;
#if NET48
private byte[] _buffer;
#else
private byte[]? _buffer;
#endif
private int _size;
private readonly Stream _ds;
private bool _finished;
@@ -48,7 +52,8 @@ namespace MPF.Core.Hashing
}
try
{
SizeRead = _ds.Read(_buffer, 0, _size);
if (_buffer != null)
SizeRead = _ds.Read(_buffer, 0, _size);
}
catch (Exception)
{

File diff suppressed because it is too large Load Diff

View File

@@ -5,43 +5,29 @@
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Copyright>Copyright (c)2019-2023</Copyright>
<Version>2.6.6</Version>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<VersionPrefix>2.7.0</VersionPrefix>
</PropertyGroup>
<PropertyGroup>
<NrtRevisionFormat>$(Version)-{chash:8}</NrtRevisionFormat>
<NrtResolveSimpleAttributes>true</NrtResolveSimpleAttributes>
<NrtShowRevision>false</NrtShowRevision>
<PropertyGroup Condition="'$(TargetFramework)'!='net48'">
<Nullable>enable</Nullable>
</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>
<InternalsVisibleTo Include="MPF.Test" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="2.8.0" GeneratePathProperty="true">
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0-preview.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="SabreTools.Models" Version="1.1.4" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.1.1" />
<PackageReference Include="SabreTools.Serialization" Version="1.1.6" />
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" />
<PackageReference Include="System.IO.Hashing" Version="7.0.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
</ItemGroup>

View File

@@ -1,4 +1,4 @@
namespace MPF.Modules.Aaru
namespace MPF.Core.Modules.Aaru
{
/// <summary>
/// Top-level commands for Aaru

View File

@@ -1,6 +1,6 @@
using SabreTools.RedumpLib.Data;
namespace MPF.Modules.Aaru
namespace MPF.Core.Modules.Aaru
{
public static class Converters
{

View File

@@ -16,7 +16,7 @@ using Schemas;
// Ignore "Type or member is obsolete"
#pragma warning disable CS0618
namespace MPF.Modules.Aaru
namespace MPF.Core.Modules.Aaru
{
/// <summary>
/// Represents a generic set of Aaru parameters
@@ -26,10 +26,18 @@ namespace MPF.Modules.Aaru
#region Generic Dumping Information
/// <inheritdoc/>
#if NET48
public override string InputPath => InputValue;
#else
public override string? InputPath => InputValue;
#endif
/// <inheritdoc/>
#if NET48
public override string OutputPath => OutputValue;
#else
public override string? OutputPath => OutputValue;
#endif
/// <inheritdoc/>
public override int? Speed
@@ -51,69 +59,177 @@ namespace MPF.Modules.Aaru
public int? BlockSizeValue { get; set; }
#if NET48
public string CommentsValue { get; set; }
#else
public string? CommentsValue { get; set; }
#endif
#if NET48
public string CreatorValue { get; set; }
#else
public string? CreatorValue { get; set; }
#endif
public int? CountValue { get; set; }
#if NET48
public string DriveManufacturerValue { get; set; }
#else
public string? DriveManufacturerValue { get; set; }
#endif
#if NET48
public string DriveModelValue { get; set; }
#else
public string? DriveModelValue { get; set; }
#endif
#if NET48
public string DriveRevisionValue { get; set; }
#else
public string? DriveRevisionValue { get; set; }
#endif
#if NET48
public string DriveSerialValue { get; set; }
#else
public string? DriveSerialValue { get; set; }
#endif
#if NET48
public string EncodingValue { get; set; }
#else
public string? EncodingValue { get; set; }
#endif
#if NET48
public string FormatConvertValue { get; set; }
#else
public string? FormatConvertValue { get; set; }
#endif
#if NET48
public string FormatDumpValue { get; set; }
#else
public string? FormatDumpValue { get; set; }
#endif
#if NET48
public string GeometryValue { get; set; }
#else
public string? GeometryValue { get; set; }
#endif
#if NET48
public string ImgBurnLogValue { get; set; }
#else
public string? ImgBurnLogValue { get; set; }
#endif
#if NET48
public string InputValue { get; set; }
#else
public string? InputValue { get; set; }
#endif
#if NET48
public string Input1Value { get; set; }
#else
public string? Input1Value { get; set; }
#endif
#if NET48
public string Input2Value { get; set; }
#else
public string? Input2Value { get; set; }
#endif
public long? LengthValue { get; set; }
public int? MaxBlocksValue { get; set; }
#if NET48
public string MediaBarcodeValue { get; set; }
#else
public string? MediaBarcodeValue { get; set; }
#endif
public int? MediaLastSequenceValue { get; set; }
#if NET48
public string MediaManufacturerValue { get; set; }
#else
public string? MediaManufacturerValue { get; set; }
#endif
#if NET48
public string MediaModelValue { get; set; }
#else
public string? MediaModelValue { get; set; }
#endif
#if NET48
public string MediaPartNumberValue { get; set; }
#else
public string? MediaPartNumberValue { get; set; }
#endif
public int? MediaSequenceValue { get; set; }
#if NET48
public string MediaSerialValue { get; set; }
#else
public string? MediaSerialValue { get; set; }
#endif
#if NET48
public string MediaTitleValue { get; set; }
#else
public string? MediaTitleValue { get; set; }
#endif
#if NET48
public string MHDDLogValue { get; set; }
#else
public string? MHDDLogValue { get; set; }
#endif
#if NET48
public string NamespaceValue { get; set; }
#else
public string? NamespaceValue { get; set; }
#endif
#if NET48
public string OptionsValue { get; set; }
#else
public string? OptionsValue { get; set; }
#endif
#if NET48
public string OutputValue { get; set; }
#else
public string? OutputValue { get; set; }
#endif
#if NET48
public string OutputPrefixValue { get; set; }
#else
public string? OutputPrefixValue { get; set; }
#endif
#if NET48
public string RemoteHostValue { get; set; }
#else
public string? RemoteHostValue { get; set; }
#endif
#if NET48
public string ResumeFileValue { get; set; }
#else
public string? ResumeFileValue { get; set; }
#endif
public short? RetryPassesValue { get; set; }
@@ -123,11 +239,19 @@ namespace MPF.Modules.Aaru
public long? StartValue { get; set; }
#if NET48
public string SubchannelValue { get; set; }
#else
public string? SubchannelValue { get; set; }
#endif
public short? WidthValue { get; set; }
#if NET48
public string XMLSidecarValue { get; set; }
#else
public string? XMLSidecarValue { get; set; }
#endif
#endregion
@@ -195,12 +319,17 @@ namespace MPF.Modules.Aaru
}
/// <inheritdoc/>
#if NET48
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive drive, bool includeArtifacts)
#else
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive? drive, bool includeArtifacts)
#endif
{
// TODO: Fill in submission info specifics for Aaru
string outputDirectory = Path.GetDirectoryName(basePath);
var outputDirectory = Path.GetDirectoryName(basePath);
// TODO: Determine if there's an Aaru version anywhere
if (info.DumpingInfo == null) info.DumpingInfo = new DumpingInfoSection();
info.DumpingInfo.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
info.DumpingInfo.DumpingDate = GetFileModifiedDate(basePath + ".cicm.xml")?.ToString("yyyy-MM-dd HH:mm:ss");
@@ -208,7 +337,7 @@ namespace MPF.Modules.Aaru
var sidecar = GenerateSidecar(basePath + ".cicm.xml");
// Fill in the hardware data
if (GetHardwareInfo(sidecar, out string manufacturer, out string model, out string firmware))
if (GetHardwareInfo(sidecar, out var manufacturer, out var model, out var firmware))
{
info.DumpingInfo.Manufacturer = manufacturer;
info.DumpingInfo.Model = model;
@@ -216,7 +345,7 @@ namespace MPF.Modules.Aaru
}
// Fill in the disc type data
if (GetDiscType(sidecar, out string discType, out string discSubType))
if (GetDiscType(sidecar, out var discType, out var discSubType))
{
string fullDiscType = string.Empty;
if (!string.IsNullOrWhiteSpace(discType) && !string.IsNullOrWhiteSpace(discSubType))
@@ -230,9 +359,10 @@ namespace MPF.Modules.Aaru
}
// Get the Datafile information
Datafile datafile = GenerateDatafile(sidecar, basePath);
var datafile = GenerateDatafile(sidecar, basePath);
// Fill in the hash data
if (info.TracksAndWriteOffsets == null) info.TracksAndWriteOffsets = new TracksAndWriteOffsetsSection();
info.TracksAndWriteOffsets.ClrMameProData = GenerateDatfile(datafile);
switch (this.Type)
@@ -247,6 +377,7 @@ namespace MPF.Modules.Aaru
if (File.Exists(basePath + ".resume.xml"))
errorCount = GetErrorCount(basePath + ".resume.xml");
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
info.CommonDiscInfo.ErrorsCount = (errorCount == -1 ? "Error retrieving error count" : errorCount.ToString());
info.TracksAndWriteOffsets.Cuesheet = GenerateCuesheet(sidecar, basePath) ?? string.Empty;
@@ -259,8 +390,10 @@ namespace MPF.Modules.Aaru
case MediaType.DVD:
case MediaType.HDDVD:
case MediaType.BluRay:
if (info.SizeAndChecksums == null) info.SizeAndChecksums = new SizeAndChecksumsSection();
// Get the individual hash data, as per internal
if (GetISOHashValues(datafile, out long size, out string crc32, out string md5, out string sha1))
if (GetISOHashValues(datafile, out long size, out var crc32, out var md5, out var sha1))
{
info.SizeAndChecksums.Size = size;
info.SizeAndChecksums.CRC32 = crc32;
@@ -273,7 +406,11 @@ namespace MPF.Modules.Aaru
//info.Extras.PVD = GeneratePVD(sidecar) ?? "Disc has no PVD";
// Deal with the layerbreak
#if NET48
string layerbreak = null;
#else
string? layerbreak = null;
#endif
if (this.Type == MediaType.DVD)
layerbreak = GetLayerbreak(sidecar) ?? string.Empty;
else if (this.Type == MediaType.BluRay)
@@ -307,34 +444,51 @@ namespace MPF.Modules.Aaru
case RedumpSystem.DVDAudio:
case RedumpSystem.DVDVideo:
if (info.CopyProtection == null) info.CopyProtection = new CopyProtectionSection();
info.CopyProtection.Protection = GetDVDProtection(sidecar) ?? string.Empty;
break;
case RedumpSystem.KonamiPython2:
if (GetPlayStationExecutableInfo(drive?.Letter, out string pythonTwoSerial, out Region? pythonTwoRegion, out string pythonTwoDate))
if (GetPlayStationExecutableInfo(drive?.Letter, out var pythonTwoSerial, out Region? pythonTwoRegion, out var pythonTwoDate))
{
// Ensure internal serial is pulled from local data
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
#if NET48
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode?, string>();
#else
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode, string>();
#endif
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = pythonTwoSerial ?? string.Empty;
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? pythonTwoRegion;
info.CommonDiscInfo.EXEDateBuildDate = pythonTwoDate;
}
if (info.VersionAndEditions == null) info.VersionAndEditions = new VersionAndEditionsSection();
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? string.Empty;
break;
case RedumpSystem.MicrosoftXbox:
if (GetXgdAuxInfo(sidecar, out string xgd1DMIHash, out string xgd1PFIHash, out string xgd1SSHash, out string ss, out string xgd1SSVer))
if (GetXgdAuxInfo(sidecar, out var xgd1DMIHash, out var xgd1PFIHash, out var xgd1SSHash, out var ss, out var xgd1SSVer))
{
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.DMIHash] = xgd1DMIHash;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.PFIHash] = xgd1PFIHash;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSHash] = xgd1SSHash;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSVersion] = xgd1SSVer;
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
#if NET48
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode?, string>();
#else
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode, string>();
#endif
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.DMIHash] = xgd1DMIHash ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.PFIHash] = xgd1PFIHash ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSHash] = xgd1SSHash ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSVersion] = xgd1SSVer ?? string.Empty;
if (info.Extras == null) info.Extras = new ExtrasSection();
info.Extras.SecuritySectorRanges = ss ?? string.Empty;
}
if (GetXboxDMIInfo(sidecar, out string serial, out string version, out Region? region))
if (GetXboxDMIInfo(sidecar, out var serial, out var version, out Region? region))
{
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
info.CommonDiscInfo.Serial = serial ?? string.Empty;
if (info.VersionAndEditions == null) info.VersionAndEditions = new VersionAndEditionsSection();
info.VersionAndEditions.Version = version ?? string.Empty;
info.CommonDiscInfo.Region = region;
}
@@ -342,27 +496,42 @@ namespace MPF.Modules.Aaru
break;
case RedumpSystem.MicrosoftXbox360:
if (GetXgdAuxInfo(sidecar, out string xgd23DMIHash, out string xgd23PFIHash, out string xgd23SSHash, out string ss360, out string xgd23SSVer))
if (GetXgdAuxInfo(sidecar, out var xgd23DMIHash, out var xgd23PFIHash, out var xgd23SSHash, out var ss360, out var xgd23SSVer))
{
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.DMIHash] = xgd23DMIHash;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.PFIHash] = xgd23PFIHash;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSHash] = xgd23SSHash;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSVersion] = xgd23SSVer;
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
#if NET48
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode?, string>();
#else
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode, string>();
#endif
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.DMIHash] = xgd23DMIHash ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.PFIHash] = xgd23PFIHash ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSHash] = xgd23SSHash ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSVersion] = xgd23SSVer ?? string.Empty;
if (info.Extras == null) info.Extras = new ExtrasSection();
info.Extras.SecuritySectorRanges = ss360 ?? string.Empty;
}
if (GetXbox360DMIInfo(sidecar, out string serial360, out string version360, out Region? region360))
if (GetXbox360DMIInfo(sidecar, out var serial360, out var version360, out Region? region360))
{
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
info.CommonDiscInfo.Serial = serial360 ?? string.Empty;
if (info.VersionAndEditions == null) info.VersionAndEditions = new VersionAndEditionsSection();
info.VersionAndEditions.Version = version360 ?? string.Empty;
info.CommonDiscInfo.Region = region360;
}
break;
case RedumpSystem.SonyPlayStation:
if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationSerial, out Region? playstationRegion, out string playstationDate))
if (GetPlayStationExecutableInfo(drive?.Letter, out var playstationSerial, out Region? playstationRegion, out var playstationDate))
{
// Ensure internal serial is pulled from local data
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
#if NET48
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode?, string>();
#else
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode, string>();
#endif
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = playstationSerial ?? string.Empty;
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationRegion;
info.CommonDiscInfo.EXEDateBuildDate = playstationDate;
@@ -371,29 +540,57 @@ namespace MPF.Modules.Aaru
break;
case RedumpSystem.SonyPlayStation2:
if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationTwoSerial, out Region? playstationTwoRegion, out string playstationTwoDate))
if (GetPlayStationExecutableInfo(drive?.Letter, out var playstationTwoSerial, out Region? playstationTwoRegion, out var playstationTwoDate))
{
// Ensure internal serial is pulled from local data
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
#if NET48
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode?, string>();
#else
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode, string>();
#endif
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = playstationTwoSerial ?? string.Empty;
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationTwoRegion;
info.CommonDiscInfo.EXEDateBuildDate = playstationTwoDate;
}
if (info.VersionAndEditions == null) info.VersionAndEditions = new VersionAndEditionsSection();
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? string.Empty;
break;
case RedumpSystem.SonyPlayStation3:
if (info.VersionAndEditions == null) info.VersionAndEditions = new VersionAndEditionsSection();
info.VersionAndEditions.Version = GetPlayStation3Version(drive?.Letter) ?? string.Empty;
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
#if NET48
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode?, string>();
#else
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode, string>();
#endif
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = GetPlayStation3Serial(drive?.Letter) ?? string.Empty;
break;
case RedumpSystem.SonyPlayStation4:
if (info.VersionAndEditions == null) info.VersionAndEditions = new VersionAndEditionsSection();
info.VersionAndEditions.Version = GetPlayStation4Version(drive?.Letter) ?? string.Empty;
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
#if NET48
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode?, string>();
#else
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode, string>();
#endif
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = GetPlayStation4Serial(drive?.Letter) ?? string.Empty;
break;
case RedumpSystem.SonyPlayStation5:
if (info.VersionAndEditions == null) info.VersionAndEditions = new VersionAndEditionsSection();
info.VersionAndEditions.Version = GetPlayStation5Version(drive?.Letter) ?? string.Empty;
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
#if NET48
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode?, string>();
#else
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode, string>();
#endif
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = GetPlayStation5Serial(drive?.Letter) ?? string.Empty;
break;
}
@@ -401,23 +598,28 @@ namespace MPF.Modules.Aaru
// Fill in any artifacts that exist, Base64-encoded, if we need to
if (includeArtifacts)
{
if (info.Artifacts == null) info.Artifacts = new Dictionary<string, string>();
if (File.Exists(basePath + ".cicm.xml"))
info.Artifacts["cicm"] = GetBase64(GetFullFile(basePath + ".cicm.xml"));
info.Artifacts["cicm"] = GetBase64(GetFullFile(basePath + ".cicm.xml")) ?? string.Empty;
if (File.Exists(basePath + ".ibg"))
info.Artifacts["ibg"] = Convert.ToBase64String(File.ReadAllBytes(basePath + ".ibg"));
if (File.Exists(basePath + ".log"))
info.Artifacts["log"] = GetBase64(GetFullFile(basePath + ".log"));
info.Artifacts["log"] = GetBase64(GetFullFile(basePath + ".log")) ?? string.Empty;
if (File.Exists(basePath + ".mhddlog.bin"))
info.Artifacts["mhddlog_bin"] = Convert.ToBase64String(File.ReadAllBytes(basePath + ".mhddlog.bin"));
if (File.Exists(basePath + ".resume.xml"))
info.Artifacts["resume"] = GetBase64(GetFullFile(basePath + ".resume.xml"));
info.Artifacts["resume"] = GetBase64(GetFullFile(basePath + ".resume.xml")) ?? string.Empty;
if (File.Exists(basePath + ".sub.log"))
info.Artifacts["sub_log"] = GetBase64(GetFullFile(basePath + ".sub.log"));
info.Artifacts["sub_log"] = GetBase64(GetFullFile(basePath + ".sub.log")) ?? string.Empty;
}
}
/// <inheritdoc/>
#if NET48
public override string GenerateParameters()
#else
public override string? GenerateParameters()
#endif
{
List<string> parameters = new List<string>();
@@ -1677,7 +1879,11 @@ namespace MPF.Modules.Aaru
short? shortValue = null;
int? intValue = null;
long? longValue = null;
#if NET48
string stringValue = null;
#else
string? stringValue = null;
#endif
// Keep a count of keys to determine if we should break out to filename handling or not
int keyCount = Keys.Count();
@@ -2126,7 +2332,7 @@ namespace MPF.Modules.Aaru
return true;
}
#endregion
#endregion
#region Private Extra Methods
@@ -2135,7 +2341,11 @@ namespace MPF.Modules.Aaru
/// </summary>
/// <param name="baseCommand">Command string to normalize</param>
/// <returns>Normalized command</returns>
#if NET48
private string NormalizeCommand(List<string> parts, ref int start)
#else
private string? NormalizeCommand(List<string> parts, ref int start)
#endif
{
// Invalid start means invalid command
if (start < 0 || start >= parts.Count)
@@ -2146,7 +2356,7 @@ namespace MPF.Modules.Aaru
if (start + 1 < parts.Count)
partTwo = parts[start + 1];
string normalized = NormalizeCommand($"{partOne} {partTwo}".Trim());
var normalized = NormalizeCommand($"{partOne} {partTwo}".Trim());
// Null normalization means invalid command
if (normalized == null)
@@ -2164,7 +2374,11 @@ namespace MPF.Modules.Aaru
/// </summary>
/// <param name="baseCommand">Command string to normalize</param>
/// <returns>Normalized command</returns>
#if NET48
private string NormalizeCommand(string baseCommand)
#else
private string? NormalizeCommand(string baseCommand)
#endif
{
// If the base command is inavlid, just return nulls
if (string.IsNullOrWhiteSpace(baseCommand))
@@ -2172,7 +2386,11 @@ namespace MPF.Modules.Aaru
// Split the command otherwise
string[] splitCommand = baseCommand.Split(' ');
#if NET48
string family, command;
#else
string? family, command;
#endif
// For commands with a family
@@ -2436,7 +2654,11 @@ namespace MPF.Modules.Aaru
/// <param name="cicmSidecar">CICM Sidecar data generated by Aaru</param>
/// <param name="basePath">Base path for determining file names</param>
/// <returns>String containing the cuesheet, null on error</returns>
#if NET48
private string GenerateCuesheet(CICMMetadataType cicmSidecar, string basePath)
#else
private string? GenerateCuesheet(CICMMetadataType? cicmSidecar, string basePath)
#endif
{
// If the object is null, we can't get information from it
if (cicmSidecar == null)
@@ -2559,6 +2781,9 @@ namespace MPF.Modules.Aaru
if (cueSheet != null && cueSheet != default)
{
var ms = new SabreTools.Serialization.Streams.CueSheet().Serialize(cueSheet);
if (ms == null)
return null;
using (var sr = new StreamReader(ms))
{
return sr.ReadToEnd();
@@ -2574,7 +2799,11 @@ namespace MPF.Modules.Aaru
/// <param name="cicmSidecar">CICM Sidecar data generated by Aaru</param>
/// <param name="basePath">Base path for determining file names</param>
/// <returns>String containing the datfile, null on error</returns>
#if NET48
private static string GenerateDatfile(CICMMetadataType cicmSidecar, string basePath)
#else
private static string? GenerateDatfile(CICMMetadataType? cicmSidecar, string basePath)
#endif
{
// If the object is null, we can't get information from it
if (cicmSidecar == null)
@@ -2682,7 +2911,11 @@ namespace MPF.Modules.Aaru
/// <param name="cicmSidecar">CICM Sidecar data generated by Aaru</param>
/// <param name="basePath">Base path for determining file names</param>
/// <returns>Datafile containing the hash information, null on error</returns>
#if NET48
private static Datafile GenerateDatafile(CICMMetadataType cicmSidecar, string basePath)
#else
private static Datafile? GenerateDatafile(CICMMetadataType? cicmSidecar, string basePath)
#endif
{
// If the object is null, we can't get information from it
if (cicmSidecar == null)
@@ -2819,19 +3052,23 @@ namespace MPF.Modules.Aaru
/// </summary>
/// <param name="cicmSidecar">CICM Sidecar data generated by Aaru</param>
/// <returns>String containing the PVD, null on error</returns>
#if NET48
private static string GeneratePVD(CICMMetadataType cicmSidecar)
#else
private static string? GeneratePVD(CICMMetadataType? cicmSidecar)
#endif
{
// If the object is null, we can't get information from it
if (cicmSidecar == null)
return null;
// Process OpticalDisc, if possible
if (cicmSidecar.OpticalDisc != null || cicmSidecar.OpticalDisc.Length > 0)
if (cicmSidecar.OpticalDisc != null && cicmSidecar.OpticalDisc.Length > 0)
{
// Loop through each OpticalDisc in the metadata
foreach (OpticalDiscType opticalDisc in cicmSidecar.OpticalDisc)
{
byte[] pvdData = GeneratePVDData(opticalDisc);
var pvdData = GeneratePVDData(opticalDisc);
// If we got a null value, we skip this disc
if (pvdData == null)
@@ -2858,7 +3095,11 @@ namespace MPF.Modules.Aaru
/// </summary>
/// <param name="opticalDisc">OpticalDisc type from CICM Sidecar data</param>
/// <returns>Byte array representing the PVD, null on error</returns>
#if NET48
private static byte[] GeneratePVDData(OpticalDiscType opticalDisc)
#else
private static byte[]? GeneratePVDData(OpticalDiscType? opticalDisc)
#endif
{
// Required variables
DateTime creation = DateTime.MinValue;
@@ -2867,7 +3108,7 @@ namespace MPF.Modules.Aaru
DateTime effective = DateTime.MinValue;
// If there are no tracks, we can't get a PVD
if (opticalDisc.Track == null || opticalDisc.Track.Length == 0)
if (opticalDisc?.Track == null || opticalDisc.Track.Length == 0)
return null;
// Take the first track only
@@ -2995,7 +3236,11 @@ namespace MPF.Modules.Aaru
/// <param name="row">Row ID for outputting</param>
/// <param name="bytes">Byte span representing the data to write</param>
/// <returns>Formatted string representing the sector line</returns>
#if NET48
private static string GenerateSectorOutputLine(string row, ReadOnlySpan<byte> bytes)
#else
private static string? GenerateSectorOutputLine(string row, ReadOnlySpan<byte> bytes)
#endif
{
// If the data isn't correct, return null
if (bytes == null || bytes.Length != 16)
@@ -3017,7 +3262,11 @@ namespace MPF.Modules.Aaru
/// </summary>
/// <param name="cicmSidecar">CICM Sidecar data generated by Aaru</param>
/// <returns>Object containing the data, null on error</returns>
#if NET48
private static CICMMetadataType GenerateSidecar(string cicmSidecar)
#else
private static CICMMetadataType? GenerateSidecar(string cicmSidecar)
#endif
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(cicmSidecar))
@@ -3039,9 +3288,7 @@ namespace MPF.Modules.Aaru
return null;
XmlSerializer serializer = new XmlSerializer(typeof(CICMMetadataType));
CICMMetadataType obj = serializer.Deserialize(xtr) as CICMMetadataType;
return obj;
return serializer.Deserialize(xtr) as CICMMetadataType;
}
/// <summary>
@@ -3049,7 +3296,11 @@ namespace MPF.Modules.Aaru
/// </summary>
/// <param name="cicmSidecar">CICM Sidecar data generated by Aaru</param>
/// <returns>True if disc type info was set, false otherwise</returns>
#if NET48
private static bool GetDiscType(CICMMetadataType cicmSidecar, out string discType, out string discSubType)
#else
private static bool GetDiscType(CICMMetadataType? cicmSidecar, out string? discType, out string? discSubType)
#endif
{
// Set the default values
discType = null; discSubType = null;
@@ -3080,7 +3331,11 @@ namespace MPF.Modules.Aaru
/// </summary>
/// <param name="cicmSidecar">CICM Sidecar data generated by Aaru</param>
/// <returns>Formatted string representing the DVD protection, null on error</returns>
#if NET48
private static string GetDVDProtection(CICMMetadataType cicmSidecar)
#else
private static string? GetDVDProtection(CICMMetadataType? cicmSidecar)
#endif
{
// If the object is null, we can't get information from it
if (cicmSidecar == null)
@@ -3146,10 +3401,12 @@ namespace MPF.Modules.Aaru
// Read in the error count whenever we find it
while (!sr.EndOfStream)
{
string line = sr.ReadLine().Trim();
var line = sr.ReadLine()?.Trim();
// Initialize on seeing the open tag
if (line.StartsWith("<BadBlocks>"))
if (string.IsNullOrWhiteSpace(line))
continue;
else if (line.StartsWith("<BadBlocks>"))
totalErrors = 0;
else if (line.StartsWith("</BadBlocks>"))
return totalErrors ?? -1;
@@ -3173,7 +3430,11 @@ namespace MPF.Modules.Aaru
/// </summary>
/// <param name="cicmSidecar">CICM Sidecar data generated by Aaru</param>
/// <returns>True if hardware info was set, false otherwise</returns>
#if NET48
private static bool GetHardwareInfo(CICMMetadataType cicmSidecar, out string manufacturer, out string model, out string firmware)
#else
private static bool GetHardwareInfo(CICMMetadataType? cicmSidecar, out string? manufacturer, out string? model, out string? firmware)
#endif
{
// Set the default values
manufacturer = null; model = null; firmware = null;
@@ -3217,7 +3478,11 @@ namespace MPF.Modules.Aaru
/// </summary>
/// <param name="cicmSidecar">CICM Sidecar data generated by Aaru</param>
/// <returns>Layerbreak if possible, null on error</returns>
#if NET48
private static string GetLayerbreak(CICMMetadataType cicmSidecar)
#else
private static string? GetLayerbreak(CICMMetadataType? cicmSidecar)
#endif
{
// If the object is null, we can't get information from it
if (cicmSidecar == null)
@@ -3228,7 +3493,11 @@ namespace MPF.Modules.Aaru
return null;
// Setup the layerbreak
#if NET48
string layerbreak = null;
#else
string? layerbreak = null;
#endif
// Find and return the layerbreak, if possible
foreach (OpticalDiscType opticalDisc in cicmSidecar.OpticalDisc)
@@ -3248,7 +3517,11 @@ namespace MPF.Modules.Aaru
/// </summary>
/// <param name="cicmSidecar">CICM Sidecar data generated by Aaru</param>
/// <returns>Sample write offset if possible, null on error</returns>
#if NET48
private static string GetWriteOffset(CICMMetadataType cicmSidecar)
#else
private static string? GetWriteOffset(CICMMetadataType? cicmSidecar)
#endif
{
// If the object is null, we can't get information from it
if (cicmSidecar == null)
@@ -3276,7 +3549,11 @@ namespace MPF.Modules.Aaru
/// </summary>
/// <param name="cicmSidecar">CICM Sidecar data generated by Aaru</param>
/// <returns>True on successful extraction of info, false otherwise</returns>
#if NET48
private static bool GetXgdAuxInfo(CICMMetadataType cicmSidecar, out string dmihash, out string pfihash, out string sshash, out string ss, out string ssver)
#else
private static bool GetXgdAuxInfo(CICMMetadataType? cicmSidecar, out string? dmihash, out string? pfihash, out string? sshash, out string? ss, out string? ssver)
#endif
{
dmihash = null; pfihash = null; sshash = null; ss = null; ssver = null;
@@ -3371,7 +3648,11 @@ namespace MPF.Modules.Aaru
/// </summary>
/// <param name="cicmSidecar">CICM Sidecar data generated by Aaru</param>
/// <returns>True on successful extraction of info, false otherwise</returns>
#if NET48
private static bool GetXboxDMIInfo(CICMMetadataType cicmSidecar, out string serial, out string version, out Region? region)
#else
private static bool GetXboxDMIInfo(CICMMetadataType? cicmSidecar, out string? serial, out string? version, out Region? region)
#endif
{
serial = null; version = null; region = Region.World;
@@ -3419,7 +3700,11 @@ namespace MPF.Modules.Aaru
/// </summary>
/// <param name="cicmSidecar">CICM Sidecar data generated by Aaru</param>
/// <returns>True on successful extraction of info, false otherwise</returns>
#if NET48
private static bool GetXbox360DMIInfo(CICMMetadataType cicmSidecar, out string serial, out string version, out Region? region)
#else
private static bool GetXbox360DMIInfo(CICMMetadataType? cicmSidecar, out string? serial, out string? version, out Region? region)
#endif
{
serial = null; version = null; region = Region.World;

View File

@@ -15,7 +15,7 @@ using MPF.Core.Utilities;
using SabreTools.Models.PIC;
using SabreTools.RedumpLib.Data;
namespace MPF.Modules
namespace MPF.Core.Modules
{
public abstract class BaseParameters
{
@@ -25,7 +25,11 @@ namespace MPF.Modules
/// Geneeic way of reporting a message
/// </summary>
/// <param name="message">String value to report</param>
#if NET48
public EventHandler<string> ReportStatus;
#else
public EventHandler<string>? ReportStatus;
#endif
#endregion
@@ -34,7 +38,11 @@ namespace MPF.Modules
/// <summary>
/// Base command to run
/// </summary>
#if NET48
public string BaseCommand { get; set; }
#else
public string? BaseCommand { get; set; }
#endif
/// <summary>
/// Set of flags to pass to the executable
@@ -63,7 +71,11 @@ namespace MPF.Modules
/// <summary>
/// Process to track external program
/// </summary>
#if NET48
private Process process;
#else
private Process? process;
#endif
#endregion
@@ -72,18 +84,30 @@ namespace MPF.Modules
/// <summary>
/// Command to flag support mappings
/// </summary>
#if NET48
public Dictionary<string, List<string>> CommandSupport => GetCommandSupport();
#else
public Dictionary<string, List<string>>? CommandSupport => GetCommandSupport();
#endif
/// <summary>
/// Input path for operations
/// </summary>
#if NET48
public virtual string InputPath => null;
#else
public virtual string? InputPath => null;
#endif
/// <summary>
/// Output path for operations
/// </summary>
/// <returns>String representing the path, null on error</returns>
#if NET48
public virtual string OutputPath => null;
#else
public virtual string? OutputPath => null;
#endif
/// <summary>
/// Get the processing speed from the implementation
@@ -97,7 +121,11 @@ namespace MPF.Modules
/// <summary>
/// Path to the executable
/// </summary>
#if NET48
public string ExecutablePath { get; set; }
#else
public string? ExecutablePath { get; set; }
#endif
/// <summary>
/// Program that this set of parameters represents
@@ -161,7 +189,11 @@ namespace MPF.Modules
/// <param name="basePath">Base filename and path to use for checking</param>
/// <param name="drive">Drive representing the disc to get information from</param>
/// <param name="includeArtifacts">True to include output files as encoded artifacts, false otherwise</param>
#if NET48
public abstract void GenerateSubmissionInfo(SubmissionInfo submissionInfo, Options options, string basePath, Drive drive, bool includeArtifacts);
#else
public abstract void GenerateSubmissionInfo(SubmissionInfo submissionInfo, Options options, string basePath, Drive? drive, bool includeArtifacts);
#endif
#endregion
@@ -171,20 +203,32 @@ namespace MPF.Modules
/// Get all commands mapped to the supported flags
/// </summary>
/// <returns>Mappings from command to supported flags</returns>
#if NET48
public virtual Dictionary<string, List<string>> GetCommandSupport() => null;
#else
public virtual Dictionary<string, List<string>>? GetCommandSupport() => null;
#endif
/// <summary>
/// Blindly generate a parameter string based on the inputs
/// </summary>
/// <returns>Parameter string for invocation, null on error</returns>
#if NET48
public virtual string GenerateParameters() => null;
#else
public virtual string? GenerateParameters() => null;
#endif
/// <summary>
/// Get the default extension for a given media type
/// </summary>
/// <param name="mediaType">MediaType value to check</param>
/// <returns>String representing the media type, null on error</returns>
#if NET48
public virtual string GetDefaultExtension(MediaType? mediaType) => null;
#else
public virtual string? GetDefaultExtension(MediaType? mediaType) => null;
#endif
/// <summary>
/// Generate a list of all log files generated
@@ -320,7 +364,11 @@ namespace MPF.Modules
/// </summary>
/// <param name="content">String content to encode</param>
/// <returns>Base64-encoded contents, if possible</returns>
#if NET48
protected static string GetBase64(string content)
#else
protected static string? GetBase64(string? content)
#endif
{
if (string.IsNullOrEmpty(content))
return null;
@@ -335,7 +383,11 @@ namespace MPF.Modules
/// <param name="filename">file location</param>
/// <param name="binary">True if should read as binary, false otherwise (default)</param>
/// <returns>Full text of the file, null on error</returns>
#if NET48
protected static string GetFullFile(string filename, bool binary = false)
#else
protected static string? GetFullFile(string filename, bool binary = false)
#endif
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(filename))
@@ -465,7 +517,11 @@ namespace MPF.Modules
/// <param name="longFlagString">Long flag string, if available</param>
/// <param name="i">Reference to the position in the parts</param>
/// <returns>True if the parameter was processed successfully or skipped, false otherwise</returns>
#if NET48
protected bool ProcessFlagParameter(List<string> parts, string shortFlagString, string longFlagString, ref int i)
#else
protected bool ProcessFlagParameter(List<string> parts, string? shortFlagString, string longFlagString, ref int i)
#endif
{
if (parts == null)
return false;
@@ -501,7 +557,11 @@ namespace MPF.Modules
/// <param name="i">Reference to the position in the parts</param>
/// <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>
#if NET48
protected bool ProcessBooleanParameter(List<string> parts, string shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
#else
protected bool ProcessBooleanParameter(List<string> parts, string? shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
#endif
{
if (parts == null)
return false;
@@ -576,7 +636,11 @@ namespace MPF.Modules
/// <param name="i">Reference to the position in the parts</param>
/// <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>
#if NET48
protected sbyte? ProcessInt8Parameter(List<string> parts, string shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
#else
protected sbyte? ProcessInt8Parameter(List<string> parts, string? shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
#endif
{
if (parts == null)
return null;
@@ -654,7 +718,11 @@ namespace MPF.Modules
/// <param name="i">Reference to the position in the parts</param>
/// <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>
#if NET48
protected short? ProcessInt16Parameter(List<string> parts, string shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
#else
protected short? ProcessInt16Parameter(List<string> parts, string? shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
#endif
{
if (parts == null)
return null;
@@ -731,7 +799,11 @@ namespace MPF.Modules
/// <param name="i">Reference to the position in the parts</param>
/// <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>
#if NET48
protected int? ProcessInt32Parameter(List<string> parts, string shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
#else
protected int? ProcessInt32Parameter(List<string> parts, string? shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
#endif
{
if (parts == null)
return null;
@@ -808,7 +880,11 @@ namespace MPF.Modules
/// <param name="i">Reference to the position in the parts</param>
/// <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>
#if NET48
protected long? ProcessInt64Parameter(List<string> parts, string shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
#else
protected long? ProcessInt64Parameter(List<string> parts, string? shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
#endif
{
if (parts == null)
return null;
@@ -873,8 +949,12 @@ namespace MPF.Modules
/// <param name="i">Reference to the position in the parts</param>
/// <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>
#if NET48
protected string ProcessStringParameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
=> ProcessStringParameter(parts, null, flagString, ref i, missingAllowed);
#else
protected string? ProcessStringParameter(List<string> parts, string flagString, ref int i, bool missingAllowed = false)
#endif
=> ProcessStringParameter(parts, null, flagString, ref i, missingAllowed);
/// <summary>
/// Process a string parameter
@@ -885,7 +965,11 @@ namespace MPF.Modules
/// <param name="i">Reference to the position in the parts</param>
/// <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>
#if NET48
protected string ProcessStringParameter(List<string> parts, string shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
#else
protected string? ProcessStringParameter(List<string> parts, string? shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
#endif
{
if (parts == null)
return null;
@@ -960,7 +1044,11 @@ namespace MPF.Modules
/// <param name="i">Reference to the position in the parts</param>
/// <param name="missingAllowed">True if missing values are allowed, false otherwise</param>
/// <returns>Byte value if success, Byte.MinValue if skipped, null on error/returns>
#if NET48
protected byte? ProcessUInt8Parameter(List<string> parts, string shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
#else
protected byte? ProcessUInt8Parameter(List<string> parts, string? shortFlagString, string longFlagString, ref int i, bool missingAllowed = false)
#endif
{
if (parts == null)
return null;
@@ -1089,17 +1177,23 @@ namespace MPF.Modules
/// </summary>
/// <param name="datafile">.dat file location</param>
/// <returns>Relevant pieces of the datfile, null on error</returns>
#if NET48
protected static string GenerateDatfile(Datafile datafile)
#else
protected static string? GenerateDatfile(Datafile? datafile)
#endif
{
// If we don't have a valid datafile, we can't do anything
if (datafile?.Games == null || datafile.Games.Length == 0 || datafile.Games[0]?.Roms == null || datafile.Games[0].Roms.Length == 0)
if (datafile?.Games == null || datafile.Games.Length == 0)
return null;
var roms = datafile.Games[0].Roms;
if (roms == null || roms.Length == 0)
return null;
// Otherwise, reconstruct the hash data with only the required info
try
{
var roms = datafile.Games[0].Roms;
string datString = string.Empty;
for (int i = 0; i < roms.Length; i++)
{
@@ -1121,7 +1215,11 @@ namespace MPF.Modules
/// </summary>
/// <param name="dat">Path to the DAT file to parse</param>
/// <returns>Filled Datafile on success, null on error</returns>
#if NET48
protected static Datafile GetDatafile(string dat)
#else
protected static Datafile? GetDatafile(string? dat)
#endif
{
// If there's no path, we can't read the file
if (string.IsNullOrWhiteSpace(dat))
@@ -1149,9 +1247,7 @@ namespace MPF.Modules
return null;
var serializer = new XmlSerializer(typeof(Datafile));
Datafile obj = serializer.Deserialize(xtr) as Datafile;
return obj;
return serializer.Deserialize(xtr) as Datafile;
}
catch
{
@@ -1166,7 +1262,11 @@ namespace MPF.Modules
/// <param name="pic">Path to a PIC.bin file</param>
/// <returns>Filled DiscInformation on success, null on error</returns>
/// <remarks>This omits the emergency brake information, if it exists</remarks>
#if NET48
protected static DiscInformation GetDiscInformation(string pic)
#else
protected static DiscInformation? GetDiscInformation(string pic)
#endif
{
try
{
@@ -1184,7 +1284,11 @@ namespace MPF.Modules
/// </summary>
/// <param name="filename">Path to the input file</param>
/// <returns>True if hashing was successful, false otherwise</returns>
#if NET48
protected static bool GetFileHashes(string filename, out long size, out string crc32, out string md5, out string sha1)
#else
protected static bool GetFileHashes(string filename, out long size, out string? crc32, out string? md5, out string? sha1)
#endif
{
// Set all initial values
size = -1; crc32 = null; md5 = null; sha1 = null;
@@ -1204,7 +1308,7 @@ namespace MPF.Modules
// Get a list of hashers to run over the buffer
var hashers = new List<Hasher>
{
new Hasher(Hash.CRC),
new Hasher(Hash.CRC32),
new Hasher(Hash.MD5),
new Hasher(Hash.SHA1),
new Hasher(Hash.SHA256),
@@ -1261,7 +1365,7 @@ namespace MPF.Modules
Parallel.ForEach(hashers, h => h.Terminate());
// Get the results
crc32 = hashers.First(h => h.HashType == Hash.CRC).GetHashString();
crc32 = hashers.First(h => h.HashType == Hash.CRC32).GetHashString();
md5 = hashers.First(h => h.HashType == Hash.MD5).GetHashString();
sha1 = hashers.First(h => h.HashType == Hash.SHA1).GetHashString();
//sha256 = hashers.First(h => h.HashType == Hash.SHA256).GetHashString();
@@ -1289,7 +1393,11 @@ namespace MPF.Modules
/// </summary>
/// <param name="filename">Path to the input file</param>
/// <returns>Filled DateTime on success, null on failure</returns>
#if NET48
protected static DateTime? GetFileModifiedDate(string filename, bool fallback = false)
#else
protected static DateTime? GetFileModifiedDate(string? filename, bool fallback = false)
#endif
{
if (string.IsNullOrWhiteSpace(filename))
return fallback ? (DateTime?)DateTime.UtcNow : null;
@@ -1305,7 +1413,11 @@ namespace MPF.Modules
/// </summary>
/// <param name="hashData">String representing the combined hash data</param>
/// <returns>True if extraction was successful, false otherwise</returns>
#if NET48
protected static bool GetISOHashValues(string hashData, out long size, out string crc32, out string md5, out string sha1)
#else
protected static bool GetISOHashValues(string? hashData, out long size, out string? crc32, out string? md5, out string? sha1)
#endif
{
size = -1; crc32 = null; md5 = null; sha1 = null;
@@ -1335,14 +1447,22 @@ namespace MPF.Modules
/// </summary>
/// <param name="datafile">Datafile represenging the hash data</param>
/// <returns>True if extraction was successful, false otherwise</returns>
#if NET48
protected static bool GetISOHashValues(Datafile datafile, out long size, out string crc32, out string md5, out string sha1)
#else
protected static bool GetISOHashValues(Datafile? datafile, out long size, out string? crc32, out string? md5, out string? sha1)
#endif
{
size = -1; crc32 = null; md5 = null; sha1 = null;
if (datafile?.Games == null || datafile.Games.Length == 0 || datafile.Games[0].Roms.Length == 0)
if (datafile?.Games == null || datafile.Games.Length == 0)
return false;
var rom = datafile.Games[0].Roms[0];
var roms = datafile.Games[0].Roms;
if (roms == null || roms.Length == 0)
return false;
var rom = roms[0];
_ = Int64.TryParse(rom.Size, out size);
crc32 = rom.Crc;
@@ -1357,7 +1477,11 @@ namespace MPF.Modules
/// </summary>
/// <param name="di">Disc information containing unformatted data</param>
/// <returns>True if layerbreak info was set, false otherwise</returns>
#if NET48
protected static bool GetLayerbreaks(DiscInformation di, out long? layerbreak1, out long? layerbreak2, out long? layerbreak3)
#else
protected static bool GetLayerbreaks(DiscInformation? di, out long? layerbreak1, out long? layerbreak2, out long? layerbreak3)
#endif
{
// Set the default values
layerbreak1 = null; layerbreak2 = null; layerbreak3 = null;
@@ -1369,9 +1493,12 @@ namespace MPF.Modules
#if NET48
int ReadFromArrayBigEndian(byte[] bytes, int offset)
#else
static int ReadFromArrayBigEndian(byte[] bytes, int offset)
static int ReadFromArrayBigEndian(byte[]? bytes, int offset)
#endif
{
if (bytes == null)
return default;
var span = new ReadOnlySpan<byte>(bytes, offset, 0x04);
byte[] rev = span.ToArray();
Array.Reverse(rev);
@@ -1381,24 +1508,24 @@ namespace MPF.Modules
// Layerbreak 1 (2+ layers)
if (di.Units.Length >= 2)
{
long offset = ReadFromArrayBigEndian(di.Units[0].Body.FormatDependentContents, 0x0C);
long value = ReadFromArrayBigEndian(di.Units[0].Body.FormatDependentContents, 0x10);
long offset = ReadFromArrayBigEndian(di.Units[0]?.Body?.FormatDependentContents, 0x0C);
long value = ReadFromArrayBigEndian(di.Units[0]?.Body?.FormatDependentContents, 0x10);
layerbreak1 = value - offset + 2;
}
// Layerbreak 2 (3+ layers)
if (di.Units.Length >= 3)
{
long offset = ReadFromArrayBigEndian(di.Units[1].Body.FormatDependentContents, 0x0C);
long value = ReadFromArrayBigEndian(di.Units[1].Body.FormatDependentContents, 0x10);
long offset = ReadFromArrayBigEndian(di.Units[1]?.Body?.FormatDependentContents, 0x0C);
long value = ReadFromArrayBigEndian(di.Units[1]?.Body?.FormatDependentContents, 0x10);
layerbreak2 = layerbreak1 + value - offset + 2;
}
// Layerbreak 3 (4 layers)
if (di.Units.Length >= 4)
{
long offset = ReadFromArrayBigEndian(di.Units[2].Body.FormatDependentContents, 0x0C);
long value = ReadFromArrayBigEndian(di.Units[2].Body.FormatDependentContents, 0x10);
long offset = ReadFromArrayBigEndian(di.Units[2]?.Body?.FormatDependentContents, 0x0C);
long value = ReadFromArrayBigEndian(di.Units[2]?.Body?.FormatDependentContents, 0x10);
layerbreak3 = layerbreak2 + value - offset + 2;
}
@@ -1410,14 +1537,18 @@ namespace MPF.Modules
/// </summary>
/// <param name="di">Disc information containing the data</param>
/// <returns>String representing the PIC identifier, null on error</returns>
#if NET48
protected static string GetPICIdentifier(DiscInformation di)
#else
protected static string? GetPICIdentifier(DiscInformation? di)
#endif
{
// If we don't have valid disc information, we can't do anything
if (di?.Units == null || di.Units.Length <= 1)
return null;
// We assume the identifier is consistent across all units
return di.Units[0].Body.DiscTypeIdentifier;
return di.Units[0]?.Body?.DiscTypeIdentifier;
}
/// <summary>
@@ -1428,7 +1559,11 @@ namespace MPF.Modules
/// <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>
#if NET48
protected static bool GetPlayStationExecutableInfo(char? driveLetter, out string serial, out Region? region, out string date)
#else
protected static bool GetPlayStationExecutableInfo(char? driveLetter, out string? serial, out Region? region, out string? date)
#endif
{
serial = null; region = null; date = null;
@@ -1446,7 +1581,11 @@ namespace MPF.Modules
string systemCnfPath = Path.Combine(drivePath, "SYSTEM.CNF");
// Try both of the common paths that contain information
#if NET48
string exeName = null;
#else
string? exeName = null;
#endif
// Read the CNF file as an INI file
var systemCnf = new IniFile(systemCnfPath);
@@ -1512,7 +1651,11 @@ namespace MPF.Modules
/// </summary>
/// <param name="driveLetter">Drive letter to use to check</param>
/// <returns>Game version if possible, null on error</returns>
#if NET48
protected static string GetPlayStation2Version(char? driveLetter)
#else
protected static string? GetPlayStation2Version(char? driveLetter)
#endif
{
// If there's no drive letter, we can't do this part
if (driveLetter == null)
@@ -1540,7 +1683,11 @@ namespace MPF.Modules
/// </summary>
/// <param name="driveLetter">Drive letter to use to check</param>
/// <returns>Internal disc serial if possible, null on error</returns>
#if NET48
protected static string GetPlayStation3Serial(char? driveLetter)
#else
protected static string? GetPlayStation3Serial(char? driveLetter)
#endif
{
// If there's no drive letter, we can't do this part
if (driveLetter == null)
@@ -1577,7 +1724,11 @@ namespace MPF.Modules
/// </summary>
/// <param name="driveLetter">Drive letter to use to check</param>
/// <returns>Game version if possible, null on error</returns>
#if NET48
protected static string GetPlayStation3Version(char? driveLetter)
#else
protected static string? GetPlayStation3Version(char? driveLetter)
#endif
{
// If there's no drive letter, we can't do this part
if (driveLetter == null)
@@ -1614,7 +1765,11 @@ namespace MPF.Modules
/// </summary>
/// <param name="driveLetter">Drive letter to use to check</param>
/// <returns>Internal disc serial if possible, null on error</returns>
#if NET48
protected static string GetPlayStation4Serial(char? driveLetter)
#else
protected static string? GetPlayStation4Serial(char? driveLetter)
#endif
{
// If there's no drive letter, we can't do this part
if (driveLetter == null)
@@ -1645,13 +1800,17 @@ namespace MPF.Modules
return null;
}
}
/// <summary>
/// Get the version from a PlayStation 4 disc, if possible
/// </summary>
/// <param name="driveLetter">Drive letter to use to check</param>
/// <returns>Game version if possible, null on error</returns>
#if NET48
protected static string GetPlayStation4Version(char? driveLetter)
#else
protected static string? GetPlayStation4Version(char? driveLetter)
#endif
{
// If there's no drive letter, we can't do this part
if (driveLetter == null)
@@ -1688,7 +1847,11 @@ namespace MPF.Modules
/// </summary>
/// <param name="driveLetter">Drive letter to use to check</param>
/// <returns>Internal disc serial if possible, null on error</returns>
#if NET48
protected static string GetPlayStation5Serial(char? driveLetter)
#else
protected static string? GetPlayStation5Serial(char? driveLetter)
#endif
{
// If there's no drive letter, we can't do this part
if (driveLetter == null)
@@ -1725,7 +1888,11 @@ namespace MPF.Modules
/// </summary>
/// <param name="driveLetter">Drive letter to use to check</param>
/// <returns>Game version if possible, null on error</returns>
#if NET48
protected static string GetPlayStation5Version(char? driveLetter)
#else
protected static string? GetPlayStation5Version(char? driveLetter)
#endif
{
// If there's no drive letter, we can't do this part
if (driveLetter == null)
@@ -1757,7 +1924,7 @@ namespace MPF.Modules
}
}
#endregion
#endregion
#region Category Extraction
@@ -1800,7 +1967,7 @@ namespace MPF.Modules
case 'E': return Region.Europe;
case 'K': return Region.SouthKorea;
case 'U': return Region.UnitedStatesOfAmerica;
case 'P':
case 'P':
// Region of S_P_ serials may be Japan, Asia, or SouthKorea
switch (serial[3])
{

View File

@@ -7,7 +7,7 @@ using MPF.Core.Converters;
using MPF.Core.Data;
using SabreTools.RedumpLib.Data;
namespace MPF.Modules.CleanRip
namespace MPF.Core.Modules.CleanRip
{
/// <summary>
/// Represents a generic set of CleanRip parameters
@@ -60,17 +60,23 @@ namespace MPF.Modules.CleanRip
}
/// <inheritdoc/>
#if NET48
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive drive, bool includeArtifacts)
#else
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive? drive, bool includeArtifacts)
#endif
{
// TODO: Determine if there's a CleanRip version anywhere
if (info.DumpingInfo == null) info.DumpingInfo = new DumpingInfoSection();
info.DumpingInfo.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
info.DumpingInfo.DumpingDate = GetFileModifiedDate(basePath + "-dumpinfo.txt")?.ToString("yyyy-MM-dd HH:mm:ss");
Datafile datafile = GenerateCleanripDatafile(basePath + ".iso", basePath + "-dumpinfo.txt");
var datafile = GenerateCleanripDatafile(basePath + ".iso", basePath + "-dumpinfo.txt");
// Get the individual hash data, as per internal
if (GetISOHashValues(datafile, out long size, out string crc32, out string md5, out string sha1))
if (GetISOHashValues(datafile, out long size, out var crc32, out var md5, out var sha1))
{
if (info.SizeAndChecksums == null) info.SizeAndChecksums = new SizeAndChecksumsSection();
info.SizeAndChecksums.Size = size;
info.SizeAndChecksums.CRC32 = crc32;
info.SizeAndChecksums.MD5 = md5;
@@ -79,7 +85,7 @@ namespace MPF.Modules.CleanRip
// Dual-layer discs have the same size and layerbreak
if (size == 8511160320)
info.SizeAndChecksums.Layerbreak = 2084960;
}
}
// Extract info based generically on MediaType
switch (this.Type)
@@ -88,12 +94,22 @@ namespace MPF.Modules.CleanRip
case MediaType.NintendoGameCubeGameDisc:
case MediaType.NintendoWiiOpticalDisc:
if (File.Exists(basePath + ".bca"))
info.Extras.BCA = GetBCA(basePath + ".bca");
if (GetGameCubeWiiInformation(basePath + "-dumpinfo.txt", out Region? gcRegion, out string gcVersion, out string gcName))
{
if (info.Extras == null) info.Extras = new ExtrasSection();
info.Extras.BCA = GetBCA(basePath + ".bca");
}
if (GetGameCubeWiiInformation(basePath + "-dumpinfo.txt", out Region? gcRegion, out var gcVersion, out var gcName))
{
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
info.CommonDiscInfo.Region = gcRegion ?? info.CommonDiscInfo.Region;
if (info.VersionAndEditions == null) info.VersionAndEditions = new VersionAndEditionsSection();
info.VersionAndEditions.Version = gcVersion ?? info.VersionAndEditions.Version;
#if NET48
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode?, string>();
#else
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode, string>();
#endif
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalName] = gcName ?? string.Empty;
}
@@ -103,10 +119,11 @@ namespace MPF.Modules.CleanRip
// Fill in any artifacts that exist, Base64-encoded, if we need to
if (includeArtifacts)
{
if (info.Artifacts == null) info.Artifacts = new Dictionary<string, string>();
if (File.Exists(basePath + ".bca"))
info.Artifacts["bca"] = GetBase64(GetFullFile(basePath + ".bca", binary: true));
info.Artifacts["bca"] = GetBase64(GetFullFile(basePath + ".bca", binary: true)) ?? string.Empty;
if (File.Exists(basePath + "-dumpinfo.txt"))
info.Artifacts["dumpinfo"] = GetBase64(GetFullFile(basePath + "-dumpinfo.txt"));
info.Artifacts["dumpinfo"] = GetBase64(GetFullFile(basePath + "-dumpinfo.txt")) ?? string.Empty;
}
}
@@ -140,7 +157,11 @@ namespace MPF.Modules.CleanRip
/// <param name="iso">Path to ISO file</param>
/// <param name="dumpinfo">Path to discinfo file</param>
/// <returns></returns>
#if NET48
private static Datafile GenerateCleanripDatafile(string iso, string dumpinfo)
#else
private static Datafile? GenerateCleanripDatafile(string iso, string dumpinfo)
#endif
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(dumpinfo))
@@ -156,14 +177,16 @@ namespace MPF.Modules.CleanRip
try
{
// Make sure this file is a dumpinfo
if (!sr.ReadLine().Contains("--File Generated by CleanRip"))
if (sr.ReadLine()?.Contains("--File Generated by CleanRip") != true)
return null;
// Read all lines and gather dat information
while (!sr.EndOfStream)
{
string line = sr.ReadLine().Trim();
if (line.StartsWith("CRC32"))
var line = sr.ReadLine()?.Trim();
if (string.IsNullOrWhiteSpace(line))
continue;
else if (line.StartsWith("CRC32"))
crc = line.Substring(7).ToLowerInvariant();
else if (line.StartsWith("MD5"))
md5 = line.Substring(5);
@@ -199,7 +222,11 @@ namespace MPF.Modules.CleanRip
/// <param name="bcaPath">Path to the BCA file associated with the dump</param>
/// <returns>BCA data as a hex string if possible, null on error</returns>
/// <remarks>https://stackoverflow.com/questions/9932096/add-separator-to-string-at-every-n-characters</remarks>
#if NET48
private static string GetBCA(string bcaPath)
#else
private static string? GetBCA(string bcaPath)
#endif
{
// If the file doesn't exist, we can't get the info
if (!File.Exists(bcaPath))
@@ -207,7 +234,10 @@ namespace MPF.Modules.CleanRip
try
{
string hex = GetFullFile(bcaPath, true);
var hex = GetFullFile(bcaPath, true);
if (hex == null)
return null;
return Regex.Replace(hex, ".{32}", "$0\n");
}
catch
@@ -223,7 +253,11 @@ namespace MPF.Modules.CleanRip
/// <param name="iso">Path to ISO file</param>
/// <param name="dumpinfo">Path to discinfo file</param>
/// <returns></returns>
#if NET48
private static string GetCleanripDatfile(string iso, string dumpinfo)
#else
private static string? GetCleanripDatfile(string iso, string dumpinfo)
#endif
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(dumpinfo))
@@ -239,14 +273,16 @@ namespace MPF.Modules.CleanRip
try
{
// Make sure this file is a dumpinfo
if (!sr.ReadLine().Contains("--File Generated by CleanRip"))
if (sr.ReadLine()?.Contains("--File Generated by CleanRip") != true)
return null;
// Read all lines and gather dat information
while (!sr.EndOfStream)
{
string line = sr.ReadLine().Trim();
if (line.StartsWith("CRC32"))
var line = sr.ReadLine()?.Trim();
if (string.IsNullOrWhiteSpace(line))
continue;
else if (line.StartsWith("CRC32"))
crc = line.Substring(7).ToLowerInvariant();
else if (line.StartsWith("MD5"))
md5 = line.Substring(5);
@@ -272,7 +308,11 @@ namespace MPF.Modules.CleanRip
/// <param name="version">Output internal version of the game</param>
/// <param name="name">Output internal name of the game</param>
/// <returns></returns>
#if NET48
private static bool GetGameCubeWiiInformation(string dumpinfo, out Region? region, out string version, out string name)
#else
private static bool GetGameCubeWiiInformation(string dumpinfo, out Region? region, out string? version, out string? name)
#endif
{
region = null; version = null; name = null;
@@ -285,14 +325,18 @@ namespace MPF.Modules.CleanRip
try
{
// Make sure this file is a dumpinfo
if (!sr.ReadLine().Contains("--File Generated by CleanRip"))
if (sr.ReadLine()?.Contains("--File Generated by CleanRip") != true)
return false;
// Read all lines and gather dat information
while (!sr.EndOfStream)
{
string line = sr.ReadLine().Trim();
if (line.StartsWith("Version"))
var line = sr.ReadLine()?.Trim();
if (string.IsNullOrWhiteSpace(line))
{
continue;
}
else if (line.StartsWith("Version"))
{
version = line.Substring("Version: ".Length);
}

View File

@@ -1,72 +1,144 @@
using System.Xml.Serialization;
namespace MPF.Modules
namespace MPF.Core.Modules
{
[XmlRoot("datafile")]
public class Datafile
{
[XmlElement("header")]
#if NET48
public Header Header;
#else
public Header? Header;
#endif
[XmlElement("game")]
#if NET48
public Game[] Games;
#else
public Game[]? Games;
#endif
}
public class Header
{
[XmlElement("name")]
#if NET48
public string Name;
#else
public string? Name;
#endif
[XmlElement("description")]
#if NET48
public string Description;
#else
public string? Description;
#endif
[XmlElement("version")]
#if NET48
public string Version;
#else
public string? Version;
#endif
[XmlElement("date")]
#if NET48
public string Date;
#else
public string? Date;
#endif
[XmlElement("author")]
#if NET48
public string Author;
#else
public string? Author;
#endif
[XmlElement("homepage")]
#if NET48
public string Homepage;
#else
public string? Homepage;
#endif
[XmlElement("url")]
#if NET48
public string Url;
#else
public string? Url;
#endif
}
public class Game
{
[XmlAttribute("name")]
#if NET48
public string Name;
#else
public string? Name;
#endif
[XmlElement("category")]
#if NET48
public string Category;
#else
public string? Category;
#endif
[XmlElement("description")]
#if NET48
public string Description;
#else
public string? Description;
#endif
[XmlElement("rom")]
#if NET48
public Rom[] Roms;
#else
public Rom[]? Roms;
#endif
}
public class Rom
{
[XmlAttribute("name")]
#if NET48
public string Name;
#else
public string? Name;
#endif
[XmlAttribute("size")]
#if NET48
public string Size;
#else
public string? Size;
#endif
[XmlAttribute("crc")]
#if NET48
public string Crc;
#else
public string? Crc;
#endif
[XmlAttribute("md5")]
#if NET48
public string Md5;
#else
public string? Md5;
#endif
[XmlAttribute("sha1")]
#if NET48
public string Sha1;
#else
public string? Sha1;
#endif
// TODO: Add extended hashes here
}

View File

@@ -1,4 +1,4 @@
namespace MPF.Modules.DiscImageCreator
namespace MPF.Core.Modules.DiscImageCreator
{
/// <summary>
/// Top-level commands for DiscImageCreator

View File

@@ -1,6 +1,6 @@
using SabreTools.RedumpLib.Data;
namespace MPF.Modules.DiscImageCreator
namespace MPF.Core.Modules.DiscImageCreator
{
public static class Converters
{
@@ -48,7 +48,11 @@ namespace MPF.Modules.DiscImageCreator
/// <param name="baseCommand">Command value to check</param>
/// <returns>MediaType if possible, null on error</returns>
/// <remarks>This takes the "safe" route by assuming the larger of any given format</remarks>
#if NET48
public static MediaType? ToMediaType(string baseCommand)
#else
public static MediaType? ToMediaType(string? baseCommand)
#endif
{
switch (baseCommand)
{
@@ -86,7 +90,11 @@ namespace MPF.Modules.DiscImageCreator
/// </summary>
/// <param name="type">MediaType value to check</param>
/// <returns>Valid extension (with leading '.'), null on error</returns>
#if NET48
public static string Extension(MediaType? type)
#else
public static string? Extension(MediaType? type)
#endif
{
switch (type)
{

View File

@@ -1,4 +1,4 @@
namespace MPF.Modules.Redumper
namespace MPF.Core.Modules.Redumper
{
/// <summary>
/// Top-level commands for Redumper

View File

@@ -1,6 +1,6 @@
using SabreTools.RedumpLib.Data;
namespace MPF.Modules.Redumper
namespace MPF.Core.Modules.Redumper
{
public static class Converters
{
@@ -11,7 +11,11 @@ namespace MPF.Modules.Redumper
/// </summary>
/// <param name="type">MediaType value to check</param>
/// <returns>Valid extension (with leading '.'), null on error</returns>
#if NET48
public static string Extension(MediaType? type)
#else
public static string? Extension(MediaType? type)
#endif
{
switch (type)
{

View File

@@ -3,12 +3,13 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using BinaryObjectScanner.Protection;
using MPF.Core.Converters;
using MPF.Core.Data;
using MPF.Core.Utilities;
using SabreTools.RedumpLib.Data;
namespace MPF.Modules.Redumper
namespace MPF.Core.Modules.Redumper
{
/// <summary>
/// Represents a generic set of Redumper parameters
@@ -26,10 +27,18 @@ namespace MPF.Modules.Redumper
#region Generic Dumping Information
/// <inheritdoc/>
#if NET48
public override string InputPath => DriveValue;
#else
public override string? InputPath => DriveValue;
#endif
/// <inheritdoc/>
#if NET48
public override string OutputPath => Path.Combine(ImagePathValue?.Trim('"') ?? string.Empty, ImageNameValue?.Trim('"') ?? string.Empty) + GetDefaultExtension(this.Type);
#else
public override string? OutputPath => Path.Combine(ImagePathValue?.Trim('"') ?? string.Empty, ImageNameValue?.Trim('"') ?? string.Empty) + GetDefaultExtension(this.Type);
#endif
/// <inheritdoc/>
public override int? Speed => SpeedValue;
@@ -48,14 +57,22 @@ namespace MPF.Modules.Redumper
/// <summary>
/// List of all modes being run
/// </summary>
#if NET48
public List<string> ModeValues { get; set; }
#else
public List<string>? ModeValues { get; set; }
#endif
#region General
/// <summary>
/// Drive to use, first available drive with disc, if not provided
/// </summary>
#if NET48
public string DriveValue { get; set; }
#else
public string? DriveValue { get; set; }
#endif
/// <summary>
/// Drive read speed, optimal drive speed will be used if not provided
@@ -70,12 +87,20 @@ namespace MPF.Modules.Redumper
/// <summary>
/// Dump files base directory
/// </summary>
#if NET48
public string ImagePathValue { get; set; }
#else
public string? ImagePathValue { get; set; }
#endif
/// <summary>
/// Dump files prefix, autogenerated in dump mode, if not provided
/// </summary>
#if NET48
public string ImageNameValue { get; set; }
#else
public string? ImageNameValue { get; set; }
#endif
#endregion
@@ -84,7 +109,11 @@ namespace MPF.Modules.Redumper
/// <summary>
/// Override drive type, possible values: GENERIC, PLEXTOR, LG_ASUS
/// </summary>
#if NET48
public string DriveTypeValue { get; set; }
#else
public string? DriveTypeValue { get; set; }
#endif
/// <summary>
/// Override drive read offset
@@ -104,12 +133,20 @@ namespace MPF.Modules.Redumper
/// <summary>
/// Override drive read method, possible values: BE, D8, BE_CDDA
/// </summary>
#if NET48
public string DriveReadMethodValue { get; set; }
#else
public string? DriveReadMethodValue { get; set; }
#endif
/// <summary>
/// Override drive sector order, possible values: DATA_C2_SUB, DATA_SUB_C2
/// </summary>
#if NET48
public string DriveSectorOrderValue { get; set; }
#else
public string? DriveSectorOrderValue { get; set; }
#endif
#endregion
@@ -151,7 +188,11 @@ namespace MPF.Modules.Redumper
/// <summary>
/// LBA ranges of sectors to skip
/// </summary>
#if NET48
public string SkipValue { get; set; }
#else
public string? SkipValue { get; set; }
#endif
/// <summary>
/// Number of sectors to read at once on initial dump, DVD only (Default 32)
@@ -242,14 +283,19 @@ namespace MPF.Modules.Redumper
}
/// <inheritdoc/>
#if NET48
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive drive, bool includeArtifacts)
#else
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive? drive, bool includeArtifacts)
#endif
{
// Get the dumping program and version
if (info.DumpingInfo == null) info.DumpingInfo = new DumpingInfoSection();
info.DumpingInfo.DumpingProgram = $"{EnumConverter.LongName(this.InternalProgram)} {GetVersion($"{basePath}.log") ?? "Unknown Version"}";
info.DumpingInfo.DumpingDate = GetFileModifiedDate($"{basePath}.log")?.ToString("yyyy-MM-dd HH:mm:ss");
// Fill in the hardware data
if (GetHardwareInfo($"{basePath}.log", out string manufacturer, out string model, out string firmware))
if (GetHardwareInfo($"{basePath}.log", out var manufacturer, out var model, out var firmware))
{
info.DumpingInfo.Manufacturer = manufacturer;
info.DumpingInfo.Model = model;
@@ -259,12 +305,15 @@ namespace MPF.Modules.Redumper
switch (this.Type)
{
case MediaType.CDROM:
info.Extras.PVD = GetPVD($"{basePath}.log") ?? "Disc has no PVD"; ;
if (info.Extras == null) info.Extras = new ExtrasSection();
info.Extras.PVD = GetPVD($"{basePath}.log") ?? "Disc has no PVD";
if (info.TracksAndWriteOffsets == null) info.TracksAndWriteOffsets = new TracksAndWriteOffsetsSection();
info.TracksAndWriteOffsets.ClrMameProData = GetDatfile($"{basePath}.log");
info.TracksAndWriteOffsets.Cuesheet = GetFullFile($"{basePath}.cue") ?? string.Empty;
// Attempt to get the write offset
string cdWriteOffset = GetWriteOffset($"{basePath}.log") ?? string.Empty;
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
info.CommonDiscInfo.RingWriteOffset = cdWriteOffset;
info.TracksAndWriteOffsets.OtherWriteOffsets = cdWriteOffset;
@@ -272,6 +321,12 @@ namespace MPF.Modules.Redumper
long errorCount = GetErrorCount($"{basePath}.log");
info.CommonDiscInfo.ErrorsCount = (errorCount == -1 ? "Error retrieving error count" : errorCount.ToString());
#if NET48
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode?, string>();
#else
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode, string>();
#endif
// Attempt to get multisession data
string cdMultiSessionInfo = GetMultisessionInformation($"{basePath}.log") ?? string.Empty;
if (!string.IsNullOrWhiteSpace(cdMultiSessionInfo))
@@ -294,11 +349,14 @@ namespace MPF.Modules.Redumper
break;
case MediaType.DVD:
info.Extras.PVD = GetPVD($"{basePath}.log") ?? "Disc has no PVD"; ;
if (info.Extras == null) info.Extras = new ExtrasSection();
info.Extras.PVD = GetPVD($"{basePath}.log") ?? "Disc has no PVD";
if (info.TracksAndWriteOffsets == null) info.TracksAndWriteOffsets = new TracksAndWriteOffsetsSection();
info.TracksAndWriteOffsets.ClrMameProData = GetDatfile($"{basePath}.log");
// Get the individual hash data, as per internal
if (GetISOHashValues(info.TracksAndWriteOffsets.ClrMameProData, out long size, out string crc32, out string md5, out string sha1))
if (info.SizeAndChecksums == null) info.SizeAndChecksums = new SizeAndChecksumsSection();
if (GetISOHashValues(info.TracksAndWriteOffsets.ClrMameProData, out long size, out var crc32, out var md5, out var sha1))
{
info.SizeAndChecksums.Size = size;
info.SizeAndChecksums.CRC32 = crc32;
@@ -323,18 +381,26 @@ namespace MPF.Modules.Redumper
case RedumpSystem.DVDAudio:
case RedumpSystem.DVDVideo:
if (info.CopyProtection == null) info.CopyProtection = new CopyProtectionSection();
info.CopyProtection.Protection = GetDVDProtection($"{basePath}.log") ?? string.Empty;
break;
case RedumpSystem.KonamiPython2:
if (GetPlayStationExecutableInfo(drive?.Letter, out string pythonTwoSerial, out Region? pythonTwoRegion, out string pythonTwoDate))
if (GetPlayStationExecutableInfo(drive?.Letter, out var pythonTwoSerial, out Region? pythonTwoRegion, out var pythonTwoDate))
{
// Ensure internal serial is pulled from local data
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
#if NET48
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode?, string>();
#else
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode, string>();
#endif
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = pythonTwoSerial ?? string.Empty;
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? pythonTwoRegion;
info.CommonDiscInfo.EXEDateBuildDate = pythonTwoDate;
}
if (info.VersionAndEditions == null) info.VersionAndEditions = new VersionAndEditionsSection();
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? string.Empty;
break;
@@ -351,7 +417,14 @@ namespace MPF.Modules.Redumper
break;
case RedumpSystem.SegaMegaCDSegaCD:
info.Extras.Header = GetSegaCDHeader($"{basePath}.log", out string scdBuildDate, out string scdSerial, out string _) ?? string.Empty;
if (info.Extras == null) info.Extras = new ExtrasSection();
info.Extras.Header = GetSegaCDHeader($"{basePath}.log", out var scdBuildDate, out var scdSerial, out _) ?? string.Empty;
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
#if NET48
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode?, string>();
#else
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode, string>();
#endif
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = scdSerial ?? string.Empty;
info.CommonDiscInfo.EXEDateBuildDate = scdBuildDate ?? string.Empty;
// TODO: Support region setting from parsed value
@@ -374,16 +447,24 @@ namespace MPF.Modules.Redumper
break;
case RedumpSystem.SegaSaturn:
if (info.Extras == null) info.Extras = new ExtrasSection();
info.Extras.Header = GetSaturnHeader($"{basePath}.log") ?? string.Empty;
// Take only the first 16 lines for Saturn
if (!string.IsNullOrEmpty(info.Extras.Header))
info.Extras.Header = string.Join("\n", info.Extras.Header.Split('\n').Take(16));
if (GetSaturnBuildInfo(info.Extras.Header, out string saturnSerial, out string saturnVersion, out string buildDate))
if (GetSaturnBuildInfo(info.Extras.Header, out var saturnSerial, out var saturnVersion, out var buildDate))
{
// Ensure internal serial is pulled from local data
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
#if NET48
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode?, string>();
#else
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode, string>();
#endif
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = saturnSerial ?? string.Empty;
if (info.VersionAndEditions == null) info.VersionAndEditions = new VersionAndEditionsSection();
info.VersionAndEditions.Version = saturnVersion ?? string.Empty;
info.CommonDiscInfo.EXEDateBuildDate = buildDate ?? string.Empty;
}
@@ -391,44 +472,80 @@ namespace MPF.Modules.Redumper
break;
case RedumpSystem.SonyPlayStation:
if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationSerial, out Region? playstationRegion, out string playstationDate))
if (GetPlayStationExecutableInfo(drive?.Letter, out var playstationSerial, out Region? playstationRegion, out var playstationDate))
{
// Ensure internal serial is pulled from local data
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
#if NET48
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode?, string>();
#else
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode, string>();
#endif
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = playstationSerial ?? string.Empty;
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationRegion;
info.CommonDiscInfo.EXEDateBuildDate = playstationDate;
}
if (info.CopyProtection == null) info.CopyProtection = new CopyProtectionSection();
info.CopyProtection.AntiModchip = GetPlayStationAntiModchipDetected($"{basePath}.log").ToYesNo();
if (info.EDC == null) info.EDC = new EDCSection();
info.EDC.EDC = GetPlayStationEDCStatus($"{basePath}.log").ToYesNo();
info.CopyProtection.LibCrypt = GetPlayStationLibCryptStatus($"{basePath}.log").ToYesNo();
info.CopyProtection.LibCryptData = GetPlayStationLibCryptData($"{basePath}.log");
break;
case RedumpSystem.SonyPlayStation2:
if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationTwoSerial, out Region? playstationTwoRegion, out string playstationTwoDate))
if (GetPlayStationExecutableInfo(drive?.Letter, out var playstationTwoSerial, out Region? playstationTwoRegion, out var playstationTwoDate))
{
// Ensure internal serial is pulled from local data
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
#if NET48
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode?, string>();
#else
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode, string>();
#endif
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = playstationTwoSerial ?? string.Empty;
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationTwoRegion;
info.CommonDiscInfo.EXEDateBuildDate = playstationTwoDate;
}
if (info.VersionAndEditions == null) info.VersionAndEditions = new VersionAndEditionsSection();
info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? string.Empty;
break;
case RedumpSystem.SonyPlayStation3:
if (info.VersionAndEditions == null) info.VersionAndEditions = new VersionAndEditionsSection();
info.VersionAndEditions.Version = GetPlayStation3Version(drive?.Letter) ?? string.Empty;
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
#if NET48
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode?, string>();
#else
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode, string>();
#endif
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = GetPlayStation3Serial(drive?.Letter) ?? string.Empty;
break;
case RedumpSystem.SonyPlayStation4:
if (info.VersionAndEditions == null) info.VersionAndEditions = new VersionAndEditionsSection();
info.VersionAndEditions.Version = GetPlayStation4Version(drive?.Letter) ?? string.Empty;
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
#if NET48
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode?, string>();
#else
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode, string>();
#endif
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = GetPlayStation4Serial(drive?.Letter) ?? string.Empty;
break;
case RedumpSystem.SonyPlayStation5:
if (info.VersionAndEditions == null) info.VersionAndEditions = new VersionAndEditionsSection();
info.VersionAndEditions.Version = GetPlayStation5Version(drive?.Letter) ?? string.Empty;
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
#if NET48
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode?, string>();
#else
if (info.CommonDiscInfo.CommentsSpecialFields == null) info.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode, string>();
#endif
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = GetPlayStation5Serial(drive?.Letter) ?? string.Empty;
break;
}
@@ -436,36 +553,37 @@ namespace MPF.Modules.Redumper
// Fill in any artifacts that exist, Base64-encoded, if we need to
if (includeArtifacts)
{
if (info.Artifacts == null) info.Artifacts = new Dictionary<string, string>();
if (File.Exists($"{basePath}.cdtext"))
info.Artifacts["cdtext"] = GetBase64(GetFullFile($"{basePath}.cdtext"));
info.Artifacts["cdtext"] = GetBase64(GetFullFile($"{basePath}.cdtext")) ?? string.Empty;
if (File.Exists($"{basePath}.cue"))
info.Artifacts["cue"] = GetBase64(GetFullFile($"{basePath}.cue"));
info.Artifacts["cue"] = GetBase64(GetFullFile($"{basePath}.cue")) ?? string.Empty;
if (File.Exists($"{basePath}.fulltoc"))
info.Artifacts["fulltoc"] = GetBase64(GetFullFile($"{basePath}.fulltoc"));
info.Artifacts["fulltoc"] = GetBase64(GetFullFile($"{basePath}.fulltoc")) ?? string.Empty;
if (File.Exists($"{basePath}.log"))
info.Artifacts["log"] = GetBase64(GetFullFile($"{basePath}.log"));
info.Artifacts["log"] = GetBase64(GetFullFile($"{basePath}.log")) ?? string.Empty;
if (File.Exists($"{basePath}.manufacturer"))
info.Artifacts["manufacturer"] = GetBase64(GetFullFile($"{basePath}.manufacturer"));
info.Artifacts["manufacturer"] = GetBase64(GetFullFile($"{basePath}.manufacturer")) ?? string.Empty;
if (File.Exists($"{basePath}.1.manufacturer"))
info.Artifacts["manufacturer1"] = GetBase64(GetFullFile($"{basePath}.1.manufacturer"));
info.Artifacts["manufacturer1"] = GetBase64(GetFullFile($"{basePath}.1.manufacturer")) ?? string.Empty;
if (File.Exists($"{basePath}.2.manufacturer"))
info.Artifacts["manufacturer2"] = GetBase64(GetFullFile($"{basePath}.2.manufacturer"));
info.Artifacts["manufacturer2"] = GetBase64(GetFullFile($"{basePath}.2.manufacturer")) ?? string.Empty;
if (File.Exists($"{basePath}.physical"))
info.Artifacts["physical"] = GetBase64(GetFullFile($"{basePath}.physical"));
info.Artifacts["physical"] = GetBase64(GetFullFile($"{basePath}.physical")) ?? string.Empty;
if (File.Exists($"{basePath}.1.physical"))
info.Artifacts["physical1"] = GetBase64(GetFullFile($"{basePath}.1.physical"));
info.Artifacts["physical1"] = GetBase64(GetFullFile($"{basePath}.1.physical")) ?? string.Empty;
if (File.Exists($"{basePath}.2.physical"))
info.Artifacts["physical2"] = GetBase64(GetFullFile($"{basePath}.2.physical"));
info.Artifacts["physical2"] = GetBase64(GetFullFile($"{basePath}.2.physical")) ?? string.Empty;
// if (File.Exists($"{basePath}.scram"))
// info.Artifacts["scram"] = GetBase64(GetFullFile($"{basePath}.scram"));
// info.Artifacts["scram"] = GetBase64(GetFullFile($"{basePath}.scram")) ?? string.Empty;
// if (File.Exists($"{basePath}.scrap"))
// info.Artifacts["scrap"] = GetBase64(GetFullFile($"{basePath}.scrap"));
// info.Artifacts["scrap"] = GetBase64(GetFullFile($"{basePath}.scrap")) ?? string.Empty;
if (File.Exists($"{basePath}.state"))
info.Artifacts["state"] = GetBase64(GetFullFile($"{basePath}.state"));
info.Artifacts["state"] = GetBase64(GetFullFile($"{basePath}.state")) ?? string.Empty;
if (File.Exists($"{basePath}.subcode"))
info.Artifacts["subcode"] = GetBase64(GetFullFile($"{basePath}.subcode"));
info.Artifacts["subcode"] = GetBase64(GetFullFile($"{basePath}.subcode")) ?? string.Empty;
if (File.Exists($"{basePath}.toc"))
info.Artifacts["toc"] = GetBase64(GetFullFile($"{basePath}.toc"));
info.Artifacts["toc"] = GetBase64(GetFullFile($"{basePath}.toc")) ?? string.Empty;
}
}
@@ -763,7 +881,11 @@ namespace MPF.Modules.Redumper
}
/// <inheritdoc/>
#if NET48
public override string GetDefaultExtension(MediaType? mediaType) => Converters.Extension(mediaType);
#else
public override string? GetDefaultExtension(MediaType? mediaType) => Converters.Extension(mediaType);
#endif
/// <inheritdoc/>
public override List<string> GetLogFilePaths(string basePath)
@@ -818,11 +940,11 @@ namespace MPF.Modules.Redumper
public override bool IsDumpingCommand()
{
return this.BaseCommand == CommandStrings.NONE
|| this.BaseCommand.Contains(CommandStrings.CD)
|| this.BaseCommand.Contains(CommandStrings.DVD)
|| this.BaseCommand.Contains(CommandStrings.BluRay)
|| this.BaseCommand.Contains(CommandStrings.SACD)
|| this.BaseCommand.Contains(CommandStrings.Dump);
|| this.BaseCommand?.Contains(CommandStrings.CD) == true
|| this.BaseCommand?.Contains(CommandStrings.DVD) == true
|| this.BaseCommand?.Contains(CommandStrings.BluRay) == true
|| this.BaseCommand?.Contains(CommandStrings.SACD) == true
|| this.BaseCommand?.Contains(CommandStrings.Dump) == true;
}
/// <inheritdoc/>
@@ -908,7 +1030,7 @@ namespace MPF.Modules.Redumper
// Set the output paths
if (!string.IsNullOrWhiteSpace(filename))
{
string imagePath = Path.GetDirectoryName(filename);
var imagePath = Path.GetDirectoryName(filename);
if (!string.IsNullOrWhiteSpace(imagePath))
{
this[FlagStrings.ImagePath] = true;
@@ -996,7 +1118,11 @@ namespace MPF.Modules.Redumper
// Flag read-out values
byte? byteValue = null;
int? intValue = null;
#if NET48
string stringValue = null;
#else
string? stringValue = null;
#endif
#region General
@@ -1176,7 +1302,11 @@ namespace MPF.Modules.Redumper
/// </summary>
/// <param name="log">Log file location</param>
/// <returns>Newline-delimited cuesheet if possible, null on error</returns>
#if NET48
private static string GetCuesheet(string log)
#else
private static string? GetCuesheet(string log)
#endif
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(log))
@@ -1187,16 +1317,20 @@ namespace MPF.Modules.Redumper
try
{
// Fast forward to the dat line
while (!sr.EndOfStream && !sr.ReadLine().TrimStart().StartsWith("CUE [")) ;
while (!sr.EndOfStream && sr.ReadLine()?.TrimStart()?.StartsWith("CUE [") == false) ;
if (sr.EndOfStream)
return null;
// Now that we're at the relevant entries, read each line in and concatenate
string cueString = "", line = sr.ReadLine().Trim();
#if NET48
string cueString = string.Empty, line = sr.ReadLine()?.Trim();
#else
string? cueString = string.Empty, line = sr.ReadLine()?.Trim();
#endif
while (!string.IsNullOrWhiteSpace(line))
{
cueString += line + "\n";
line = sr.ReadLine().Trim();
line = sr.ReadLine()?.Trim();
}
return cueString.TrimEnd('\n');
@@ -1214,7 +1348,11 @@ namespace MPF.Modules.Redumper
/// </summary>
/// <param name="log">Log file location</param>
/// <returns>Newline-delimited datfile if possible, null on error</returns>
#if NET48
private static string GetDatfile(string log)
#else
private static string? GetDatfile(string log)
#endif
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(log))
@@ -1225,13 +1363,14 @@ namespace MPF.Modules.Redumper
try
{
// Fast forward to the dat line
while (!sr.EndOfStream && !sr.ReadLine().TrimStart().StartsWith("dat:")) ;
while (!sr.EndOfStream && sr.ReadLine()?.TrimStart()?.StartsWith("dat:") == false) ;
if (sr.EndOfStream)
return null;
// Now that we're at the relevant entries, read each line in and concatenate
string datString = "", line = sr.ReadLine().Trim();
while (line.StartsWith("<rom"))
var datString = string.Empty;
var line = sr.ReadLine()?.Trim();
while (line?.StartsWith("<rom") == true)
{
datString += line + "\n";
if (sr.EndOfStream)
@@ -1255,23 +1394,31 @@ namespace MPF.Modules.Redumper
/// </summary>
/// <param name="log">Log file location</param>
/// <returns>Formatted string representing the DVD protection, null on error</returns>
#if NET48
private static string GetDVDProtection(string log)
#else
private static string? GetDVDProtection(string log)
#endif
{
// If one of the files doesn't exist, we can't get info from them
if (!File.Exists(log))
return null;
// Setup all of the individual pieces
#if NET48
string region = null, rceProtection = null, copyrightProtectionSystemType = null, vobKeys = null, decryptedDiscKey = null;
#else
string? region = null, rceProtection = null, copyrightProtectionSystemType = null, vobKeys = null, decryptedDiscKey = null;
#endif
using (StreamReader sr = File.OpenText(log))
{
try
{
// Fast forward to the copyright information
while (!sr.ReadLine().Trim().StartsWith("copyright:")) ;
while (sr.ReadLine()?.Trim().StartsWith("copyright:") == false) ;
// Now read until we hit the manufacturing information
string line = sr.ReadLine()?.Trim();
var line = sr.ReadLine()?.Trim();
while (line != null && !sr.EndOfStream)
{
if (line.StartsWith("protection system type"))
@@ -1369,7 +1516,7 @@ namespace MPF.Modules.Redumper
try
{
// Fast forward to the errors lines
while (!sr.EndOfStream && !sr.ReadLine().Trim().StartsWith("CD-ROM [")) ;
while (!sr.EndOfStream && sr.ReadLine()?.Trim()?.StartsWith("CD-ROM [") == false) ;
if (sr.EndOfStream)
return 0;
@@ -1377,9 +1524,9 @@ namespace MPF.Modules.Redumper
while (!sr.EndOfStream)
{
// Skip forward to the "REDUMP.ORG" line
string line = string.Empty;
while (!sr.EndOfStream && !(line = sr.ReadLine().Trim()).StartsWith("REDUMP.ORG errors")) ;
if (line == string.Empty)
var line = string.Empty;
while (!sr.EndOfStream && (line = sr.ReadLine()?.Trim())?.StartsWith("REDUMP.ORG errors") == false) ;
if (string.IsNullOrEmpty(line))
break;
// REDUMP.ORG errors: <error count>
@@ -1405,7 +1552,11 @@ namespace MPF.Modules.Redumper
/// </summary>
/// <param name="log">Log file location</param>
/// <returns>Layerbreak if possible, null on error</returns>
#if NET48
private static string GetLayerbreak(string log)
#else
private static string? GetLayerbreak(string log)
#endif
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(log))
@@ -1416,15 +1567,19 @@ namespace MPF.Modules.Redumper
try
{
// Fast forward to the disc structure lines
while (!sr.EndOfStream && !sr.ReadLine().Trim().StartsWith("layer 0")) ;
while (!sr.EndOfStream && sr.ReadLine()?.Trim()?.StartsWith("layer 0") == false) ;
if (sr.EndOfStream)
return null;
// Now that we're at the relevant lines, find the layerbreak
#if NET48
string layerbreak = null;
#else
string? layerbreak = null;
#endif
while (!sr.EndOfStream)
{
string line = sr.ReadLine()?.Trim();
var line = sr.ReadLine()?.Trim();
// If we have a null line, just break
if (line == null)
@@ -1476,7 +1631,11 @@ namespace MPF.Modules.Redumper
/// </summary>
/// <param name="log">Log file location</param>
/// <returns>Formatted multisession information, null on error</returns>
#if NET48
private static string GetMultisessionInformation(string log)
#else
private static string? GetMultisessionInformation(string log)
#endif
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(log))
@@ -1487,15 +1646,19 @@ namespace MPF.Modules.Redumper
try
{
// Fast forward to the multisession lines
while (!sr.EndOfStream && !sr.ReadLine().Trim().StartsWith("multisession:")) ;
while (!sr.EndOfStream && sr.ReadLine()?.Trim()?.StartsWith("multisession:") == false) ;
if (sr.EndOfStream)
return null;
// Now that we're at the relevant lines, find the session info
#if NET48
string firstSession = null, secondSession = null;
#else
string? firstSession = null, secondSession = null;
#endif
while (!sr.EndOfStream)
{
string line = sr.ReadLine()?.Trim();
var line = sr.ReadLine()?.Trim();
// If we have a null line, just break
if (line == null)
@@ -1549,7 +1712,7 @@ namespace MPF.Modules.Redumper
try
{
// Check for the anti-modchip strings
string line = sr.ReadLine().Trim();
var line = sr.ReadLine()?.Trim();
while (!sr.EndOfStream)
{
if (line == null)
@@ -1560,7 +1723,7 @@ namespace MPF.Modules.Redumper
else if (line.StartsWith("anti-modchip: yes"))
return true;
line = sr.ReadLine().Trim();
line = sr.ReadLine()?.Trim();
}
return false;
@@ -1589,7 +1752,7 @@ namespace MPF.Modules.Redumper
try
{
// Check for the EDC strings
string line = sr.ReadLine().Trim();
var line = sr.ReadLine()?.Trim();
while (!sr.EndOfStream)
{
if (line == null)
@@ -1600,7 +1763,7 @@ namespace MPF.Modules.Redumper
else if (line.Contains("EDC: yes"))
return true;
line = sr.ReadLine().Trim();
line = sr.ReadLine()?.Trim();
}
return false;
@@ -1618,7 +1781,11 @@ namespace MPF.Modules.Redumper
/// </summary>
/// <param name="log">Log file location</param>
/// <returns>PS1 LibCrypt data, if possible</returns>
#if NET48
private static string GetPlayStationLibCryptData(string log)
#else
private static string? GetPlayStationLibCryptData(string log)
#endif
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(log))
@@ -1629,16 +1796,20 @@ namespace MPF.Modules.Redumper
try
{
// Fast forward to the LibCrypt line
while (!sr.EndOfStream && !sr.ReadLine().TrimStart().StartsWith("libcrypt:")) ;
while (!sr.EndOfStream && sr.ReadLine()?.TrimStart()?.StartsWith("libcrypt:") == false) ;
if (sr.EndOfStream)
return null;
// Now that we're at the relevant entries, read each line in and concatenate
string libCryptString = "", line = sr.ReadLine().Trim();
while (line.StartsWith("MSF:"))
#if NET48
string libCryptString = "", line = sr.ReadLine()?.Trim();
#else
string? libCryptString = "", line = sr.ReadLine()?.Trim();
#endif
while (line?.StartsWith("MSF:") == true)
{
libCryptString += line + "\n";
line = sr.ReadLine().Trim();
line = sr.ReadLine()?.Trim();
}
return libCryptString.TrimEnd('\n');
@@ -1667,7 +1838,7 @@ namespace MPF.Modules.Redumper
try
{
// Check for the libcrypt strings
string line = sr.ReadLine().Trim();
var line = sr.ReadLine()?.Trim();
while (!sr.EndOfStream)
{
if (line == null)
@@ -1678,7 +1849,7 @@ namespace MPF.Modules.Redumper
else if (line.StartsWith("libcrypt: yes"))
return true;
line = sr.ReadLine().Trim();
line = sr.ReadLine()?.Trim();
}
return false;
@@ -1696,7 +1867,11 @@ namespace MPF.Modules.Redumper
/// </summary>
/// <param name="log">Log file location</param>
/// <returns>Newline-delimited PVD if possible, null on error</returns>
#if NET48
private static string GetPVD(string log)
#else
private static string? GetPVD(string log)
#endif
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(log))
@@ -1707,16 +1882,20 @@ namespace MPF.Modules.Redumper
try
{
// Fast forward to the PVD line
while (!sr.EndOfStream && !sr.ReadLine().TrimStart().StartsWith("PVD:")) ;
while (!sr.EndOfStream && sr.ReadLine()?.TrimStart()?.StartsWith("PVD:") == false) ;
if (sr.EndOfStream)
return null;
// Now that we're at the relevant entries, read each line in and concatenate
string pvdString = "", line = sr.ReadLine().Trim();
while (line.StartsWith("03"))
#if NET48
string pvdString = "", line = sr.ReadLine()?.Trim();
#else
string? pvdString = "", line = sr.ReadLine()?.Trim();
#endif
while (line?.StartsWith("03") == true)
{
pvdString += line + "\n";
line = sr.ReadLine().Trim();
line = sr.ReadLine()?.Trim();
}
return pvdString.TrimEnd('\n');
@@ -1734,7 +1913,11 @@ namespace MPF.Modules.Redumper
/// </summary>
/// <param name="log">Log file location</param>
/// <returns>Non-zero dta start if possible, null on error</returns>
#if NET48
private static string GetRingNonZeroDataStart(string log)
#else
private static string? GetRingNonZeroDataStart(string log)
#endif
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(log))
@@ -1745,11 +1928,15 @@ namespace MPF.Modules.Redumper
try
{
// If we find the sample range, return the start value only
#if NET48
string line;
#else
string? line;
#endif
while (!sr.EndOfStream)
{
line = sr.ReadLine().TrimStart();
if (line.StartsWith("non-zero data sample range"))
line = sr.ReadLine()?.TrimStart();
if (line?.StartsWith("non-zero data sample range") == true)
#if NET48
return line.Substring("non-zero data sample range: [".Length).Trim().Split(' ')[0];
#else
@@ -1773,8 +1960,12 @@ namespace MPF.Modules.Redumper
/// </summary>
/// <<param name="segaHeader">String representing a formatter variant of the Saturn header</param>
/// <returns>True on successful extraction of info, false otherwise</returns>
/// TODO: Remove when Redumpe gets native reading support
/// TODO: Remove when Redumper gets native reading support
#if NET48
private static bool GetSaturnBuildInfo(string segaHeader, out string serial, out string version, out string date)
#else
private static bool GetSaturnBuildInfo(string? segaHeader, out string? serial, out string? version, out string? date)
#endif
{
serial = null; version = null; date = null;
@@ -1814,7 +2005,11 @@ namespace MPF.Modules.Redumper
/// </summary>
/// <param name="log">Log file location</param>
/// <returns>Header as a byte array if possible, null on error</returns>
#if NET48
private static string GetSaturnHeader(string log)
#else
private static string? GetSaturnHeader(string log)
#endif
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(log))
@@ -1825,21 +2020,25 @@ namespace MPF.Modules.Redumper
try
{
// Fast forward to the SS line
while (!sr.EndOfStream && !sr.ReadLine().TrimStart().StartsWith("SS [")) ;
while (!sr.EndOfStream && sr.ReadLine()?.TrimStart()?.StartsWith("SS [") == false) ;
if (sr.EndOfStream)
return null;
#if NET48
string line, headerString = "";
#else
string? line, headerString = "";
#endif
while (!sr.EndOfStream)
{
line = sr.ReadLine().TrimStart();
if (line.StartsWith("header:"))
line = sr.ReadLine()?.TrimStart();
if (line?.StartsWith("header:") == true)
{
line = sr.ReadLine().TrimStart();
while (line.StartsWith("00"))
line = sr.ReadLine()?.TrimStart();
while (line?.StartsWith("00") == true)
{
headerString += line + "\n";
line = sr.ReadLine().Trim();
line = sr.ReadLine()?.Trim();
}
}
else
@@ -1863,7 +2062,11 @@ namespace MPF.Modules.Redumper
/// </summary>
/// <param name="log">Log file location</param>
/// <returns>Header as a byte array if possible, null on error</returns>
#if NET48
private static string GetSegaCDHeader(string log, out string buildDate, out string serial, out string region)
#else
private static string? GetSegaCDHeader(string log, out string? buildDate, out string? serial, out string? region)
#endif
{
// Set the default values
buildDate = null; serial = null; region = null;
@@ -1877,14 +2080,21 @@ namespace MPF.Modules.Redumper
try
{
// Fast forward to the MCD line
while (!sr.EndOfStream && !sr.ReadLine().TrimStart().StartsWith("MCD [")) ;
while (!sr.EndOfStream && sr.ReadLine()?.TrimStart()?.StartsWith("MCD [") == false) ;
if (sr.EndOfStream)
return null;
string line, headerString = "";
#if NET48
string line, headerString = string.Empty;
#else
string? line, headerString = string.Empty;
#endif
while (!sr.EndOfStream)
{
line = sr.ReadLine().TrimStart();
line = sr.ReadLine()?.TrimStart();
if (line == null)
break;
if (line.StartsWith("build date:"))
{
#if NET48
@@ -1919,11 +2129,11 @@ namespace MPF.Modules.Redumper
}
else if (line.StartsWith("header:"))
{
line = sr.ReadLine().TrimStart();
while (line.StartsWith("01"))
line = sr.ReadLine()?.TrimStart();
while (line?.StartsWith("01") == true)
{
headerString += line + "\n";
line = sr.ReadLine().Trim();
line = sr.ReadLine()?.Trim();
}
}
else
@@ -1947,7 +2157,11 @@ namespace MPF.Modules.Redumper
/// </summary>
/// <param name="log">Log file location</param>
/// <returns>Universal hash if possible, null on error</returns>
#if NET48
private static string GetUniversalHash(string log)
#else
private static string? GetUniversalHash(string log)
#endif
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(log))
@@ -1958,11 +2172,15 @@ namespace MPF.Modules.Redumper
try
{
// If we find the universal hash line, return the hash only
#if NET48
string line;
#else
string? line;
#endif
while (!sr.EndOfStream)
{
line = sr.ReadLine().TrimStart();
if (line.StartsWith("Universal Hash"))
line = sr.ReadLine()?.TrimStart();
if (line?.StartsWith("Universal Hash") == true)
#if NET48
return line.Substring("Universal Hash (SHA-1): ".Length).Trim();
#else
@@ -1986,7 +2204,11 @@ namespace MPF.Modules.Redumper
/// </summary>
/// <param name="log">Log file location</param>
/// <returns>Sample write offset if possible, null on error</returns>
#if NET48
private static string GetWriteOffset(string log)
#else
private static string? GetWriteOffset(string log)
#endif
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(log))
@@ -1997,11 +2219,15 @@ namespace MPF.Modules.Redumper
try
{
// If we find the disc write offset line, return the offset
#if NET48
string line;
#else
string? line;
#endif
while (!sr.EndOfStream)
{
line = sr.ReadLine().TrimStart();
if (line.StartsWith("disc write offset"))
line = sr.ReadLine()?.TrimStart();
if (line?.StartsWith("disc write offset") == true)
#if NET48
return line.Substring("disc write offset: ".Length).Trim();
#else
@@ -2025,7 +2251,11 @@ namespace MPF.Modules.Redumper
/// </summary>
/// <param name="log">Log file location</param>
/// <returns>Version if possible, null on error</returns>
#if NET48
private static string GetVersion(string log)
#else
private static string? GetVersion(string log)
#endif
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(log))
@@ -2049,7 +2279,7 @@ namespace MPF.Modules.Redumper
//var regex = new Regex(@"^redumper (v\d{4}\.\d{2}\.\d{2}(| build_\d+)) \[.+\]");
// Extract the version string
var match = regex.Match(sr.ReadLine().Trim());
var match = regex.Match(sr.ReadLine()?.Trim() ?? string.Empty);
var version = match.Groups[1].Value;
return string.IsNullOrWhiteSpace(version) ? null : version;
}
@@ -2066,7 +2296,11 @@ namespace MPF.Modules.Redumper
/// </summary>
/// <param name="log">Log file location</param>
/// <returns>True if hardware info was set, false otherwise</returns>
#if NET48
private static bool GetHardwareInfo(string log, out string manufacturer, out string model, out string firmware)
#else
private static bool GetHardwareInfo(string log, out string? manufacturer, out string? model, out string? firmware)
#endif
{
// Set the default values
manufacturer = null; model = null; firmware = null;
@@ -2085,7 +2319,12 @@ namespace MPF.Modules.Redumper
// If we find the hardware info line, return each value
// drive: <vendor_id> - <product_id> (revision level: <product_revision_level>, vendor specific: <vendor_specific>)
var regex = new Regex(@"drive: (.+) - (.+) \(revision level: (.+), vendor specific: (.+)\)");
#if NET48
string line;
#else
string? line;
#endif
while ((line = sr.ReadLine()) != null)
{
var match = regex.Match(line.Trim());

View File

@@ -6,7 +6,7 @@ using MPF.Core.Converters;
using MPF.Core.Data;
using SabreTools.RedumpLib.Data;
namespace MPF.Modules.UmdImageCreator
namespace MPF.Core.Modules.UmdImageCreator
{
/// <summary>
/// Represents a generic set of UmdImageCreator parameters
@@ -61,9 +61,14 @@ namespace MPF.Modules.UmdImageCreator
}
/// <inheritdoc/>
#if NET48
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive drive, bool includeArtifacts)
#else
public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive? drive, bool includeArtifacts)
#endif
{
// TODO: Determine if there's a UMDImageCreator version anywhere
if (info.DumpingInfo == null) info.DumpingInfo = new DumpingInfoSection();
info.DumpingInfo.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
info.DumpingInfo.DumpingDate = GetFileModifiedDate(basePath + "_disc.txt")?.ToString("yyyy-MM-dd HH:mm:ss");
@@ -71,21 +76,26 @@ namespace MPF.Modules.UmdImageCreator
switch (this.Type)
{
case MediaType.UMD:
if (info.Extras == null) info.Extras = new ExtrasSection();
info.Extras.PVD = GetPVD(basePath + "_mainInfo.txt") ?? string.Empty;
if (GetFileHashes(basePath + ".iso", out long filesize, out string crc32, out string md5, out string sha1))
if (GetFileHashes(basePath + ".iso", out long filesize, out var crc32, out var md5, out var sha1))
{
if (info.SizeAndChecksums == null) info.SizeAndChecksums = new SizeAndChecksumsSection();
info.SizeAndChecksums.Size = filesize;
info.SizeAndChecksums.CRC32 = crc32;
info.SizeAndChecksums.MD5 = md5;
info.SizeAndChecksums.SHA1 = sha1;
}
if (GetUMDAuxInfo(basePath + "_disc.txt", out string title, out DiscCategory? umdcat, out string umdversion, out string umdlayer, out long umdsize))
if (GetUMDAuxInfo(basePath + "_disc.txt", out var title, out DiscCategory? umdcat, out var umdversion, out var umdlayer, out long umdsize))
{
if (info.CommonDiscInfo == null) info.CommonDiscInfo = new CommonDiscInfoSection();
info.CommonDiscInfo.Title = title ?? string.Empty;
info.CommonDiscInfo.Category = umdcat ?? DiscCategory.Games;
if (info.VersionAndEditions == null) info.VersionAndEditions = new VersionAndEditionsSection();
info.VersionAndEditions.Version = umdversion ?? string.Empty;
if (info.SizeAndChecksums == null) info.SizeAndChecksums = new SizeAndChecksumsSection();
info.SizeAndChecksums.Size = umdsize;
if (!string.IsNullOrWhiteSpace(umdlayer))
@@ -98,16 +108,17 @@ namespace MPF.Modules.UmdImageCreator
// Fill in any artifacts that exist, Base64-encoded, if we need to
if (includeArtifacts)
{
if (info.Artifacts == null) info.Artifacts = new Dictionary<string, string>();
if (File.Exists(basePath + "_disc.txt"))
info.Artifacts["disc"] = GetBase64(GetFullFile(basePath + "_disc.txt"));
info.Artifacts["disc"] = GetBase64(GetFullFile(basePath + "_disc.txt")) ?? string.Empty;
if (File.Exists(basePath + "_drive.txt"))
info.Artifacts["drive"] = GetBase64(GetFullFile(basePath + "_drive.txt"));
info.Artifacts["drive"] = GetBase64(GetFullFile(basePath + "_drive.txt")) ?? string.Empty;
if (File.Exists(basePath + "_mainError.txt"))
info.Artifacts["mainError"] = GetBase64(GetFullFile(basePath + "_mainError.txt"));
info.Artifacts["mainError"] = GetBase64(GetFullFile(basePath + "_mainError.txt")) ?? string.Empty;
if (File.Exists(basePath + "_mainInfo.txt"))
info.Artifacts["mainInfo"] = GetBase64(GetFullFile(basePath + "_mainInfo.txt"));
info.Artifacts["mainInfo"] = GetBase64(GetFullFile(basePath + "_mainInfo.txt")) ?? string.Empty;
if (File.Exists(basePath + "_volDesc.txt"))
info.Artifacts["volDesc"] = GetBase64(GetFullFile(basePath + "_volDesc.txt"));
info.Artifacts["volDesc"] = GetBase64(GetFullFile(basePath + "_volDesc.txt")) ?? string.Empty;
}
}
@@ -144,7 +155,11 @@ namespace MPF.Modules.UmdImageCreator
/// </summary>
/// <param name="mainInfo">_mainInfo.txt file location</param>
/// <returns>Newline-deliminated PVD if possible, null on error</returns>
#if NET48
private static string GetPVD(string mainInfo)
#else
private static string? GetPVD(string mainInfo)
#endif
{
// If the file doesn't exist, we can't get info from it
if (!File.Exists(mainInfo))
@@ -155,10 +170,10 @@ namespace MPF.Modules.UmdImageCreator
try
{
// Make sure we're in the right sector
while (!sr.ReadLine().StartsWith("========== LBA[000016, 0x0000010]: Main Channel ==========")) ;
while (sr.ReadLine()?.StartsWith("========== LBA[000016, 0x0000010]: Main Channel ==========") == false) ;
// Fast forward to the PVD
while (!sr.ReadLine().StartsWith("0310")) ;
while (sr.ReadLine()?.StartsWith("0310") == false) ;
// Now that we're at the PVD, read each line in and concatenate
string pvd = "";
@@ -180,7 +195,11 @@ namespace MPF.Modules.UmdImageCreator
/// </summary>
/// <param name="disc">_disc.txt file location</param>
/// <returns>True on successful extraction of info, false otherwise</returns>
#if NET48
private static bool GetUMDAuxInfo(string disc, out string title, out DiscCategory? umdcat, out string umdversion, out string umdlayer, out long umdsize)
#else
private static bool GetUMDAuxInfo(string disc, out string? title, out DiscCategory? umdcat, out string? umdversion, out string? umdlayer, out long umdsize)
#endif
{
title = null; umdcat = null; umdversion = null; umdlayer = null; umdsize = -1;
@@ -193,10 +212,12 @@ namespace MPF.Modules.UmdImageCreator
try
{
// Loop through everything to get the first instance of each required field
string line = string.Empty;
var line = string.Empty;
while (!sr.EndOfStream)
{
line = sr.ReadLine().Trim();
line = sr.ReadLine()?.Trim();
if (line == null)
break;
if (line.StartsWith("TITLE") && title == null)
title = line.Substring("TITLE: ".Length);
@@ -211,7 +232,7 @@ namespace MPF.Modules.UmdImageCreator
}
// If the L0 length is the size of the full disc, there's no layerbreak
if (Int64.Parse(umdlayer) * 2048 == umdsize)
if (Int64.TryParse(umdlayer, out long umdlayerValue) && umdlayerValue * 2048 == umdsize)
umdlayer = null;
return true;

View File

@@ -8,7 +8,7 @@ using BinaryObjectScanner.Protection;
using BurnOutSharp;
using psxt001z;
namespace MPF.Library
namespace MPF.Core
{
public static class Protection
{
@@ -19,7 +19,11 @@ namespace MPF.Library
/// <param name="options">Options object that determines what to scan</param>
/// <param name="progress">Optional progress callback</param>
/// <returns>Set of all detected copy protections with an optional error string</returns>
public static async Task<(Dictionary<string, List<string>>, string)> RunProtectionScanOnPath(string path, Core.Data.Options options, IProgress<ProtectionProgress> progress = null)
#if NET48
public static async Task<(Dictionary<string, List<string>>, string)> RunProtectionScanOnPath(string path, Data.Options options, IProgress<ProtectionProgress> progress = null)
#else
public static async Task<(Dictionary<string, List<string>>?, string?)> RunProtectionScanOnPath(string path, Data.Options options, IProgress<ProtectionProgress>? progress = null)
#endif
{
try
{
@@ -62,7 +66,11 @@ namespace MPF.Library
/// </summary>
/// <param name="protections">Dictionary of file to list of protection mappings</param>
/// <returns>Detected protections, if any</returns>
#if NET48
public static string FormatProtections(Dictionary<string, List<string>> protections)
#else
public static string? FormatProtections(Dictionary<string, List<string>>? protections)
#endif
{
// If the filtered list is empty in some way, return
if (protections == null || !protections.Any())

View File

@@ -3,13 +3,13 @@ using System.Collections.Generic;
using System.Linq;
using MPF.Core.Converters;
namespace MPF.UI.Core.ComboBoxItems
namespace MPF.Core.UI.ComboBoxItems
{
/// <summary>
/// A generic combo box element
/// </summary>
/// <typeparam name="T">Enum type representing the possible values</typeparam>
public class Element<T> : IElement where T : struct, Enum
public class Element<T> : IEquatable<Element<T>>, IElement where T : struct, Enum
{
private readonly T Data;
@@ -47,5 +47,18 @@ namespace MPF.UI.Core.ComboBoxItems
.OfType<T>()
.Select(e => new Element<T>(e));
}
/// <inheritdoc/>
#if NET48
public bool Equals(Element<T> other)
#else
public bool Equals(Element<T>? other)
#endif
{
if (other == null)
return false;
return Name == other.Name;
}
}
}

View File

@@ -1,4 +1,4 @@
namespace MPF.UI.Core.ComboBoxItems
namespace MPF.Core.UI.ComboBoxItems
{
public interface IElement
{

View File

@@ -1,18 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using MPF.Core.Utilities;
using MPF.UI.Core.ComboBoxItems;
using SabreTools.RedumpLib.Data;
namespace MPF.UI.Core.ComboBoxItems
namespace MPF.Core.UI.ComboBoxItems
{
/// <summary>
/// Represents a single item in the System combo box
/// </summary>
public class RedumpSystemComboBoxItem : IElement
public class RedumpSystemComboBoxItem : IEquatable<RedumpSystemComboBoxItem>, IElement
{
#if NET48
private readonly object Data;
#else
private readonly object? Data;
#endif
public RedumpSystemComboBoxItem(RedumpSystem? system) => Data = system;
public RedumpSystemComboBoxItem(SystemCategory? category) => Data = category;
@@ -81,5 +83,18 @@ namespace MPF.UI.Core.ComboBoxItems
return systemsValues;
}
/// <inheritdoc/>
#if NET48
public bool Equals(RedumpSystemComboBoxItem other)
#else
public bool Equals(RedumpSystemComboBoxItem? other)
#endif
{
if (other == null)
return false;
return Value == other.Value;
}
}
}

View File

@@ -0,0 +1,245 @@
using System.Collections.Generic;
using System.Linq;
using MPF.Core.Data;
using MPF.Core.UI.ComboBoxItems;
using MPF.Core.Utilities;
using SabreTools.RedumpLib.Data;
namespace MPF.Core.UI.ViewModels
{
public class DiscInformationViewModel
{
#region Fields
/// <summary>
/// Application-level Options object
/// </summary>
public Options Options { 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 Redump-supported Regions
/// </summary>
private static readonly List<Region> RedumpRegions = new List<Region>
{
Region.Argentina,
Region.Asia,
Region.AsiaEurope,
Region.AsiaUSA,
Region.Australia,
Region.AustraliaGermany,
Region.AustraliaNewZealand,
Region.Austria,
Region.AustriaSwitzerland,
Region.Belarus,
Region.Belgium,
Region.BelgiumNetherlands,
Region.Brazil,
Region.Bulgaria,
Region.Canada,
Region.China,
Region.Croatia,
Region.Czechia,
Region.Denmark,
Region.Estonia,
Region.Europe,
Region.EuropeAsia,
Region.EuropeAustralia,
Region.EuropeCanada,
Region.EuropeGermany,
Region.Export,
Region.Finland,
Region.France,
Region.FranceSpain,
Region.Germany,
Region.GreaterChina,
Region.Greece,
Region.Hungary,
Region.Iceland,
Region.India,
Region.Ireland,
Region.Israel,
Region.Italy,
Region.Japan,
Region.JapanAsia,
Region.JapanEurope,
Region.JapanKorea,
Region.JapanUSA,
Region.SouthKorea,
Region.LatinAmerica,
Region.Lithuania,
Region.Netherlands,
Region.NewZealand,
Region.Norway,
Region.Poland,
Region.Portugal,
Region.Romania,
Region.RussianFederation,
Region.Scandinavia,
Region.Serbia,
Region.Singapore,
Region.Slovakia,
Region.SouthAfrica,
Region.Spain,
Region.SpainPortugal,
Region.Sweden,
Region.Switzerland,
Region.Taiwan,
Region.Thailand,
Region.Turkey,
Region.UnitedArabEmirates,
Region.UnitedKingdom,
Region.UKAustralia,
Region.Ukraine,
Region.UnitedStatesOfAmerica,
Region.USAAsia,
Region.USAAustralia,
Region.USABrazil,
Region.USACanada,
Region.USAEurope,
Region.USAGermany,
Region.USAJapan,
Region.USAKorea,
Region.World,
};
/// <summary>
/// List of available languages
/// </summary>
public List<Element<Language>> Languages { get; private set; } = Element<Language>.GenerateElements().ToList();
/// <summary>
/// List of Redump-supported Languages
/// </summary>
private static readonly List<Language> RedumpLanguages = new List<Language>
{
Language.Afrikaans,
Language.Albanian,
Language.Arabic,
Language.Armenian,
Language.Basque,
Language.Belarusian,
Language.Bulgarian,
Language.Catalan,
Language.Chinese,
Language.Croatian,
Language.Czech,
Language.Danish,
Language.Dutch,
Language.English,
Language.Estonian,
Language.Finnish,
Language.French,
Language.Gaelic,
Language.German,
Language.Greek,
Language.Hebrew,
Language.Hindi,
Language.Hungarian,
Language.Icelandic,
Language.Indonesian,
Language.Italian,
Language.Japanese,
Language.Korean,
Language.Latin,
Language.Latvian,
Language.Lithuanian,
Language.Macedonian,
Language.Norwegian,
Language.Polish,
Language.Portuguese,
Language.Panjabi,
Language.Romanian,
Language.Russian,
Language.Serbian,
Language.Slovak,
Language.Slovenian,
Language.Spanish,
Language.Swedish,
Language.Tamil,
Language.Thai,
Language.Turkish,
Language.Ukrainian,
Language.Vietnamese,
};
/// <summary>
/// List of available languages
/// </summary>
public List<Element<LanguageSelection>> LanguageSelections { get; private set; } = Element<LanguageSelection>.GenerateElements().ToList();
#endregion
/// <summary>
/// Constructor
/// </summary>
public DiscInformationViewModel(Options options, SubmissionInfo submissionInfo)
{
Options = options;
SubmissionInfo = submissionInfo.Clone() as SubmissionInfo ?? new SubmissionInfo();
}
#region Helpers
/// <summary>
/// Load the current contents of the base SubmissionInfo to the UI
/// </summary>
/// TODO: Convert selected list item to binding
public void Load()
{
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));
}
/// <summary>
/// Save the current contents of the UI to the base SubmissionInfo
/// </summary>
/// TODO: Convert selected list item to binding
public void Save()
{
if (SubmissionInfo.CommonDiscInfo == null) SubmissionInfo.CommonDiscInfo = new CommonDiscInfoSection();
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();
}
/// <summary>
/// Repopulate the list of Languages based on Redump support
/// </summary>
public void SetRedumpLanguages()
{
this.Languages = RedumpLanguages.Select(l => new Element<Language>(l)).ToList();
}
/// <summary>
/// Repopulate the list of Regions based on Redump support
/// </summary>
public void SetRedumpRegions()
{
this.Regions = RedumpRegions.Select(r => new Element<Region>(r)).ToList();
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,81 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MPF.Core.Data;
using MPF.Core.UI.ComboBoxItems;
using SabreTools.RedumpLib.Web;
namespace MPF.Core.UI.ViewModels
{
public class OptionsViewModel
{
#region Fields
/// <summary>
/// Current set of options
/// </summary>
public Options Options { get; }
/// <summary>
/// Flag for if settings were saved or not
/// </summary>
public bool SavedSettings { get; 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(Options baseOptions)
{
Options = new Options(baseOptions);
}
#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.Redumper };
return internalPrograms.Select(ip => new Element<InternalProgram>(ip)).ToList();
}
#endregion
#region UI Commands
/// <summary>
/// Test Redump login credentials
/// </summary>
#if NET48
public (bool?, string) TestRedumpLogin(string username, string password)
#else
public async Task<(bool?, string?)> TestRedumpLogin(string username, string password)
#endif
{
#if NET48
return RedumpWebClient.ValidateCredentials(username, password);
#else
return await RedumpHttpClient.ValidateCredentials(username, password);
#endif
}
#endregion
}
}

View File

@@ -14,7 +14,11 @@ namespace MPF.Core.Utilities
/// <param name="reader">TextReader representing the input</param>
/// <param name="baseClass">Invoking class, passed on to the event handler</param>
/// <param name="handler">Event handler to be invoked to write to log</param>
#if NET48
public static async Task OutputToLog(TextReader reader, object baseClass, EventHandler<string> handler)
#else
public static async Task OutputToLog(TextReader reader, object baseClass, EventHandler<string>? handler)
#endif
{
// Initialize the required variables
char[] buffer = new char[256];
@@ -63,7 +67,11 @@ namespace MPF.Core.Utilities
/// <param name="line">Current line to process</param>
/// <param name="baseClass">Invoking class, passed on to the event handler</param>
/// <param name="handler">Event handler to be invoked to write to log</param>
#if NET48
private static void ProcessNewLines(StringBuilder sb, string line, object baseClass, EventHandler<string> handler)
#else
private static void ProcessNewLines(StringBuilder sb, string line, object baseClass, EventHandler<string>? handler)
#endif
{
line = line.Replace("\r\n", "\n");
var split = line.Split('\n');
@@ -105,7 +113,11 @@ namespace MPF.Core.Utilities
/// <param name="line">Current line to process</param>
/// <param name="baseClass">Invoking class, passed on to the event handler</param>
/// <param name="handler">Event handler to be invoked to write to log</param>
#if NET48
private static void ProcessCarriageReturns(StringBuilder sb, string line, object baseClass, EventHandler<string> handler)
#else
private static void ProcessCarriageReturns(StringBuilder sb, string line, object baseClass, EventHandler<string>? handler)
#endif
{
var split = line.Split('\r');

View File

@@ -1,8 +1,10 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;
using MPF.Core.Converters;
using MPF.Core.Data;
using Newtonsoft.Json;
using SabreTools.RedumpLib.Data;
namespace MPF.Core.Utilities
{
@@ -12,10 +14,86 @@ namespace MPF.Core.Utilities
#region Arguments
/// <summary>
/// Process any standalone arguments for the program
/// </summary>
/// <returns>True if one of the arguments was processed, false otherwise</returns>
public static bool ProcessStandaloneArguments(string[] args)
{
// Help options
if (args.Length == 0 || args[0] == "-h" || args[0] == "-?")
return false;
// List options
if (args[0] == "-lm" || args[0] == "--listmedia")
{
Console.WriteLine("Supported Media Types:");
foreach (string mediaType in Extensions.ListMediaTypes())
{
Console.WriteLine(mediaType);
}
Console.ReadLine();
return true;
}
else if (args[0] == "-lp" || args[0] == "--listprograms")
{
Console.WriteLine("Supported Programs:");
foreach (string program in EnumExtensions.ListPrograms())
{
Console.WriteLine(program);
}
Console.ReadLine();
return true;
}
else if (args[0] == "-ls" || args[0] == "--listsystems")
{
Console.WriteLine("Supported Systems:");
foreach (string system in Extensions.ListSystems())
{
Console.WriteLine(system);
}
Console.ReadLine();
return true;
}
return false;
}
/// <summary>
/// Process common arguments for all functionality
/// </summary>
/// <returns>True if all arguments pass, false otherwise</returns>
#if NET48
public static (bool, MediaType, RedumpSystem?, string) ProcessCommonArguments(string[] args)
#else
public static (bool, MediaType, RedumpSystem?, string?) ProcessCommonArguments(string[] args)
#endif
{
// All other use requires at least 3 arguments
if (args.Length < 3)
return (false, MediaType.NONE, null, "Invalid number of arguments");
// Check the MediaType
var mediaType = EnumConverter.ToMediaType(args[0].Trim('"'));
if (mediaType == MediaType.NONE)
return (false, MediaType.NONE, null, $"{args[0]} is not a recognized media type");
// Check the RedumpSystem
var knownSystem = Extensions.ToRedumpSystem(args[1].Trim('"'));
if (knownSystem == null)
return (false, MediaType.NONE, null, $"{args[1]} is not a recognized system");
return (true, mediaType, knownSystem, null);
}
/// <summary>
/// Load the current set of options from application arguments
/// </summary>
#if NET48
public static (Options, string, int) LoadFromArguments(string[] args, int startIndex = 0)
#else
public static (Options, string?, int) LoadFromArguments(string[] args, int startIndex = 0)
#endif
{
// Create the output values with defaults
var options = new Options()
@@ -27,7 +105,11 @@ namespace MPF.Core.Utilities
CompressLogFiles = false,
};
#if NET48
string parsedPath = null;
#else
string? parsedPath = null;
#endif
// These values require multiple parts to be active
bool scan = false, protectFile = false;
@@ -137,7 +219,7 @@ namespace MPF.Core.Utilities
return supportedArguments;
}
#endregion
#endregion
#region Configuration
@@ -154,7 +236,11 @@ namespace MPF.Core.Utilities
var serializer = JsonSerializer.Create();
var reader = new StreamReader(ConfigurationPath);
#if NET48
var settings = serializer.Deserialize(reader, typeof(Dictionary<string, string>)) as Dictionary<string, string>;
#else
var settings = serializer.Deserialize(reader, typeof(Dictionary<string, string?>)) as Dictionary<string, string?>;
#endif
return new Options(settings);
}

View File

@@ -130,16 +130,23 @@ namespace MPF.Core.Utilities
/// String representing the message to display the the user.
/// String representing the new release URL.
/// </returns>
#if NET48
public static (bool different, string message, string url) CheckForNewVersion()
#else
public static (bool different, string message, string? url) CheckForNewVersion()
#endif
{
try
{
// Get current assembly version
var assemblyVersion = Assembly.GetEntryAssembly().GetName().Version;
var assemblyVersion = Assembly.GetEntryAssembly()?.GetName()?.Version;
if (assemblyVersion == null)
return (false, "Assembly version could not be determined", null);
string version = $"{assemblyVersion.Major}.{assemblyVersion.Minor}" + (assemblyVersion.Build != 0 ? $".{assemblyVersion.Build}" : string.Empty);
// Get the latest tag from GitHub
(string tag, string url) = GetRemoteVersionAndUrl();
var (tag, url) = GetRemoteVersionAndUrl();
bool different = version != tag;
string message = $"Local version: {version}"
@@ -159,12 +166,20 @@ namespace MPF.Core.Utilities
/// <summary>
/// Get the current informational version formatted as a string
/// </summary>
#if NET48
public static string GetCurrentVersion()
#else
public static string? GetCurrentVersion()
#endif
{
try
{
var assemblyVersion = Attribute.GetCustomAttribute(Assembly.GetEntryAssembly(), typeof(AssemblyInformationalVersionAttribute)) as AssemblyInformationalVersionAttribute;
return assemblyVersion.InformationalVersion;
var assembly = Assembly.GetEntryAssembly();
if (assembly == null)
return null;
var assemblyVersion = Attribute.GetCustomAttribute(assembly, typeof(AssemblyInformationalVersionAttribute)) as AssemblyInformationalVersionAttribute;
return assemblyVersion?.InformationalVersion;
}
catch (Exception ex)
{
@@ -175,9 +190,13 @@ namespace MPF.Core.Utilities
/// <summary>
/// Get the latest version of MPF from GitHub and the release URL
/// </summary>
#if NET48
private static (string tag, string url) GetRemoteVersionAndUrl()
#else
private static (string? tag, string? url) GetRemoteVersionAndUrl()
#endif
{
#if NETFRAMEWORK
#if NET48
using (System.Net.WebClient wc = new System.Net.WebClient())
{
wc.Headers["User-Agent"] = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0";
@@ -198,10 +217,16 @@ namespace MPF.Core.Utilities
string url = "https://api.github.com/repos/SabreTools/MPF/releases/latest";
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, url);
message.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0");
string latestReleaseJsonString = hc.Send(message)?.Content?.ReadAsStringAsync().ConfigureAwait(false).GetAwaiter().GetResult();
var latestReleaseJsonString = hc.Send(message)?.Content?.ReadAsStringAsync().ConfigureAwait(false).GetAwaiter().GetResult();
if (latestReleaseJsonString == null)
return (null, null);
var latestReleaseJson = JObject.Parse(latestReleaseJsonString);
string latestTag = latestReleaseJson["tag_name"].ToString();
string releaseUrl = latestReleaseJson["html_url"].ToString();
if (latestReleaseJson == null)
return (null, null);
var latestTag = latestReleaseJson["tag_name"]?.ToString();
var releaseUrl = latestReleaseJson["html_url"]?.ToString();
return (latestTag, releaseUrl);
}

View File

@@ -1,4 +0,0 @@
using System.Runtime.CompilerServices;
// Anything marked as internal can be used by the test methods
[assembly: InternalsVisibleTo("MPF.Test")]

View File

@@ -1,43 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48;net6.0;net7.0</TargetFrameworks>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Copyright>Copyright (c)2019-2023</Copyright>
<Version>2.6.6</Version>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup>
<NrtRevisionFormat>$(Version)-{chash:8}</NrtRevisionFormat>
<NrtResolveSimpleAttributes>true</NrtResolveSimpleAttributes>
<NrtShowRevision>false</NrtShowRevision>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MPF.Core\MPF.Core.csproj" />
<ProjectReference Include="..\MPF.Modules\MPF.Modules.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BurnOutSharp" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="2.8.0" GeneratePathProperty="true">
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="SabreTools.Models" Version="1.1.4" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.1.1" />
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Content Include="$(PkgBurnOutSharp)\content\**" PackagePath="contentFiles\any\any;content" CopyToOutputDirectory="Always" PackageCopyToOutput="true" />
</ItemGroup>
</Project>

View File

@@ -1,4 +0,0 @@
using System.Runtime.CompilerServices;
// Anything marked as internal can be used by the test methods
[assembly: InternalsVisibleTo("MPF.Test")]

View File

@@ -1,34 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48;net6.0;net7.0</TargetFrameworks>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Copyright>Copyright (c)2019-2023</Copyright>
<Version>2.6.6</Version>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup>
<NrtRevisionFormat>$(Version)-{chash:8}</NrtRevisionFormat>
<NrtResolveSimpleAttributes>true</NrtResolveSimpleAttributes>
<NrtShowRevision>false</NrtShowRevision>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MPF.Core\MPF.Core.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.Models" Version="1.1.4" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.1.1" />
<PackageReference Include="SabreTools.Serialization" Version="1.1.6" />
<PackageReference Include="System.Memory" Version="4.5.5" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View File

@@ -2,9 +2,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
#if NETFRAMEWORK
using IMAPI2;
#endif
using MPF.Core.Converters;
using MPF.Core.Data;
using Xunit;
@@ -25,35 +22,6 @@ namespace MPF.Test.Core.Converters
DriveType.Removable,
};
#if NETFRAMEWORK
/// <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>
@@ -71,25 +39,6 @@ namespace MPF.Test.Core.Converters
Assert.NotNull(actual);
}
#if NETFRAMEWORK
/// <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>
@@ -108,26 +57,6 @@ namespace MPF.Test.Core.Converters
return testData;
}
#if NETFRAMEWORK
/// <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

View File

@@ -1,6 +1,5 @@
using System.IO;
using MPF.Core;
using MPF.Core.Data;
using MPF.Library;
using SabreTools.RedumpLib.Data;
using Xunit;

View File

@@ -1,6 +1,6 @@
using System.Collections.Generic;
using System.IO;
using MPF.Library;
using MPF.Core;
using SabreTools.RedumpLib.Data;
using Xunit;

View File

@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using MPF.Library;
using MPF.Core;
using Xunit;
namespace MPF.Test.Library

View File

@@ -5,31 +5,8 @@
<IsPackable>false</IsPackable>
</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="..\MPF\MPF.csproj" />
<ProjectReference Include="..\MPF.Library\MPF.Library.csproj" />
<ProjectReference Include="..\MPF.Modules\MPF.Modules.csproj" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,6 +1,6 @@
using System.Collections.Generic;
using MPF.Core.Data;
using MPF.Modules.DiscImageCreator;
using MPF.Core.Modules.DiscImageCreator;
using SabreTools.RedumpLib.Data;
using Xunit;

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Windows.Media;
using static MPF.Core.Data.Interface;
namespace MPF.UI.Core
{
@@ -10,12 +11,6 @@ namespace MPF.UI.Core
/// </summary>
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> HDDVD { 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);

View File

@@ -0,0 +1,57 @@
using System;
using System.Globalization;
using System.Windows.Data;
using MPF.Core.Data;
using MPF.Core.UI.ComboBoxItems;
using SabreTools.RedumpLib.Data;
namespace MPF.UI.Core
{
internal class ElementConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
switch (value)
{
case DiscCategory discCategory:
return new Element<DiscCategory>(discCategory);
case InternalProgram internalProgram:
return new Element<InternalProgram>(internalProgram);
case MediaType mediaType:
return new Element<MediaType>(mediaType);
case RedumpSystem redumpSystem:
return new RedumpSystemComboBoxItem(redumpSystem);
case Region region:
return new Element<Region>(region);
// Null values are treated as a system value
default:
return new RedumpSystemComboBoxItem((RedumpSystem?)null);
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
// If it's an IElement but ends up null
var element = value as IElement;
if (element == null)
return null;
switch (element)
{
case Element<DiscCategory> dcElement:
return dcElement.Value;
case Element<InternalProgram> ipElement:
return ipElement.Value;
case Element<MediaType> mtElement:
return mtElement.Value;
case RedumpSystemComboBoxItem rsElement:
return rsElement.Value;
case Element<Region> reValue:
return reValue.Value;
default: return null;
}
}
}
}

View File

@@ -7,14 +7,7 @@
<UseWPF>true</UseWPF>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Copyright>Copyright (c)2019-2023</Copyright>
<Version>2.6.6</Version>
</PropertyGroup>
<PropertyGroup>
<NrtRevisionFormat>$(Version)-{chash:8}</NrtRevisionFormat>
<NrtResolveSimpleAttributes>true</NrtResolveSimpleAttributes>
<NrtShowRevision>false</NrtShowRevision>
<UserSecretsId>27abb4ca-bf7a-431e-932f-49153303d5ff</UserSecretsId>
<VersionPrefix>2.7.0</VersionPrefix>
</PropertyGroup>
<ItemGroup>
@@ -24,7 +17,6 @@
<ItemGroup>
<ProjectReference Include="..\MPF.Core\MPF.Core.csproj" />
<ProjectReference Include="..\MPF.Library\MPF.Library.csproj" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net48'">
@@ -33,14 +25,6 @@
<ItemGroup>
<PackageReference Include="SabreTools.RedumpLib" Version="1.1.1" />
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Images\" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,19 +1,219 @@
using System.Windows.Controls;
using MPF.UI.Core.ViewModels;
using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Threading;
using MPF.Core.Data;
namespace MPF.UI.Core.UserControls
{
public partial class LogOutput : UserControl
{
/// <summary>
/// Read-only access to the current log view model
/// Document representing the text
/// </summary>
public LogViewModel LogViewModel => DataContext as LogViewModel;
internal FlowDocument Document { get; private set; }
/// <summary>
/// Queue of items that need to be logged
/// </summary>
internal ProcessingQueue<LogLine> LogQueue { get; private set; }
/// <summary>
/// Paragraph backing the log
/// </summary>
private readonly Paragraph _paragraph;
/// <summary>
/// Cached value of the last line written
/// </summary>
private Run lastLine = null;
public LogOutput()
{
InitializeComponent();
DataContext = new LogViewModel(this);
// Update the internal state
Document = new FlowDocument()
{
Background = new SolidColorBrush(Color.FromArgb(0xFF, 0x20, 0x20, 0x20))
};
_paragraph = new Paragraph();
Document.Blocks.Add(_paragraph);
// Setup the processing queue
LogQueue = new ProcessingQueue<LogLine>(ProcessLogLine);
// Add handlers
OutputViewer.SizeChanged += OutputViewerSizeChanged;
Output.TextChanged += OnTextChanged;
ClearButton.Click += OnClearButton;
SaveButton.Click += OnSaveButton;
// Update the internal state
Output.Document = Document;
}
#region Logging
/// <summary>
/// Enqueue text to the log with formatting
/// </summary>
/// <param name="logLevel">LogLevel for the log</param>
/// <param name="text">Text to write to the log</param>
public void EnqueueLog(LogLevel logLevel, string text)
{
// Null text gets ignored
if (text == null)
return;
// Enqueue the text
LogQueue.Enqueue(new LogLine(text, logLevel));
}
/// <summary>
/// Log line wrapper
/// </summary>
internal readonly 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>
/// Process the log lines in the queue
/// </summary>
/// <param name="nextLogLine">LogLine item to process</param>
internal void ProcessLogLine(LogLine nextLogLine)
{
// Null text gets ignored
string nextText = nextLogLine.Text;
if (nextText == null)
return;
try
{
if (nextText.StartsWith("\r"))
ReplaceLastLine(nextLogLine);
else
AppendToTextBox(nextLogLine);
}
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>
/// 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 Helpers
/// <summary>
/// Clear all inlines of the paragraph
/// </summary>
private void ClearInlines() => _paragraph.Inlines.Clear();
/// <summary>
/// Save all inlines to console.log
/// </summary>
private void SaveInlines()
{
using (StreamWriter tw = new StreamWriter(File.OpenWrite("console.log")))
{
foreach (var inline in _paragraph.Inlines)
{
if (inline is Run run)
tw.Write(run.Text);
}
}
}
/// <summary>
/// Scroll the current view to the bottom
/// </summary>
public void ScrollToBottom() => OutputViewer.ScrollToBottom();
#endregion
#region EventHandlers
private void OnClearButton(object sender, EventArgs e)
=> ClearInlines();
private void OnSaveButton(object sender, EventArgs e)
=> SaveInlines();
private void OnTextChanged(object sender, TextChangedEventArgs e)
=> ScrollToBottom();
private void OutputViewerSizeChanged(object sender, SizeChangedEventArgs e)
=> ScrollToBottom();
#endregion
}
}

View File

@@ -1,850 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using MPF.Core.Data;
using MPF.Core.Utilities;
using MPF.UI.Core.ComboBoxItems;
using MPF.UI.Core.Windows;
using SabreTools.RedumpLib.Data;
namespace MPF.UI.Core.ViewModels
{
public class DiscInformationViewModel
{
#region Fields
/// <summary>
/// Parent DiscInformationWindow object
/// </summary>
public DiscInformationWindow Parent { get; private set; }
/// <summary>
/// Application-level Options object
/// </summary>
public Options Options { 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 Redump-supported Regions
/// </summary>
private static readonly List<Region> RedumpRegions = new List<Region>
{
Region.Argentina,
Region.Asia,
Region.AsiaEurope,
Region.AsiaUSA,
Region.Australia,
Region.AustraliaGermany,
Region.AustraliaNewZealand,
Region.Austria,
Region.AustriaSwitzerland,
Region.Belarus,
Region.Belgium,
Region.BelgiumNetherlands,
Region.Brazil,
Region.Bulgaria,
Region.Canada,
Region.China,
Region.Croatia,
Region.Czechia,
Region.Denmark,
Region.Estonia,
Region.Europe,
Region.EuropeAsia,
Region.EuropeAustralia,
Region.EuropeCanada,
Region.EuropeGermany,
Region.Export,
Region.Finland,
Region.France,
Region.FranceSpain,
Region.Germany,
Region.GreaterChina,
Region.Greece,
Region.Hungary,
Region.Iceland,
Region.India,
Region.Ireland,
Region.Israel,
Region.Italy,
Region.Japan,
Region.JapanAsia,
Region.JapanEurope,
Region.JapanKorea,
Region.JapanUSA,
Region.SouthKorea,
Region.LatinAmerica,
Region.Lithuania,
Region.Netherlands,
Region.NewZealand,
Region.Norway,
Region.Poland,
Region.Portugal,
Region.Romania,
Region.RussianFederation,
Region.Scandinavia,
Region.Serbia,
Region.Singapore,
Region.Slovakia,
Region.SouthAfrica,
Region.Spain,
Region.SpainPortugal,
Region.Sweden,
Region.Switzerland,
Region.Taiwan,
Region.Thailand,
Region.Turkey,
Region.UnitedArabEmirates,
Region.UnitedKingdom,
Region.UKAustralia,
Region.Ukraine,
Region.UnitedStatesOfAmerica,
Region.USAAsia,
Region.USAAustralia,
Region.USABrazil,
Region.USACanada,
Region.USAEurope,
Region.USAGermany,
Region.USAJapan,
Region.USAKorea,
Region.World,
};
/// <summary>
/// List of available languages
/// </summary>
public List<Element<Language>> Languages { get; private set; } = Element<Language>.GenerateElements().ToList();
/// <summary>
/// List of Redump-supported Languages
/// </summary>
private static readonly List<Language> RedumpLanguages = new List<Language>
{
Language.Afrikaans,
Language.Albanian,
Language.Arabic,
Language.Armenian,
Language.Basque,
Language.Belarusian,
Language.Bulgarian,
Language.Catalan,
Language.Chinese,
Language.Croatian,
Language.Czech,
Language.Danish,
Language.Dutch,
Language.English,
Language.Estonian,
Language.Finnish,
Language.French,
Language.Gaelic,
Language.German,
Language.Greek,
Language.Hebrew,
Language.Hindi,
Language.Hungarian,
Language.Icelandic,
Language.Indonesian,
Language.Italian,
Language.Japanese,
Language.Korean,
Language.Latin,
Language.Latvian,
Language.Lithuanian,
Language.Macedonian,
Language.Norwegian,
Language.Polish,
Language.Portuguese,
Language.Panjabi,
Language.Romanian,
Language.Russian,
Language.Serbian,
Language.Slovak,
Language.Slovenian,
Language.Spanish,
Language.Swedish,
Language.Tamil,
Language.Thai,
Language.Turkish,
Language.Ukrainian,
Language.Vietnamese,
};
/// <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, Options options, SubmissionInfo submissionInfo)
{
Parent = parent;
Options = options;
SubmissionInfo = submissionInfo.Clone() as SubmissionInfo ?? new SubmissionInfo();
// Limit lists, if necessary
if (this.Options.EnableRedumpCompatibility)
{
SetRedumpRegions();
SetRedumpLanguages();
}
// 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;
// Contents
Parent.GeneralContent.Tab = true;
Parent.GamesTextBox.Tab = true;
Parent.NetYarozeGamesTextBox.Tab = true;
Parent.PlayableDemosTextBox.Tab = true;
Parent.RollingDemosTextBox.Tab = true;
Parent.TechDemosTextBox.Tab = true;
Parent.GameFootageTextBox.Tab = true;
Parent.VideosTextBox.Tab = true;
Parent.PatchesTextBox.Tab = true;
Parent.SavegamesTextBox.Tab = true;
Parent.ExtrasTextBox.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?.FullyMatchedID == null)
Parent.FullyMatchedID.Visibility = Visibility.Collapsed;
else
Parent.FullyMatchedID.Text = SubmissionInfo.FullyMatchedID.ToString();
if (SubmissionInfo?.PartiallyMatchedIDs == null)
Parent.PartiallyMatchedIDs.Visibility = Visibility.Collapsed;
else
Parent.PartiallyMatchedIDs.Text = string.Join(", ", SubmissionInfo.PartiallyMatchedIDs);
if (SubmissionInfo?.CopyProtection?.AntiModchip == null)
Parent.AntiModchip.Visibility = Visibility.Collapsed;
else
Parent.AntiModchip.Text = SubmissionInfo.CopyProtection.AntiModchip.LongName();
if (SubmissionInfo?.TracksAndWriteOffsets?.OtherWriteOffsets == null)
Parent.DiscOffset.Visibility = Visibility.Collapsed;
else
Parent.DiscOffset.Text = SubmissionInfo.TracksAndWriteOffsets.OtherWriteOffsets;
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.DMIHash) != true)
Parent.DMIHash.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?.CommonDiscInfo?.ErrorsCount))
Parent.ErrorsCount.Visibility = Visibility.Collapsed;
if (string.IsNullOrWhiteSpace(SubmissionInfo?.CommonDiscInfo?.EXEDateBuildDate))
Parent.EXEDateBuildDate.Visibility = Visibility.Collapsed;
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.Filename) != true)
Parent.Filename.Visibility = Visibility.Collapsed;
if (string.IsNullOrWhiteSpace(SubmissionInfo?.Extras?.Header))
Parent.Header.Visibility = Visibility.Collapsed;
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.InternalName) != true)
Parent.InternalName.Visibility = Visibility.Collapsed;
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.InternalSerialName) != true)
Parent.InternalSerialName.Visibility = Visibility.Collapsed;
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.Multisession) != true)
Parent.Multisession.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?.Extras?.PVD))
Parent.PVD.Visibility = Visibility.Collapsed;
if (SubmissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.RingNonZeroDataStart) != true)
Parent.RingNonZeroDataStart.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.UniversalHash) != true)
Parent.UniversalHash.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 (this.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.CDProjektID))
Parent.CDProjektIDTextBox.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.CDProjektID];
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.Filename))
Parent.Filename.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.Filename];
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.InternalName))
Parent.InternalName.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalName];
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.InternalSerialName))
Parent.InternalSerialName.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName];
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.Multisession))
Parent.Multisession.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.Multisession];
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.PFIHash))
Parent.PFIHash.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.PFIHash];
if (SubmissionInfo.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.RingNonZeroDataStart))
Parent.RingNonZeroDataStart.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.RingNonZeroDataStart];
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.UniversalHash))
Parent.UniversalHash.Text = SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.UniversalHash];
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)
#if NET48
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode?, string>();
#else
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields = new Dictionary<SiteCode, string>();
#endif
if (SubmissionInfo.CommonDiscInfo.ContentsSpecialFields == null)
#if NET48
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields = new Dictionary<SiteCode?, string>();
#else
SubmissionInfo.CommonDiscInfo.ContentsSpecialFields = new Dictionary<SiteCode, string>();
#endif
#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.CDProjektID] = Parent.CDProjektIDTextBox.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.Filename] = Parent.Filename.Text;
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalName] = Parent.InternalName.Text;
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.InternalSerialName] = Parent.InternalSerialName.Text;
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.Multisession] = Parent.Multisession.Text;
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.PFIHash] = Parent.PFIHash.Text;
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.RingNonZeroDataStart] = Parent.RingNonZeroDataStart.Text;
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSHash] = Parent.SSHash.Text;
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSVersion] = Parent.SSVersion.Text;
SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[SiteCode.UniversalHash] = Parent.UniversalHash.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>
/// Repopulate the list of Languages based on Redump support
/// </summary>
private void SetRedumpLanguages()
{
this.Languages = RedumpLanguages.Select(l => new Element<Language>(l)).ToList();
}
/// <summary>
/// Repopulate the list of Regions based on Redump support
/// </summary>
private void SetRedumpRegions()
{
this.Regions = RedumpRegions.Select(r => new Element<Region>(r)).ToList();
}
/// <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.HDDVDDL:
case DiscType.BD25:
case DiscType.BD33:
case DiscType.BD50:
case DiscType.BD66:
case DiscType.BD100:
case DiscType.BD128:
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
}
}

View File

@@ -1,293 +0,0 @@
using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using MPF.Core.Data;
using MPF.UI.Core.UserControls;
namespace MPF.UI.Core.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;
#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;
logQueue = new ProcessingQueue<LogLine>(ProcessLogLine);
}
#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, LogLevel.USER);
/// <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()
{
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</param>
private void LogInternal(string text, LogLevel logLevel)
{
// Null text gets ignored
if (text == null)
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 (nextText.StartsWith("\r"))
ReplaceLastLine(nextLogLine);
else
AppendToTextBox(nextLogLine);
}
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>
/// 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();
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,277 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using MPF.Core.Data;
using MPF.UI.Core.ComboBoxItems;
using MPF.UI.Core.Windows;
using SabreTools.RedumpLib.Web;
using WPFCustomMessageBox;
namespace MPF.UI.Core.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, Options baseOptions)
{
Parent = parent;
Options = new Options(baseOptions);
// Add handlers
Parent.AaruPathButton.Click += BrowseForPathClick;
Parent.DiscImageCreatorPathButton.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.Redumper };
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>
#if NET48
private bool? TestRedumpLogin()
#else
private async Task<bool?> TestRedumpLogin()
#endif
{
#if NET48
(bool? success, string message) = RedumpWebClient.ValidateCredentials(Parent.RedumpUsernameTextBox.Text, Parent.RedumpPasswordBox.Password);
#else
(bool? success, string message) = await RedumpHttpClient.ValidateCredentials(Parent.RedumpUsernameTextBox.Text, Parent.RedumpPasswordBox.Password);
#endif
if (success == true)
CustomMessageBox.Show(Parent, message, "Success", MessageBoxButton.OK, MessageBoxImage.Information);
else if (success == false)
CustomMessageBox.Show(Parent, message, "Failure", MessageBoxButton.OK, MessageBoxImage.Error);
else
CustomMessageBox.Show(Parent, message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return success;
}
#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>
#if NET48
private void OnRedumpTestClick(object sender, EventArgs e) =>
TestRedumpLogin();
#else
private async void OnRedumpTestClick(object sender, EventArgs e) =>
_ = await TestRedumpLogin();
#endif
#endregion
}
}

View File

@@ -4,12 +4,17 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:MPF.UI.Core.UserControls"
xmlns:core="clr-namespace:MPF.UI.Core"
xmlns:redump="clr-namespace:SabreTools.RedumpLib.Data;assembly=SabreTools.RedumpLib"
xmlns:windows="clr-namespace:MPF.UI.Core.Windows"
mc:Ignorable="d"
Title="Disc Information" Width="515" WindowStyle="None"
WindowStartupLocation="CenterOwner" ResizeMode="CanMinimize" SizeToContent="Height"
BorderBrush="DarkGray" BorderThickness="2">
<Window.Resources>
<core:ElementConverter x:Key="ElementConverter" />
</Window.Resources>
<WindowChrome.WindowChrome>
<WindowChrome CaptionHeight="0" ResizeBorderThickness="0" />
</WindowChrome.WindowChrome>
@@ -74,10 +79,12 @@
<StackPanel Orientation="Vertical">
<controls:UserInput Label="Title"
Text="{Binding SubmissionInfo.CommonDiscInfo.Title, Mode=TwoWay}"/>
<controls:UserInput x:Name="AlternativeTitleTextBox" Label="Alternative Title"/>
<controls:UserInput x:Name="AlternativeTitleTextBox" Label="Alternative Title"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)AlternativeTitle], Mode=TwoWay}"/>
<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 x:Name="AlternativeForeignTitleTextBox" Label="Alternative Foreign Title"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)AlternativeForeignTitle], Mode=TwoWay}"/>
<controls:UserInput Label="Disc Number / Letter"
Text="{Binding SubmissionInfo.CommonDiscInfo.DiscNumberLetter, Mode=TwoWay}"/>
<controls:UserInput Label="Disc Title"
@@ -90,8 +97,9 @@
</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}"
Style="{DynamicResource CustomComboBoxStyle}" />
<ComboBox x:Name="CategoryComboBox" Grid.Row="0" Grid.Column="1" Height="22" HorizontalAlignment="Stretch"
ItemsSource="{Binding Categories}" SelectedItem="{Binding SubmissionInfo.CommonDiscInfo.Category, Converter={StaticResource ElementConverter}, Mode=TwoWay}"
Style="{DynamicResource CustomComboBoxStyle}" />
</Grid>
<Grid>
@@ -101,8 +109,9 @@
</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}"
Style="{DynamicResource CustomComboBoxStyle}" />
<ComboBox x:Name="RegionComboBox" Grid.Row="0" Grid.Column="1" Height="22" HorizontalAlignment="Stretch"
ItemsSource="{Binding Regions}" SelectedItem="{Binding SubmissionInfo.CommonDiscInfo.Region, Converter={StaticResource ElementConverter}, Mode=TwoWay}"
Style="{DynamicResource CustomComboBoxStyle}" />
</Grid>
<Grid>
@@ -112,7 +121,8 @@
</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}"
<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>
@@ -129,7 +139,8 @@
</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}"
<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>
@@ -164,7 +175,8 @@
<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"/>
<controls:UserInput x:Name="GenreTextBox" Label="Genre"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)Genre], Mode=TwoWay}"/>
<controls:UserInput x:Name="ProtectionTextBox" Label="Protection" ToolTip="CAUTION: Only edit if you know what you are doing!"
Text="{Binding SubmissionInfo.CopyProtection.Protection, Mode=TwoWay}" TextHeight="75" TextWrapping="Wrap"
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>
@@ -175,9 +187,11 @@
</Grid.ColumnDefinitions>
<Label/>
<CheckBox Grid.Column="1" x:Name="PostgapTypeCheckBox" Content="Postgap type (Form 2)" Margin="0,4"/>
<CheckBox Grid.Column="1" x:Name="PostgapTypeCheckBox" Content="Postgap type (Form 2)" Margin="0,4"
IsChecked="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)PostgapType], Mode=TwoWay}"/>
</Grid>
<controls:UserInput x:Name="SeriesTextBox" Label="Series"/>
<controls:UserInput x:Name="SeriesTextBox" Label="Series"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)Series], Mode=TwoWay}"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.75*" />
@@ -185,7 +199,8 @@
</Grid.ColumnDefinitions>
<Label/>
<CheckBox Grid.Column="1" x:Name="VCDCheckBox" Content="V-CD" Margin="0,4"/>
<CheckBox Grid.Column="1" x:Name="VCDCheckBox" Content="V-CD" Margin="0,4"
IsChecked="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)VCD], Mode=TwoWay}"/>
</Grid>
</StackPanel>
</GroupBox>
@@ -193,43 +208,74 @@
<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="CDProjektIDTextBox" Label="CD Projekt ID"/>
<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"/>
<controls:UserInput x:Name="BBFCRegistrationNumberTextBox" Label="BBFC Reg. No."
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)BBFCRegistrationNumber], Mode=TwoWay}"/>
<controls:UserInput x:Name="DiscHologramIDTextBox" Label="Disc Hologram ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)DiscHologramID], Mode=TwoWay}"/>
<controls:UserInput x:Name="DNASDiscIDTextBox" Label="DNAS Disc ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)DNASDiscID], Mode=TwoWay}"/>
<controls:UserInput x:Name="ISBNTextBox" Label="ISBN"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)ISBN], Mode=TwoWay}"/>
<controls:UserInput x:Name="ISSNTextBox" Label="ISSN"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)ISSN], Mode=TwoWay}"/>
<controls:UserInput x:Name="PPNTextBox" Label="PPN"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)PPN], Mode=TwoWay}"/>
<controls:UserInput x:Name="VFCCodeTextBox" Label="VFC code"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)VFCCode], Mode=TwoWay}"/>
</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"/>
<controls:UserInput x:Name="AcclaimIDTextBox" Label="Acclaim ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)AcclaimID], Mode=TwoWay}"/>
<controls:UserInput x:Name="ActivisionIDTextBox" Label="Activision ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)ActivisionID], Mode=TwoWay}"/>
<controls:UserInput x:Name="BandaiIDTextBox" Label="Bandai ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)BandaiID], Mode=TwoWay}"/>
<controls:UserInput x:Name="CDProjektIDTextBox" Label="CD Projekt ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)CDProjektID], Mode=TwoWay}"/>
<controls:UserInput x:Name="ElectronicArtsIDTextBox" Label="Electronic Arts ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)ElectronicArtsID], Mode=TwoWay}"/>
<controls:UserInput x:Name="FoxInteractiveIDTextBox" Label="Fox Interactive ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)FoxInteractiveID], Mode=TwoWay}"/>
<controls:UserInput x:Name="GTInteractiveIDTextBox" Label="GT Interactive ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)GTInteractiveID], Mode=TwoWay}"/>
<controls:UserInput x:Name="JASRACIDTextBox" Label="JASRAC ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)JASRACID], Mode=TwoWay}"/>
<controls:UserInput x:Name="KingRecordsIDTextBox" Label="King Records ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)KingRecordsID], Mode=TwoWay}"/>
<controls:UserInput x:Name="KoeiIDTextBox" Label="Koei ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)KoeiID], Mode=TwoWay}"/>
<controls:UserInput x:Name="KonamiIDTextBox" Label="Konami ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)KonamiID], Mode=TwoWay}"/>
<controls:UserInput x:Name="LucasArtsIDTextBox" Label="LucasArts ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)LucasArtsID], Mode=TwoWay}"/>
<controls:UserInput x:Name="MicrosoftIDTextBox" Label="Microsoft ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)MicrosoftID], Mode=TwoWay}"/>
<controls:UserInput x:Name="NaganoIDTextBox" Label="Nagano ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)NaganoID], Mode=TwoWay}"/>
<controls:UserInput x:Name="NamcoIDTextBox" Label="Namco ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)NamcoID], Mode=TwoWay}"/>
<controls:UserInput x:Name="NipponIchiSoftwareIDTextBox" Label="Nippon Ichi Software ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)NipponIchiSoftwareID], Mode=TwoWay}"/>
<controls:UserInput x:Name="OriginIDTextBox" Label="Origin ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)OriginID], Mode=TwoWay}"/>
<controls:UserInput x:Name="PonyCanyonIDTextBox" Label="Pony Canyon ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)PonyCanyonID], Mode=TwoWay}"/>
<controls:UserInput x:Name="SegaIDTextBox" Label="Sega ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)SegaID], Mode=TwoWay}"/>
<controls:UserInput x:Name="SelenIDTextBox" Label="Selen ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)SelenID], Mode=TwoWay}"/>
<controls:UserInput x:Name="SierraIDTextBox" Label="Sierra ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)SierraID], Mode=TwoWay}"/>
<controls:UserInput x:Name="TaitoIDTextBox" Label="Taito ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)TaitoID], Mode=TwoWay}"/>
<controls:UserInput x:Name="UbisoftIDTextBox" Label="Ubisoft ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)UbisoftID], Mode=TwoWay}"/>
<controls:UserInput x:Name="ValveIDTextBox" Label="Valve ID"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)ValveID], Mode=TwoWay}"/>
</StackPanel>
</GroupBox>
</StackPanel>
@@ -245,31 +291,41 @@
<!-- Games -->
<controls:UserInput x:Name="GamesTextBox" Label="Games" TextHeight="50"
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"/>
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[(redump:SiteCode)Games], Mode=TwoWay}"/>
<controls:UserInput x:Name="NetYarozeGamesTextBox" Label="Net Yaroze Games" TextHeight="50"
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"/>
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[(redump:SiteCode)NetYarozeGames], Mode=TwoWay}"/>
<!-- Demos -->
<controls:UserInput x:Name="PlayableDemosTextBox" Label="Playable Demos" TextHeight="50"
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"/>
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[(redump:SiteCode)PlayableDemos], Mode=TwoWay}"/>
<controls:UserInput x:Name="RollingDemosTextBox" Label="Rolling Demos" TextHeight="50"
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"/>
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[(redump:SiteCode)RollingDemos], Mode=TwoWay}"/>
<controls:UserInput x:Name="TechDemosTextBox" Label="Tech Demos" TextHeight="50"
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"/>
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[(redump:SiteCode)TechDemos], Mode=TwoWay}"/>
<!-- Video -->
<controls:UserInput x:Name="GameFootageTextBox" Label="Game Footage" TextHeight="50"
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"/>
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[(redump:SiteCode)GameFootage], Mode=TwoWay}"/>
<controls:UserInput x:Name="VideosTextBox" Label="Videos" TextHeight="50"
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"/>
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[(redump:SiteCode)Videos], Mode=TwoWay}"/>
<!-- Miscellaneous -->
<controls:UserInput x:Name="PatchesTextBox" Label="Patches" TextHeight="50"
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"/>
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[(redump:SiteCode)Patches], Mode=TwoWay}"/>
<controls:UserInput x:Name="SavegamesTextBox" Label="Savegames" TextHeight="50"
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"/>
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[(redump:SiteCode)Savegames], Mode=TwoWay}"/>
<controls:UserInput x:Name="ExtrasTextBox" Label="Extras" TextHeight="50"
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"/>
Enter="True" TextWrapping="Wrap" VerticalContentAlignmentValue="Top"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.ContentsSpecialFields[(redump:SiteCode)Extras], Mode=TwoWay}"/>
</StackPanel>
</ScrollViewer>
</TabItem>
@@ -339,50 +395,68 @@
<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="FullyMatchedID" Label="Fully Matched ID" IsReadOnly="True"/>
<controls:UserInput x:Name="FullyMatchedID" Label="Fully Matched ID" IsReadOnly="True"
Text="{Binding SubmissionInfo.FullyMatchedID, Mode=TwoWay}"/>
<controls:UserInput x:Name="PartiallyMatchedIDs" Label="Partially Matched ID(s)" IsReadOnly="True"/>
<controls:UserInput x:Name="AntiModchip" Label="Anti-Modchip" IsReadOnly="True"/>
<controls:UserInput x:Name="DiscOffset" Label="Disc Offset" 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="AntiModchip" Label="Anti-Modchip" IsReadOnly="True"
Text="{Binding SubmissionInfo.CopyProtection.AntiModchip, Mode=TwoWay}"/>
<controls:UserInput x:Name="DiscOffset" Label="Disc Offset" IsReadOnly="True"
Text="{Binding SubmissionInfo.TracksAndWriteOffsets.OtherWriteOffsets, Mode=TwoWay}"/>
<controls:UserInput x:Name="DMIHash" Label="DMI Hash" IsReadOnly="True"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)DMIHash], Mode=TwoWay}"/>
<controls:UserInput x:Name="EDC" Label="EDC" IsReadOnly="True"
Text="{Binding SubmissionInfo.EDC.EDC, Mode=TwoWay}"/>
<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="Filename" Label="Filename" IsReadOnly="True"
TextHeight="75" TextWrapping="NoWrap"
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)Filename], 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="InternalName" Label="Internal Names" IsReadOnly="True"/>
<controls:UserInput x:Name="InternalSerialName" Label="Internal Serial" IsReadOnly="True"/>
<controls:UserInput x:Name="InternalName" Label="Internal Names" IsReadOnly="True"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)InternalName], Mode=TwoWay}"/>
<controls:UserInput x:Name="InternalSerialName" Label="Internal Serial" IsReadOnly="True"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)InternalSerialName], Mode=TwoWay}"/>
<controls:UserInput x:Name="Multisession" Label="Multisession" IsReadOnly="True" TextHeight="75" TextWrapping="NoWrap"
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>
<controls:UserInput x:Name="LibCrypt" Label="LibCrypt" IsReadOnly="True"/>
VerticalContentAlignmentValue="Top" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)Multisession], Mode=TwoWay}"/>
<controls:UserInput x:Name="LibCrypt" Label="LibCrypt" IsReadOnly="True"
Text="{Binding SubmissionInfo.CopyProtection.LibCrypt, Mode=TwoWay}"/>
<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="PFIHash" Label="PFI Hash" IsReadOnly="True"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)PFIHash], Mode=TwoWay}"/>
<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="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="RingNonZeroDataStart" Label="Ring Non-Zero Data Start" IsReadOnly="True"/>
<controls:UserInput x:Name="RingNonZeroDataStart" Label="Ring Non-Zero Data Start" IsReadOnly="True"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)RingNonZeroDataStart], Mode=TwoWay}"/>
<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="SSHash" Label="Security Sector Hash" IsReadOnly="True"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)SSHash], Mode=TwoWay}"/>
<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="UniversalHash" Label="Universal Hash (SHA-1)" 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"/>
<controls:UserInput x:Name="SSVersion" Label="Security Sector Version" IsReadOnly="True"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)SSVersion], Mode=TwoWay}"/>
<controls:UserInput x:Name="UniversalHash" Label="Universal Hash (SHA-1)" IsReadOnly="True"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)UniversalHash], Mode=TwoWay}"/>
<controls:UserInput x:Name="VolumeLabel" Label="Volume Label" IsReadOnly="True"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)VolumeLabel], Mode=TwoWay}"/>
<controls:UserInput x:Name="XeMID" Label="XeMID" IsReadOnly="True"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)XeMID], Mode=TwoWay}"/>
<controls:UserInput x:Name="XMID" Label="XMID" IsReadOnly="True"
Text="{Binding Path=SubmissionInfo.CommonDiscInfo.CommentsSpecialFields[(redump:SiteCode)XMID], Mode=TwoWay}"/>
<!-- TODO: Add track/checksum data once there's a reasonable way to do so -->
</StackPanel>

View File

@@ -1,5 +1,8 @@
using MPF.Core.Data;
using MPF.UI.Core.ViewModels;
using System.Linq;
using System.Windows;
using MPF.Core.Data;
using MPF.Core.UI.ViewModels;
using MPF.Core.Utilities;
using SabreTools.RedumpLib.Data;
namespace MPF.UI.Core.Windows
@@ -20,7 +23,356 @@ namespace MPF.UI.Core.Windows
public DiscInformationWindow(Options options, SubmissionInfo submissionInfo)
{
InitializeComponent();
DataContext = new DiscInformationViewModel(this, options, submissionInfo);
DataContext = new DiscInformationViewModel(options, submissionInfo);
DiscInformationViewModel.Load();
// Limit lists, if necessary
if (options.EnableRedumpCompatibility)
{
DiscInformationViewModel.SetRedumpRegions();
DiscInformationViewModel.SetRedumpLanguages();
}
// Add handlers
AcceptButton.Click += OnAcceptClick;
CancelButton.Click += OnCancelClick;
RingCodeGuideButton.Click += OnRingCodeGuideClick;
// Update UI with new values
ManipulateFields(options, submissionInfo);
}
#region Helpers
/// <summary>
/// Manipulate fields based on the current disc
/// </summary>
private void ManipulateFields(Options options, SubmissionInfo submissionInfo)
{
// Enable tabs in all fields, if required
if (options.EnableTabsInInputFields)
EnableTabsInInputFields();
// Hide read-only fields that don't have values set
HideReadOnlyFields(submissionInfo);
// Different media types mean different fields available
UpdateFromDiscType(submissionInfo);
// Different systems mean different fields available
UpdateFromSystemType(submissionInfo);
}
/// <summary>
/// Enable tab entry on supported fields
/// </summary>
/// TODO: See if these can be done by binding
private void EnableTabsInInputFields()
{
// Additional Information
CommentsTextBox.Tab = true;
// Contents
GeneralContent.Tab = true;
GamesTextBox.Tab = true;
NetYarozeGamesTextBox.Tab = true;
PlayableDemosTextBox.Tab = true;
RollingDemosTextBox.Tab = true;
TechDemosTextBox.Tab = true;
GameFootageTextBox.Tab = true;
VideosTextBox.Tab = true;
PatchesTextBox.Tab = true;
SavegamesTextBox.Tab = true;
ExtrasTextBox.Tab = true;
// L0
L0MasteringRing.Tab = true;
L0MasteringSID.Tab = true;
L0Toolstamp.Tab = true;
L0MouldSID.Tab = true;
L0AdditionalMould.Tab = true;
// L1
L1MasteringRing.Tab = true;
L1MasteringSID.Tab = true;
L1Toolstamp.Tab = true;
L1MouldSID.Tab = true;
L1AdditionalMould.Tab = true;
// L2
L2MasteringRing.Tab = true;
L2MasteringSID.Tab = true;
L2Toolstamp.Tab = true;
// L3
L3MasteringRing.Tab = true;
L3MasteringSID.Tab = true;
L3Toolstamp.Tab = true;
}
/// <summary>
/// Hide any optional, read-only fields if they don't have a value
/// </summary>
/// TODO: Figure out how to bind the PartiallyMatchedIDs array to a text box
/// TODO: Convert visibility to a binding
private void HideReadOnlyFields(SubmissionInfo submissionInfo)
{
if (submissionInfo?.FullyMatchedID == null)
FullyMatchedID.Visibility = Visibility.Collapsed;
if (submissionInfo?.PartiallyMatchedIDs == null)
PartiallyMatchedIDs.Visibility = Visibility.Collapsed;
else
PartiallyMatchedIDs.Text = string.Join(", ", submissionInfo.PartiallyMatchedIDs);
if (submissionInfo?.CopyProtection?.AntiModchip == null)
AntiModchip.Visibility = Visibility.Collapsed;
if (submissionInfo?.TracksAndWriteOffsets?.OtherWriteOffsets == null)
DiscOffset.Visibility = Visibility.Collapsed;
if (submissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.DMIHash) != true)
DMIHash.Visibility = Visibility.Collapsed;
if (submissionInfo?.EDC?.EDC == null)
EDC.Visibility = Visibility.Collapsed;
if (string.IsNullOrWhiteSpace(submissionInfo?.CommonDiscInfo?.ErrorsCount))
ErrorsCount.Visibility = Visibility.Collapsed;
if (string.IsNullOrWhiteSpace(submissionInfo?.CommonDiscInfo?.EXEDateBuildDate))
EXEDateBuildDate.Visibility = Visibility.Collapsed;
if (submissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.Filename) != true)
Filename.Visibility = Visibility.Collapsed;
if (string.IsNullOrWhiteSpace(submissionInfo?.Extras?.Header))
Header.Visibility = Visibility.Collapsed;
if (submissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.InternalName) != true)
InternalName.Visibility = Visibility.Collapsed;
if (submissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.InternalSerialName) != true)
InternalSerialName.Visibility = Visibility.Collapsed;
if (submissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.Multisession) != true)
Multisession.Visibility = Visibility.Collapsed;
if (submissionInfo?.CopyProtection?.LibCrypt == null)
LibCrypt.Visibility = Visibility.Collapsed;
if (string.IsNullOrWhiteSpace(submissionInfo?.CopyProtection?.LibCryptData))
LibCryptData.Visibility = Visibility.Collapsed;
if (submissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.PFIHash) != true)
PFIHash.Visibility = Visibility.Collapsed;
if (string.IsNullOrWhiteSpace(submissionInfo?.Extras?.PIC))
PIC.Visibility = Visibility.Collapsed;
if (string.IsNullOrWhiteSpace(submissionInfo?.Extras?.PVD))
PVD.Visibility = Visibility.Collapsed;
if (submissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.RingNonZeroDataStart) != true)
RingNonZeroDataStart.Visibility = Visibility.Collapsed;
if (string.IsNullOrWhiteSpace(submissionInfo?.CopyProtection?.SecuROMData))
SecuROMData.Visibility = Visibility.Collapsed;
if (submissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.SSHash) != true)
SSHash.Visibility = Visibility.Collapsed;
if (string.IsNullOrWhiteSpace(submissionInfo?.Extras?.SecuritySectorRanges))
SecuritySectorRanges.Visibility = Visibility.Collapsed;
if (submissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.SSVersion) != true)
SSVersion.Visibility = Visibility.Collapsed;
if (submissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.UniversalHash) != true)
UniversalHash.Visibility = Visibility.Collapsed;
if (submissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.VolumeLabel) != true)
VolumeLabel.Visibility = Visibility.Collapsed;
if (submissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.XeMID) != true)
XeMID.Visibility = Visibility.Collapsed;
if (submissionInfo?.CommonDiscInfo?.CommentsSpecialFields.Keys.Contains(SiteCode.XMID) != true)
XMID.Visibility = Visibility.Collapsed;
}
/// <summary>
/// Update visible fields and sections based on the media type
/// </summary>
/// TODO: See if these can be done by binding
private void UpdateFromDiscType(SubmissionInfo submissionInfo)
{
// 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:
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 DiscType.DVD5:
case DiscType.DVD9:
case DiscType.HDDVDSL:
case DiscType.HDDVDDL:
case DiscType.BD25:
case DiscType.BD33:
case DiscType.BD50:
case DiscType.BD66:
case DiscType.BD100:
case DiscType.BD128:
case DiscType.NintendoGameCubeGameDisc:
case DiscType.NintendoWiiOpticalDiscSL:
case DiscType.NintendoWiiOpticalDiscDL:
case DiscType.NintendoWiiUOpticalDiscSL:
// 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;
}
}
/// <summary>
/// Update visible fields and sections based on the system type
/// </summary>
/// TODO: See if these can be done by binding
private void UpdateFromSystemType(SubmissionInfo submissionInfo)
{
var system = submissionInfo?.CommonDiscInfo?.System;
switch (system)
{
case RedumpSystem.SonyPlayStation2:
LanguageSelectionGrid.Visibility = Visibility.Visible;
break;
}
}
#endregion
#region Event Handlers
/// <summary>
/// Handler for AcceptButton Click event
/// </summary>
private void OnAcceptClick(object sender, RoutedEventArgs e)
{
DiscInformationViewModel.Save();
DialogResult = true;
Close();
}
/// <summary>
/// Handler for CancelButton Click event
/// </summary>
private void OnCancelClick(object sender, RoutedEventArgs e)
{
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();
}
#endregion
}
}

View File

@@ -4,20 +4,23 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:MPF.UI.Core.UserControls"
xmlns:core="clr-namespace:MPF.UI.Core"
xmlns:coreWindows="clr-namespace:MPF.UI.Core.Windows"
xmlns:viewModels="clr-namespace:MPF.UI.Core.ViewModels"
xmlns:viewModels="clr-namespace:MPF.Core.UI.ViewModels;assembly=MPF.Core"
mc:Ignorable="d"
Title="Media Preservation Frontend" Width="600" WindowStyle="None"
WindowStartupLocation="CenterScreen" ResizeMode="CanMinimize" SizeToContent="Height"
BorderBrush="DarkGray" BorderThickness="2">
<WindowChrome.WindowChrome>
<WindowChrome CaptionHeight="0" ResizeBorderThickness="0" />
</WindowChrome.WindowChrome>
<Window.DataContext>
<viewModels:MainViewModel/>
</Window.DataContext>
<Window.Resources>
<core:ElementConverter x:Key="ElementConverter" />
</Window.Resources>
<WindowChrome.WindowChrome>
<WindowChrome CaptionHeight="0" ResizeBorderThickness="0" />
</WindowChrome.WindowChrome>
<Grid>
<StackPanel Orientation="Vertical">
@@ -52,7 +55,8 @@
<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}" />
Template="{DynamicResource CustomMenuItemTemplate}"
IsEnabled="{Binding OptionsMenuItemEnabled}"/>
<MenuItem x:Name="DebugViewMenuItem" Header="_Debug Info Window" HorizontalAlignment="Left" Width="185"
Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
Foreground="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"
@@ -123,7 +127,9 @@
</Grid.RowDefinitions>
<Label x:Name="SystemMediaTypeLabel" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Content="System/Media Type" />
<ComboBox x:Name="SystemTypeComboBox" Grid.Row="0" Grid.Column="1" Height="22" Width="250" HorizontalAlignment="Left" ItemsSource="{Binding Systems}" SelectedIndex="0" Style="{DynamicResource CustomComboBoxStyle}">
<ComboBox x:Name="SystemTypeComboBox" Grid.Row="0" Grid.Column="1" Height="22" Width="250" HorizontalAlignment="Left"
ItemsSource="{Binding Systems}" SelectedItem="{Binding Path=CurrentSystem, Converter={StaticResource ElementConverter}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding SystemTypeComboBoxEnabled}" Style="{DynamicResource CustomComboBoxStyle}">
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Style.Triggers>
@@ -134,15 +140,21 @@
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
<ComboBox x:Name="MediaTypeComboBox" Grid.Row="0" Grid.Column="1" Height="22" Width="140" HorizontalAlignment="Right" Style="{DynamicResource CustomComboBoxStyle}" />
<ComboBox x:Name="MediaTypeComboBox" Grid.Row="0" Grid.Column="1" Height="22" Width="140" HorizontalAlignment="Right"
ItemsSource="{Binding MediaTypes}" SelectedItem="{Binding Path=CurrentMediaType, Converter={StaticResource ElementConverter}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding MediaTypeComboBoxEnabled}" Style="{DynamicResource CustomComboBoxStyle}" />
<Label x:Name="OutputPathLabel" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" Content="Output Path"/>
<TextBox x:Name="OutputPathTextBox" Grid.Row="1" Grid.Column="1" Height="22" Width="345" HorizontalAlignment="Left" VerticalContentAlignment="Center" />
<TextBox x:Name="OutputPathTextBox" Grid.Row="1" Grid.Column="1" Height="22" Width="345" HorizontalAlignment="Left" VerticalContentAlignment="Center"
Text="{Binding OutputPath, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding OutputPathTextBoxEnabled}" />
<Button x:Name="OutputPathBrowseButton" Grid.Row="1" Grid.Column="1" Height="22" Width="50" HorizontalAlignment="Right" Content="Browse"
Style="{DynamicResource CustomButtonStyle}"/>
IsEnabled="{Binding OutputPathBrowseButtonEnabled}" Style="{DynamicResource CustomButtonStyle}"/>
<Label x:Name="DriveLetterLabel" Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" Content="Drive Letter"/>
<ComboBox x:Name="DriveLetterComboBox" Grid.Row="2" Grid.Column="1" Height="22" Width="60" HorizontalAlignment="Left" Style="{DynamicResource CustomComboBoxStyle}">
<ComboBox x:Name="DriveLetterComboBox" Grid.Row="2" Grid.Column="1" Height="22" Width="60" HorizontalAlignment="Left"
ItemsSource="{Binding Drives}" SelectedItem="{Binding Path=CurrentDrive, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding DriveLetterComboBoxEnabled}" Style="{DynamicResource CustomComboBoxStyle}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Letter}" />
@@ -151,37 +163,48 @@
</ComboBox>
<Label x:Name="DriveSpeedLabel" Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" Content="Drive Speed"/>
<ComboBox x:Name="DriveSpeedComboBox" Grid.Row="3" Grid.Column="1" Height="22" Width="60" HorizontalAlignment="Left" Style="{DynamicResource CustomComboBoxStyle}" />
<ComboBox x:Name="DriveSpeedComboBox" Grid.Row="3" Grid.Column="1" Height="22" Width="60" HorizontalAlignment="Left"
ItemsSource="{Binding DriveSpeeds}" SelectedItem="{Binding Path=DriveSpeed, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding DriveSpeedComboBoxEnabled}" Style="{DynamicResource CustomComboBoxStyle}" />
<Label x:Name="DumpingProgramLabel" Grid.Row="4" Grid.Column="0" VerticalAlignment="Center" Content="Dumping Program"/>
<ComboBox x:Name="DumpingProgramComboBox" Grid.Row="4" Grid.Column="1" Height="22" Width="250" HorizontalAlignment="Left" Style="{DynamicResource CustomComboBoxStyle}" />
<ComboBox x:Name="DumpingProgramComboBox" Grid.Row="4" Grid.Column="1" Height="22" Width="250" HorizontalAlignment="Left"
ItemsSource="{Binding InternalPrograms}" SelectedItem="{Binding Path=CurrentProgram, Converter={StaticResource ElementConverter}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding DumpingProgramComboBoxEnabled}" Style="{DynamicResource CustomComboBoxStyle}" />
<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" />
<TextBox x:Name="ParametersTextBox" Grid.Row="5" Grid.Column="1" Height="22" Width="370" HorizontalAlignment="Left" VerticalContentAlignment="Center"
Text="{Binding Parameters, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding ParametersCheckBoxEnabled}"/>
<CheckBox x:Name="EnableParametersCheckBox" Grid.Row="5" Grid.Column="1" Height="22" HorizontalAlignment="Right"
IsChecked="{Binding ParametersCheckBoxEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding EnableParametersCheckBoxEnabled}"/>
</Grid>
</GroupBox>
<GroupBox Margin="5,5,5,5" HorizontalAlignment="Stretch" Header="Controls">
<UniformGrid Columns="4" Margin="5,5,5,5">
<Button x:Name="StartStopButton" Height="22" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" IsDefault="True" Content="Start Dumping"
IsEnabled="False" Style="{DynamicResource CustomButtonStyle}" />
<Button x:Name="StartStopButton" Height="22" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" IsDefault="True"
Content="{Binding StartStopButtonText, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding StartStopButtonEnabled}" Style="{DynamicResource CustomButtonStyle}" />
<Button x:Name="MediaScanButton" Height="22" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Scan for discs"
Style="{DynamicResource CustomButtonStyle}" />
IsEnabled="{Binding MediaScanButtonEnabled}" Style="{DynamicResource CustomButtonStyle}" />
<Button x:Name="UpdateVolumeLabel" Height="22" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Update Label"
Style="{DynamicResource CustomButtonStyle}" />
IsEnabled="{Binding UpdateVolumeLabelEnabled}" Style="{DynamicResource CustomButtonStyle}" />
<Button x:Name="CopyProtectScanButton" Height="22" Width="125" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Scan for protection"
Style="{DynamicResource CustomButtonStyle}" />
IsEnabled="{Binding CopyProtectScanButtonEnabled}" Style="{DynamicResource CustomButtonStyle}" />
</UniformGrid>
</GroupBox>
<GroupBox Margin="5,5,5,5" HorizontalAlignment="Stretch" Header="Status">
<UniformGrid Margin="5,5,5,5" Grid.ColumnSpan="2">
<TextBlock x:Name="StatusLabel" VerticalAlignment="Center" HorizontalAlignment="Center" Text="Waiting for media..." />
<TextBlock x:Name="StatusLabel" VerticalAlignment="Center" HorizontalAlignment="Center"
Text="{Binding Status, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</UniformGrid>
</GroupBox>
<Expander Margin="5,5 5 5" MaxHeight="300" HorizontalAlignment="Stretch" Header="Log Output" x:Name="LogPanel">
<Expander Margin="5,5 5 5" MaxHeight="300" HorizontalAlignment="Stretch" Header="Log Output" x:Name="LogPanel"
IsExpanded="{Binding LogPanelExpanded}">
<controls:LogOutput x:Name="LogOutput"/>
</Expander>
</StackPanel>

View File

@@ -1,5 +1,12 @@
using System;
using MPF.UI.Core.ViewModels;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using MPF.Core;
using MPF.Core.UI.ViewModels;
using SabreTools.RedumpLib.Data;
using WPFCustomMessageBox;
using WinForms = System.Windows.Forms;
namespace MPF.UI.Core.Windows
{
@@ -21,7 +28,408 @@ namespace MPF.UI.Core.Windows
protected override void OnContentRendered(EventArgs e)
{
base.OnContentRendered(e);
MainViewModel.Init(this);
// Disable buttons until we load fully
MainViewModel.StartStopButtonEnabled = false;
MainViewModel.MediaScanButtonEnabled = false;
MainViewModel.UpdateVolumeLabelEnabled = false;
MainViewModel.CopyProtectScanButtonEnabled = false;
// Add the click handlers to the UI
AddEventHandlers();
// Display the debug option in the menu, if necessary
if (MainViewModel.Options.ShowDebugViewMenuItem)
DebugViewMenuItem.Visibility = Visibility.Visible;
MainViewModel.Init(LogOutput.EnqueueLog, DisplayUserMessage, ShowDiscInformationWindow);
// Set the UI color scheme according to the options
if (MainViewModel.Options.EnableDarkMode)
EnableDarkMode();
else
EnableLightMode();
// Check for updates, if necessary
if (MainViewModel.Options.CheckForUpdatesOnStartup)
CheckForUpdates(showIfSame: false);
}
#region UI Functionality
/// <summary>
/// Add all event handlers
/// </summary>
public void AddEventHandlers()
{
// Menu Bar Click
AboutMenuItem.Click += AboutClick;
AppExitMenuItem.Click += AppExitClick;
CheckForUpdatesMenuItem.Click += CheckForUpdatesClick;
DebugViewMenuItem.Click += DebugViewClick;
OptionsMenuItem.Click += OptionsMenuItemClick;
// User Area Click
CopyProtectScanButton.Click += CopyProtectScanButtonClick;
EnableParametersCheckBox.Click += EnableParametersCheckBoxClick;
MediaScanButton.Click += MediaScanButtonClick;
UpdateVolumeLabel.Click += UpdateVolumeLabelClick;
OutputPathBrowseButton.Click += OutputPathBrowseButtonClick;
StartStopButton.Click += StartStopButtonClick;
// User Area SelectionChanged
SystemTypeComboBox.SelectionChanged += SystemTypeComboBoxSelectionChanged;
MediaTypeComboBox.SelectionChanged += MediaTypeComboBoxSelectionChanged;
DriveLetterComboBox.SelectionChanged += DriveLetterComboBoxSelectionChanged;
DriveSpeedComboBox.SelectionChanged += DriveSpeedComboBoxSelectionChanged;
DumpingProgramComboBox.SelectionChanged += DumpingProgramComboBoxSelectionChanged;
// User Area TextChanged
OutputPathTextBox.TextChanged += OutputPathTextBoxTextChanged;
}
/// <summary>
/// Browse for an output file path
/// </summary>
public void BrowseFile()
{
// Get the current path, if possible
string currentPath = MainViewModel.OutputPath;
if (string.IsNullOrWhiteSpace(currentPath))
currentPath = Path.Combine(MainViewModel.Options.DefaultOutputPath, "track.bin");
if (string.IsNullOrWhiteSpace(currentPath))
currentPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "track.bin");
// Get the full path
currentPath = Path.GetFullPath(currentPath);
// Get the directory
string directory = Path.GetDirectoryName(currentPath);
// Get the filename
string filename = Path.GetFileName(currentPath);
WinForms.FileDialog fileDialog = new WinForms.SaveFileDialog
{
FileName = filename,
InitialDirectory = directory,
};
WinForms.DialogResult result = fileDialog.ShowDialog();
if (result == WinForms.DialogResult.OK)
{
MainViewModel.OutputPath = fileDialog.FileName;
}
}
/// <summary>
/// Check for available updates
/// </summary>
/// <param name="showIfSame">True to show the box even if it's the same, false to only show if it's different</param>
public void CheckForUpdates(bool showIfSame)
{
(bool different, string message, string url) = MainViewModel.CheckForUpdates();
// If we have a new version, put it in the clipboard
if (different)
Clipboard.SetText(url);
if (showIfSame || different)
CustomMessageBox.Show(message, "Version Update Check", MessageBoxButton.OK, different ? MessageBoxImage.Exclamation : MessageBoxImage.Information);
}
/// <summary>
/// Display a user message using a CustomMessageBox
/// </summary>
/// <param name="title">Title to display to the user</param>
/// <param name="message">Message to display to the user</param>
/// <param name="optionCount">Number of options to display</param>
/// <param name="flag">true for inquiry, false otherwise</param>
/// <returns>true for positive, false for negative, null for neutral</returns>
public bool? DisplayUserMessage(string title, string message, int optionCount, bool flag)
{
// Set the correct button style
MessageBoxButton button;
switch (optionCount)
{
case 1:
button = MessageBoxButton.OK;
break;
case 2:
button = MessageBoxButton.YesNo;
break;
case 3:
button = MessageBoxButton.YesNoCancel;
break;
// This should not happen, but default to "OK"
default:
button = MessageBoxButton.OK;
break;
}
// Set the correct icon
MessageBoxImage image = flag ? MessageBoxImage.Question : MessageBoxImage.Exclamation;
// Display and get the result
MessageBoxResult result = CustomMessageBox.Show(this, message, title, button, image);
switch (result)
{
case MessageBoxResult.OK:
case MessageBoxResult.Yes:
return true;
case MessageBoxResult.No:
return false;
case MessageBoxResult.Cancel:
case MessageBoxResult.None:
default:
return null;
}
}
/// <summary>
/// Build a dummy SubmissionInfo and display it for testing
/// </summary>
public void ShowDebugDiscInfoWindow()
{
var submissionInfo = MainViewModel.CreateDebugSubmissionInfo();
var result = ShowDiscInformationWindow(submissionInfo);
InfoTool.ProcessSpecialFields(result.Item2);
}
/// <summary>
/// Show the disc information window
/// </summary>
/// <param name="submissionInfo">SubmissionInfo object to display and possibly change</param>
/// <returns>Dialog open result</returns>
public (bool?, SubmissionInfo) ShowDiscInformationWindow(SubmissionInfo submissionInfo)
{
if (MainViewModel.Options.ShowDiscEjectReminder)
CustomMessageBox.Show("It is now safe to eject the disc", "Eject", MessageBoxButton.OK, MessageBoxImage.Information);
var discInformationWindow = new DiscInformationWindow(MainViewModel.Options, submissionInfo)
{
Focusable = true,
Owner = this,
ShowActivated = true,
ShowInTaskbar = true,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
};
bool? result = discInformationWindow.ShowDialog();
// Copy back the submission info changes, if necessary
if (result == true)
submissionInfo = discInformationWindow.DiscInformationViewModel.SubmissionInfo.Clone() as SubmissionInfo;
return (result, submissionInfo);
}
/// <summary>
/// Show the Options window
/// </summary>
public void ShowOptionsWindow()
{
var optionsWindow = new OptionsWindow(MainViewModel.Options)
{
Focusable = true,
Owner = this,
ShowActivated = true,
ShowInTaskbar = true,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
};
optionsWindow.Closed += OnOptionsUpdated;
optionsWindow.Show();
}
/// <summary>
/// Recolor all UI elements for light mode
/// </summary>
private static void EnableLightMode()
{
var theme = new LightModeTheme();
theme.Apply();
}
/// <summary>
/// Recolor all UI elements for dark mode
/// </summary>
private static void EnableDarkMode()
{
var theme = new DarkModeTheme();
theme.Apply();
}
#endregion
#region Event Handlers
/// <summary>
/// Handler for OptionsWindow OnUpdated event
/// </summary>
public void OnOptionsUpdated(object sender, EventArgs e)
{
bool savedSettings = (sender as OptionsWindow)?.OptionsViewModel?.SavedSettings ?? false;
var options = (sender as OptionsWindow).OptionsViewModel.Options;
MainViewModel.UpdateOptions(savedSettings, options);
}
#region Menu Bar
/// <summary>
/// Handler for AboutMenuItem Click event
/// </summary>
public void AboutClick(object sender, RoutedEventArgs e)
{
string aboutText = MainViewModel.CreateAboutText();
CustomMessageBox.Show(aboutText, "About", MessageBoxButton.OK, MessageBoxImage.Information);
}
/// <summary>
/// Handler for AppExitMenuItem Click event
/// </summary>
public void AppExitClick(object sender, RoutedEventArgs e) =>
Application.Current.Shutdown();
/// <summary>
/// Handler for CheckForUpdatesMenuItem Click event
/// </summary>
public void CheckForUpdatesClick(object sender, RoutedEventArgs e)
=> CheckForUpdates(showIfSame: true);
/// <summary>
/// Handler for DebugViewMenuItem Click event
/// </summary>
public void DebugViewClick(object sender, RoutedEventArgs e) =>
ShowDebugDiscInfoWindow();
/// <summary>
/// Handler for OptionsMenuItem Click event
/// </summary>
public void OptionsMenuItemClick(object sender, RoutedEventArgs e) =>
ShowOptionsWindow();
#endregion
#region User Area
/// <summary>
/// Handler for CopyProtectScanButton Click event
/// </summary>
public async void CopyProtectScanButtonClick(object sender, RoutedEventArgs e)
{
(string output, string error) = await MainViewModel.ScanAndShowProtection();
if (!MainViewModel.LogPanelExpanded)
{
if (string.IsNullOrEmpty(error))
CustomMessageBox.Show(output, "Detected Protection(s)", MessageBoxButton.OK, MessageBoxImage.Information);
else
CustomMessageBox.Show("An exception occurred, see the log for details", "Error!", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
/// <summary>
/// Handler for DriveLetterComboBox SelectionChanged event
/// </summary>
public void DriveLetterComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (MainViewModel.CanExecuteSelectionChanged)
MainViewModel.InitializeUIValues(removeEventHandlers: true, rescanDrives: false);
}
/// <summary>
/// Handler for DriveSpeedComboBox SelectionChanged event
/// </summary>
public void DriveSpeedComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (MainViewModel.CanExecuteSelectionChanged)
MainViewModel.EnsureDiscInformation();
}
/// <summary>
/// Handler for DumpingProgramComboBox SelectionChanged event
/// </summary>
public void DumpingProgramComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (MainViewModel.CanExecuteSelectionChanged)
MainViewModel.ChangeDumpingProgram();
}
/// <summary>
/// Handler for EnableParametersCheckBox Click event
/// </summary>
public void EnableParametersCheckBoxClick(object sender, RoutedEventArgs e)
{
if (MainViewModel.CanExecuteSelectionChanged)
MainViewModel.ToggleParameters();
}
/// <summary>
/// Handler for MediaScanButton Click event
/// </summary>
public void MediaScanButtonClick(object sender, RoutedEventArgs e) =>
MainViewModel.InitializeUIValues(removeEventHandlers: true, rescanDrives: true);
/// <summary>
/// Handler for MediaTypeComboBox SelectionChanged event
/// </summary>
public void MediaTypeComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (MainViewModel.CanExecuteSelectionChanged)
MainViewModel.ChangeMediaType(e.RemovedItems, e.AddedItems);
}
/// <summary>
/// Handler for OutputPathBrowseButton Click event
/// </summary>
public void OutputPathBrowseButtonClick(object sender, RoutedEventArgs e)
{
BrowseFile();
MainViewModel.EnsureDiscInformation();
}
/// <summary>
/// Handler for OutputPathTextBox TextChanged event
/// </summary>
public void OutputPathTextBoxTextChanged(object sender, TextChangedEventArgs e)
{
if (MainViewModel.CanExecuteSelectionChanged)
MainViewModel.EnsureDiscInformation();
}
/// <summary>
/// Handler for StartStopButton Click event
/// </summary>
public void StartStopButtonClick(object sender, RoutedEventArgs e) =>
MainViewModel.ToggleStartStop();
/// <summary>
/// Handler for SystemTypeComboBox SelectionChanged event
/// </summary>
public void SystemTypeComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (MainViewModel.CanExecuteSelectionChanged)
MainViewModel.ChangeSystem();
}
/// <summary>
/// Handler for UpdateVolumeLabel Click event
/// </summary>
public void UpdateVolumeLabelClick(object sender, RoutedEventArgs e)
{
if (MainViewModel.CanExecuteSelectionChanged)
{
if (MainViewModel.Options.FastUpdateLabel)
MainViewModel.FastUpdateLabel(removeEventHandlers: true);
else
MainViewModel.InitializeUIValues(removeEventHandlers: true, rescanDrives: false);
}
}
#endregion
#endregion // Event Handlers
}
}

View File

@@ -10,6 +10,9 @@
WindowStartupLocation="CenterOwner" ResizeMode="CanMinimize" SizeToContent="Height"
BorderBrush="DarkGray" BorderThickness="2">
<Window.Resources>
<core:ElementConverter x:Key="ElementConverter" />
</Window.Resources>
<WindowChrome.WindowChrome>
<WindowChrome CaptionHeight="0" ResizeBorderThickness="0" />
</WindowChrome.WindowChrome>
@@ -99,26 +102,31 @@
</Grid.RowDefinitions>
<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" />
<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="..."
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" />
<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="..."
Style="{DynamicResource CustomButtonStyle}" />
<Label Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Redumper Path" />
<TextBox x:Name="RedumperPathTextBox" Grid.Row="2" Grid.Column="1" Height="22" HorizontalAlignment="Stretch" Text="{Binding Options.RedumperPath}" VerticalContentAlignment="Center" />
<TextBox x:Name="RedumperPathTextBox" Grid.Row="2" Grid.Column="1" Height="22" HorizontalAlignment="Stretch"
Text="{Binding Options.RedumperPath}" VerticalContentAlignment="Center" />
<Button x:Name="RedumperPathButton" Grid.Row="2" Grid.Column="2" Height="22" Width="22" Content="..."
Style="{DynamicResource CustomButtonStyle}" />
<Label Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Content="Default Dumping Program" />
<ComboBox x:Name="InternalProgramComboBox" Grid.Row="3" Grid.Column="1" Height="22" HorizontalAlignment="Stretch"
ItemsSource="{Binding InternalPrograms}" Style="{DynamicResource CustomComboBoxStyle}" />
ItemsSource="{Binding InternalPrograms}" SelectedItem="{Binding Options.InternalProgram, Converter={StaticResource ElementConverter}, Mode=TwoWay}"
Style="{DynamicResource CustomComboBoxStyle}" />
<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" />
<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="..."
Style="{DynamicResource CustomButtonStyle}" />
</Grid>
@@ -139,7 +147,9 @@
/>
<Label VerticalAlignment="Center" Content="Default System:" HorizontalAlignment="Right" />
<ComboBox x:Name="DefaultSystemComboBox" Height="22" Width="200" HorizontalAlignment="Left" ItemsSource="{Binding Systems}" SelectedIndex="0" Style="{DynamicResource CustomComboBoxStyle}">
<ComboBox x:Name="DefaultSystemComboBox" Height="22" Width="200" HorizontalAlignment="Left"
ItemsSource="{Binding Systems}" SelectedItem="{Binding Options.DefaultSystem, Converter={StaticResource ElementConverter}, Mode=TwoWay}"
SelectedIndex="0" Style="{DynamicResource CustomComboBoxStyle}">
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Style.Triggers>

View File

@@ -1,5 +1,11 @@
using MPF.Core.Data;
using MPF.UI.Core.ViewModels;
using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using MPF.Core.Data;
using MPF.Core.UI.ViewModels;
using WPFCustomMessageBox;
namespace MPF.UI.Core.Windows
{
@@ -19,13 +25,179 @@ namespace MPF.UI.Core.Windows
public OptionsWindow(Options options)
{
InitializeComponent();
DataContext = new OptionsViewModel(this, options);
DataContext = new OptionsViewModel(options);
#if NET6_0_OR_GREATER
this.SkipMediaTypeDetectionCheckBox.IsEnabled = false;
this.SkipMediaTypeDetectionCheckBox.IsChecked = false;
this.SkipMediaTypeDetectionCheckBox.ToolTip = "This feature is not enabled for .NET 6";
#endif
// Set initial value for binding
RedumpPasswordBox.Password = options.RedumpPassword;
// Add handlers
AaruPathButton.Click += BrowseForPathClick;
DiscImageCreatorPathButton.Click += BrowseForPathClick;
DefaultOutputPathButton.Click += BrowseForPathClick;
AcceptButton.Click += OnAcceptClick;
CancelButton.Click += OnCancelClick;
RedumpPasswordBox.PasswordChanged += OnPasswordChanged;
RedumpLoginTestButton.Click += OnRedumpTestClick;
}
#region UI Commands
/// <summary>
/// Browse and set a path based on the invoking button
/// </summary>
private void BrowseForPath(Window parent, 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(parent, 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 == System.Windows.Forms.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)
{
OptionsViewModel.Options[pathSettingName] = path;
TextBoxForPathSetting(parent, pathSettingName).Text = path;
}
else
{
CustomMessageBox.Show(
"Specified path doesn't exist!",
"Error",
MessageBoxButton.OK,
MessageBoxImage.Error
);
}
}
}
}
/// <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(Window parent, string name) =>
parent.FindName(name + "TextBox") as System.Windows.Controls.TextBox;
/// <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>
/// Test Redump credentials for validity
/// </summary>
#if NET48
private void ValidateRedumpCredentials()
#else
private async Task ValidateRedumpCredentials()
#endif
{
#if NET48
(bool? success, string message) = OptionsViewModel.TestRedumpLogin(RedumpUsernameTextBox.Text, RedumpPasswordBox.Password);
#else
(bool? success, string message) = await OptionsViewModel.TestRedumpLogin(RedumpUsernameTextBox.Text, RedumpPasswordBox.Password);
#endif
if (success == true)
CustomMessageBox.Show(this, message, "Success", MessageBoxButton.OK, MessageBoxImage.Information);
else if (success == false)
CustomMessageBox.Show(this, message, "Failure", MessageBoxButton.OK, MessageBoxImage.Error);
else
CustomMessageBox.Show(this, message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
#endregion
#region Event Handlers
/// <summary>
/// Handler for generic Click event
/// </summary>
private void BrowseForPathClick(object sender, EventArgs e) =>
BrowseForPath(this, sender as System.Windows.Controls.Button);
/// <summary>
/// Handler for AcceptButton Click event
/// </summary>
private void OnAcceptClick(object sender, EventArgs e)
{
OptionsViewModel.SavedSettings = true;
Close();
}
/// <summary>
/// Handler for CancelButtom Click event
/// </summary>
private void OnCancelClick(object sender, EventArgs e)
{
OptionsViewModel.SavedSettings = false;
Close();
}
/// <summary>
/// Handler for RedumpPasswordBox PasswordChanged event
/// </summary>
private void OnPasswordChanged(object sender, EventArgs e)
{
OptionsViewModel.Options.RedumpPassword = RedumpPasswordBox.Password;
}
/// <summary>
/// Test Redump credentials for validity
/// </summary>
#if NET48
private void OnRedumpTestClick(object sender, EventArgs e) => ValidateRedumpCredentials();
#else
private async void OnRedumpTestClick(object sender, EventArgs e) => await ValidateRedumpCredentials();
#endif
#endregion
}
}

14
MPF.sln
View File

@@ -7,8 +7,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MPF", "MPF\MPF.csproj", "{7
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MPF.Test", "MPF.Test\MPF.Test.csproj", "{7CC064D2-38AB-4A05-8519-28660DE4562A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MPF.Library", "MPF.Library\MPF.Library.csproj", "{51AB0928-13F9-44BF-A407-B6957A43A056}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MPF.Check", "MPF.Check\MPF.Check.csproj", "{8CFDE289-E171-4D49-A40D-5293265C1253}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4D1DCF5A-F0B0-4E81-A05B-F1A7D37C9D9D}"
@@ -25,8 +23,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
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
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MPF.UI.Core", "MPF.UI.Core\MPF.UI.Core.csproj", "{EA3768DB-694A-4653-82E4-9FF71B8963F3}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MPF", "MPF", "{4160167D-681D-480B-ABC6-06AC869E5769}"
@@ -45,10 +41,6 @@ Global
{7CC064D2-38AB-4A05-8519-28660DE4562A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7CC064D2-38AB-4A05-8519-28660DE4562A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7CC064D2-38AB-4A05-8519-28660DE4562A}.Release|Any CPU.Build.0 = Release|Any CPU
{51AB0928-13F9-44BF-A407-B6957A43A056}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{51AB0928-13F9-44BF-A407-B6957A43A056}.Debug|Any CPU.Build.0 = Debug|Any CPU
{51AB0928-13F9-44BF-A407-B6957A43A056}.Release|Any CPU.ActiveCfg = Release|Any CPU
{51AB0928-13F9-44BF-A407-B6957A43A056}.Release|Any CPU.Build.0 = Release|Any CPU
{8CFDE289-E171-4D49-A40D-5293265C1253}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{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
@@ -57,10 +49,6 @@ Global
{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
{EA3768DB-694A-4653-82E4-9FF71B8963F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EA3768DB-694A-4653-82E4-9FF71B8963F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EA3768DB-694A-4653-82E4-9FF71B8963F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -72,10 +60,8 @@ Global
GlobalSection(NestedProjects) = preSolution
{7B1B75EB-8940-466F-BD51-76471A57F9BE} = {4160167D-681D-480B-ABC6-06AC869E5769}
{7CC064D2-38AB-4A05-8519-28660DE4562A} = {4160167D-681D-480B-ABC6-06AC869E5769}
{51AB0928-13F9-44BF-A407-B6957A43A056} = {4160167D-681D-480B-ABC6-06AC869E5769}
{8CFDE289-E171-4D49-A40D-5293265C1253} = {4160167D-681D-480B-ABC6-06AC869E5769}
{70B1265D-FE49-472A-A83D-0B462152D37A} = {4160167D-681D-480B-ABC6-06AC869E5769}
{8A4254BD-552F-4238-B8EB-D59AACD768B9} = {4160167D-681D-480B-ABC6-06AC869E5769}
{EA3768DB-694A-4653-82E4-9FF71B8963F3} = {4160167D-681D-480B-ABC6-06AC869E5769}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution

View File

@@ -11,23 +11,16 @@
<Description>Frontend for various dumping programs</Description>
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
<Copyright>Copyright (c)2019-2023</Copyright>
<Version>2.6.6</Version>
<VersionPrefix>2.7.0</VersionPrefix>
<InternalsVisibleTo>MPF.Test</InternalsVisibleTo>
</PropertyGroup>
<PropertyGroup>
<NrtRevisionFormat>$(Version)-{chash:8}</NrtRevisionFormat>
<NrtResolveSimpleAttributes>true</NrtResolveSimpleAttributes>
<NrtShowRevision>false</NrtShowRevision>
</PropertyGroup>
<ItemGroup>
<Resource Include="Images\Icon.ico" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MPF.Core\MPF.Core.csproj" />
<ProjectReference Include="..\MPF.Library\MPF.Library.csproj" />
<ProjectReference Include="..\MPF.UI.Core\MPF.UI.Core.csproj" />
</ItemGroup>
@@ -40,10 +33,6 @@
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="SabreTools.RedumpLib" Version="1.1.1" />
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>

View File

@@ -19,7 +19,7 @@ MPF is the main, UI-centric application of the MPF suite. This program allows us
### System Requirements
- Windows 8.1 (x86 or x64) or newer
- Windows 8.1 (x64) or newer
- Users who wish to use MPF on Windows 7 need to disable strong name validation due to `Microsoft.Management.Infrastructure` being unsigned. Add the following registry keys (accurate at time of writing):
```
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\*,31bf3856ad364e35]
@@ -27,35 +27,28 @@ MPF is the main, UI-centric application of the MPF suite. This program allows us
```
- Alternatively, look at this [StackOverflow question](https://stackoverflow.com/questions/403731/strong-name-validation-failed) for more information.
- .NET Framework 4.8 .NET 6.0, or .NET 7.0 Runtimes
- .NET Framework 4.8, .NET 6.0, or .NET 7.0 Runtimes
- As much hard drive space as the amount of discs you will be dumping (20+ GB recommended)
Ensure that your operating system is as up-to-date as possible, since some features may rely on those updates.
### Support Limitations
.NET 6 has some known limitations that are documented in code and in some prior support tickets:
The main UI has some known limitations that are documented in code and in some prior support tickets:
- Windows-only due to reliance on WPF and Winforms
- MAUI is not a viable alternative due to lack of out-of-box support for Linux
- Avalonia is being heavily considered
- No media type detection due to lack of alternatives to IMAPI2
- Avalonia is being heavily considered as an alternative
### Build Instructions
To build for .NET Framework 4.8 (Windows only), ensure that the .NET Framework 4.8 SDK is installed and included in your PATH. Then, run the following commands from command prompt, Powershell, or Terminal:
To build for .NET Framework 4.8, .NET 6.0, or .NET 7.0 (all Windows only), ensure that the .NET 7.0 SDK (or later) is installed and included in your PATH. Then, run the following commands from command prompt, Powershell, or Terminal:
```
dotnet restore
msbuild MPF\MPF.csproj -property:TargetFramework=net48 -property:RuntimeIdentifiers=win7-x64
```
To build for .NET 6.0 or .NET 7.0 (Windows only), ensure that the .NET 7.0 SDK (or later) is installed and included in your PATH. Then, run the following commands from command prompt, Powershell, or Terminal:
```
dotnet build MPF\MPF.csproj --framework net6.0-windows --runtime [win-x64]
dotnet build MPF\MPF.csproj --framework [net48|net6.0-windows|net7.0-windows] --runtime win-x64 --self-contained
```
You may also run `publish-win.bat` (on Windows) or `publish-nix.sh` (on Linux) to build and package all variants MPF and MPF.Check at once. The Windows script additionally requires 7-zip commandline, Git for Windows, and .NET Framework 4.8 SDK to be installed and in PATH. The Linux script additionally requires `zip` and Git to be installed and in PATH.
## Media Preservation Frontend Checker (MPF.Check)
@@ -63,22 +56,15 @@ MPF.Check is a commandline-only program that allows users to generate submission
### System Requirements
- Windows 8.1 (x86 or x64) or newer, GNU/Linux x64, or OSX x64
- Windows 8.1 (x64) or newer, GNU/Linux x64, or OSX x64
- .NET Framework 4.8 (Windows or `mono` only), .NET 6.0, or .NET 7.0 Runtimes
### Build Instructions
To build for .NET Framework 4.8 (Windows only), ensure that the .NET Framework 4.8 SDK is installed and included in your PATH. Then, run the following commands from command prompt, Powershell, or Terminal:
To build for .NET Framework 4.8 (Windows only), .NET 6.0, and .NET 7.0 (both all supported OSes), ensure that the .NET 7.0 SDK (or later) is installed and included in your PATH. Then, run the following commands from command prompt, Powershell, Terminal, or shell:
```
dotnet restore
msbuild MPF.Check\MPF.Check.csproj -property:TargetFramework=net48 -property:RuntimeIdentifiers=win7-x64
```
To build for .NET 6.0 and .NET 7.0 (All supported OSes), ensure that the .NET 7.0 SDK (or later) is installed and included in your PATH. Then, run the following commands from command prompt, Powershell, Terminal, or shell:
```
dotnet build MPF.Check\MPF.Check.csproj --framework net6.0 --runtime [win-x64linux-x64|osx-x64]
dotnet build MPF.Check\MPF.Check.csproj --framework [net48|net6.0|net7.0] --runtime [win-x64|linux-x64|osx-x64] --self-contained
```
Choose one of `[win-x64|linux-x64|osx-x64]` depending on the machine you are targeting.

View File

@@ -1,5 +1,5 @@
# version format
version: 2.6.6-{build}
version: 2.7.0-{build}
# pull request template
pull_requests:
@@ -8,131 +8,119 @@ pull_requests:
# vm template
image: Visual Studio 2022
# environment variables
environment:
EnableNuGetPackageRestore: true
# install dependencies
install:
- ps: appveyor DownloadFile https://dist.nuget.org/win-x86-commandline/latest/nuget.exe
# pre-build script
before_build:
- nuget restore
# build step
build_script:
- dotnet restore
# .NET Framework 4.8 Debug
- msbuild MPF\MPF.csproj -target:Publish -property:TargetFramework=net48 -property:RuntimeIdentifiers=win7-x64
- msbuild MPF.Check\MPF.Check.csproj -target:Publish -property:TargetFramework=net48 -property:RuntimeIdentifiers=win7-x64
- dotnet publish MPF\MPF.csproj -f net48 -r win7-x64 -c Debug --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT%
- dotnet publish MPF.Check\MPF.Check.csproj -f net48 -r win7-x64 -c Debug --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT%
# # .NET Framework 4.8 Release
# - msbuild MPF\MPF.csproj -target:Publish -property:TargetFramework=net48 -property:Configuration=Release -property:RuntimeIdentifiers=win7-x64
# - msbuild MPF.Check\MPF.Check.csproj -target:Publish -property:TargetFramework=net48 -property:Configuration=Release -property:RuntimeIdentifiers=win7-x64
# .NET Framework 4.8 Release
- dotnet publish MPF\MPF.csproj -f net48 -r win7-x64 -c Release --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:DebugType=None -p:DebugSymbols=false
- dotnet publish MPF.Check\MPF.Check.csproj -f net48 -r win7-x64 -c Release --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:DebugType=None -p:DebugSymbols=false
# .NET 6.0 Debug
- dotnet publish MPF\MPF.csproj -f net6.0-windows -r win-x64 --self-contained true -p:PublishSingleFile=true
- dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r win-x64 --self-contained true -p:PublishSingleFile=true
- dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r linux-x64 --self-contained true -p:PublishSingleFile=true
- dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r osx-x64 --self-contained true -p:PublishSingleFile=true
- dotnet publish MPF\MPF.csproj -f net6.0-windows -r win-x64 -c Debug --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true
- dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r win-x64 -c Debug --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true
- dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r linux-x64 -c Debug --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true
- dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r osx-x64 -c Debug --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true
# # .NET 6.0 Release
# - dotnet publish MPF\MPF.csproj -f net6.0-windows -r win-x64 -c Release --self-contained true -p:PublishSingleFile=true
# - dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r win-x64 -c Release --self-contained true -p:PublishSingleFile=true
# - dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r linux-x64 -c Release --self-contained true -p:PublishSingleFile=true
# - dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r osx-x64 -c Release --self-contained true -p:PublishSingleFile=true
# .NET 6.0 Release
- dotnet publish MPF\MPF.csproj -f net6.0-windows -r win-x64 -c Release --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
- dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r win-x64 -c Release --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
- dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r linux-x64 -c Release --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
- dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r osx-x64 -c Release --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
# .NET 7.0 Debug
- dotnet publish MPF\MPF.csproj -f net7.0-windows -r win-x64 --self-contained true -p:PublishSingleFile=true
- dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r win-x64 --self-contained true -p:PublishSingleFile=true
- dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r linux-x64 --self-contained true -p:PublishSingleFile=true
- dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r osx-x64 --self-contained true -p:PublishSingleFile=true
- dotnet publish MPF\MPF.csproj -f net7.0-windows -r win-x64 -c Debug --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true
- dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r win-x64 -c Debug --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true
- dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r linux-x64 -c Debug --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true
- dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r osx-x64 -c Debug --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true
# # .NET 7.0 Release
# - dotnet publish MPF\MPF.csproj -f net7.0-windows -r win-x64 -c Release --self-contained true -p:PublishSingleFile=true
# - dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r win-x64 -c Release --self-contained true -p:PublishSingleFile=true
# - dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r linux-x64 -c Release --self-contained true -p:PublishSingleFile=true
# - dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r osx-x64 -c Release --self-contained true -p:PublishSingleFile=true
# .NET 7.0 Release
- dotnet publish MPF\MPF.csproj -f net7.0-windows -r win-x64 -c Release --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
- dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r win-x64 -c Release --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
- dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r linux-x64 -c Release --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
- dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r osx-x64 -c Release --self-contained true --version-suffix %APPVEYOR_REPO_COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
# post-build step
after_build:
# Aaru
- ps: appveyor DownloadFile https://github.com/aaru-dps/Aaru/releases/download/v5.3.2/aaru-5.3.2_windows_x64.zip
- 7z x aaru-5.3.2_windows_x64.zip -oMPF\bin\Debug\net48\publish\Programs\Aaru *
- 7z x aaru-5.3.2_windows_x64.zip -oMPF\bin\Debug\net48\win7-x64\publish\Programs\Aaru *
- 7z x aaru-5.3.2_windows_x64.zip -oMPF\bin\Debug\net6.0-windows\win-x64\publish\Programs\Aaru *
- 7z x aaru-5.3.2_windows_x64.zip -oMPF\bin\Debug\net7.0-windows\win-x64\publish\Programs\Aaru *
# - 7z x aaru-5.3.2_windows_x64.zip -oMPF\bin\Release\net48\publish\Programs\Aaru *
# - 7z x aaru-5.3.2_windows_x64.zip -oMPF\bin\Release\net48\win7-x64\publish\Programs\Aaru *
# - 7z x aaru-5.3.2_windows_x64.zip -oMPF\bin\Release\net6.0-windows\win-x64\publish\Programs\Aaru *
# - 7z x aaru-5.3.2_windows_x64.zip -oMPF\bin\Release\net7.0-windows\win-x64\publish\Programs\Aaru *
# DiscImageCreator
- ps: appveyor DownloadFile https://github.com/saramibreak/DiscImageCreator/files/11660558/DiscImageCreator_20230606.zip
- 7z e DiscImageCreator_20230606.zip -oMPF\bin\Debug\net48\publish\Programs\Creator Release_ANSI\*
- 7z e DiscImageCreator_20230606.zip -oMPF\bin\Debug\net48\win7-x64\publish\Programs\Creator Release_ANSI\*
- 7z e DiscImageCreator_20230606.zip -oMPF\bin\Debug\net6.0-windows\win-x64\publish\Programs\Creator Release_ANSI\*
- 7z e DiscImageCreator_20230606.zip -oMPF\bin\Debug\net7.0-windows\win-x64\publish\Programs\Creator Release_ANSI\*
# - 7z e DiscImageCreator_20230606.zip -oMPF\bin\Release\net48\publish\Programs\Creator Release_ANSI\*
# - 7z e DiscImageCreator_20230606.zip -oMPF\bin\Release\net48\win7-x64\publish\Programs\Creator Release_ANSI\*
# - 7z e DiscImageCreator_20230606.zip -oMPF\bin\Release\net6.0-windows\win-x64\publish\Programs\Creator Release_ANSI\*
# - 7z e DiscImageCreator_20230606.zip -oMPF\bin\Release\net7.0-windows\win-x64\publish\Programs\Creator Release_ANSI\*
# Redumper
- ps: appveyor DownloadFile https://github.com/superg/redumper/releases/download/build_221/redumper-2023.10.02_build221-win64.zip
- 7z e redumper-2023.10.02_build221-win64.zip -oMPF\bin\Debug\net48\publish\Programs\Redumper redumper-2023.10.02_build221-win64\bin\*
- 7z e redumper-2023.10.02_build221-win64.zip -oMPF\bin\Debug\net48\win7-x64\publish\Programs\Redumper redumper-2023.10.02_build221-win64\bin\*
- 7z e redumper-2023.10.02_build221-win64.zip -oMPF\bin\Debug\net6.0-windows\win-x64\publish\Programs\Redumper redumper-2023.10.02_build221-win64\bin\*
- 7z e redumper-2023.10.02_build221-win64.zip -oMPF\bin\Debug\net7.0-windows\win-x64\publish\Programs\Redumper redumper-2023.10.02_build221-win64\bin\*
# - 7z e redumper-2023.10.02_build221-win64.zip -oMPF\bin\Release\net48\publish\Programs\Redumper redumper-2023.10.02_build221-win64\bin\*
# - 7z e redumper-2023.10.02_build221-win64.zip -oMPF\bin\Release\net48\win7-x64\publish\Programs\Redumper redumper-2023.10.02_build221-win64\bin\*
# - 7z e redumper-2023.10.02_build221-win64.zip -oMPF\bin\Release\net6.0-windows\win-x64\publish\Programs\Redumper redumper-2023.10.02_build221-win64\bin\*
# - 7z e redumper-2023.10.02_build221-win64.zip -oMPF\bin\Release\net7.0-windows\win-x64\publish\Programs\Redumper redumper-2023.10.02_build221-win64\bin\*
# Create MPF Debug archives
- cd %APPVEYOR_BUILD_FOLDER%\MPF\bin\Debug\net48\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF-dbg_net48.zip *
- cd %APPVEYOR_BUILD_FOLDER%\MPF\bin\Debug\net48\win7-x64\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF_%APPVEYOR_BUILD_NUMBER%_net48_debug.zip *
- cd %APPVEYOR_BUILD_FOLDER%\MPF\bin\Debug\net6.0-windows\win-x64\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF-dbg_net6.0_win-x64.zip *
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF_%APPVEYOR_BUILD_NUMBER%_net6.0_win-x64_debug.zip *
- cd %APPVEYOR_BUILD_FOLDER%\MPF\bin\Debug\net7.0-windows\win-x64\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF-dbg_net7.0_win-x64.zip *
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF_%APPVEYOR_BUILD_NUMBER%_net7.0_win-x64_debug.zip *
# # Create MPF Release archives
# - cd %APPVEYOR_BUILD_FOLDER%\MPF\bin\Release\net48\publish\
# - 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF_net48.zip *
# - cd %APPVEYOR_BUILD_FOLDER%\MPF\bin\Release\net48\win7-x64\publish\
# - 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF_%APPVEYOR_BUILD_NUMBER%_net48_release.zip *
# - cd %APPVEYOR_BUILD_FOLDER%\MPF\bin\Release\net6.0-windows\win-x64\publish\
# - 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF_net6.0_win-x64.zip *
# - 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF_%APPVEYOR_BUILD_NUMBER%_net6.0_win-x64_release.zip *
# - cd %APPVEYOR_BUILD_FOLDER%\MPF\bin\Release\net7.0-windows\win-x64\publish\
# - 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF_net7.0_win-x64.zip *
# - 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF_%APPVEYOR_BUILD_NUMBER%_net7.0_win-x64_release.zip *
# Create MPF.Check Debug archives
- cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Debug\net48\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check-dbg_net48.zip *
- cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Debug\net48\win7-x64\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_%APPVEYOR_BUILD_NUMBER%_net48_debug.zip *
- cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Debug\net6.0\win-x64\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check-dbg_net6.0_win-x64.zip *
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_%APPVEYOR_BUILD_NUMBER%_net6.0_win-x64_debug.zip *
- cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Debug\net6.0\linux-x64\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check-dbg_net6.0_linux-x64.zip *
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_%APPVEYOR_BUILD_NUMBER%_net6.0_linux-x64_debug.zip *
- cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Debug\net6.0\osx-x64\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check-dbg_net6.0_osx-x64.zip *
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_%APPVEYOR_BUILD_NUMBER%_net6.0_osx-x64_debug.zip *
- cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Debug\net7.0\win-x64\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check-dbg_net7.0_win-x64.zip *
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_%APPVEYOR_BUILD_NUMBER%_net7.0_win-x64_debug.zip *
- cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Debug\net7.0\linux-x64\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check-dbg_net7.0_linux-x64.zip *
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_%APPVEYOR_BUILD_NUMBER%_net7.0_linux-x64_debug.zip *
- cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Debug\net7.0\osx-x64\publish\
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check-dbg_net7.0_osx-x64.zip *
- 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_%APPVEYOR_BUILD_NUMBER%_net7.0_osx-x64_debug.zip *
# # Create MPF.Check Release archives
# - cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Release\net48\publish\
# - 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_net48.zip *
# - cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Release\net48\win7-x64\publish\
# - 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_%APPVEYOR_BUILD_NUMBER%_net48_release.zip *
# - cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Release\net6.0\win-x64\publish\
# - 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_net6.0_win-x64.zip *
# - 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_%APPVEYOR_BUILD_NUMBER%_net6.0_win-x64_release.zip *
# - cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Release\net6.0\linux-x64\publish\
# - 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_net6.0_linux-x64.zip *
# - 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_%APPVEYOR_BUILD_NUMBER%_net6.0_linux-x64_release.zip *
# - cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Release\net6.0\osx-x64\publish\
# - 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_net6.0_osx-x64.zip *
# - 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_%APPVEYOR_BUILD_NUMBER%_net6.0_osx-x64_release.zip *
# - cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Release\net7.0\win-x64\publish\
# - 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_net7.0_win-x64.zip *
# - 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_%APPVEYOR_BUILD_NUMBER%_net7.0_win-x64_release.zip *
# - cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Release\net7.0\linux-x64\publish\
# - 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_net7.0_linux-x64.zip *
# - 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_%APPVEYOR_BUILD_NUMBER%_net7.0_linux-x64_release.zip *
# - cd %APPVEYOR_BUILD_FOLDER%\MPF.Check\bin\Release\net7.0\osx-x64\publish\
# - 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_net7.0_osx-x64.zip *
# - 7z a -tzip %APPVEYOR_BUILD_FOLDER%\MPF.Check_%APPVEYOR_BUILD_NUMBER%_net7.0_osx-x64_release.zip *
# success/failure tracking
on_success:
@@ -144,46 +132,46 @@ on_failure:
# artifact linking
artifacts:
- path: MPF-dbg_net48.zip
- path: MPF_%APPVEYOR_BUILD_NUMBER%_net48_debug.zip
name: MPF (.NET Framework 4.8, Debug)
- path: MPF-dbg_net6.0_win-x64.zip
- path: MPF_%APPVEYOR_BUILD_NUMBER%_net6.0_win-x64_debug.zip
name: MPF (.NET 6.0, Debug, Windows x64)
- path: MPF-dbg_net7.0_win-x64.zip
- path: MPF_%APPVEYOR_BUILD_NUMBER%_net7.0_win-x64_debug.zip
name: MPF (.NET 7.0, Debug, Windows x64)
# - path: MPF_net48.zip
# - path: MPF_%APPVEYOR_BUILD_NUMBER%_net48_release.zip
# name: MPF (.NET Framework 4.8, Release)
# - path: MPF_net6.0_win-x64.zip
# - path: MPF_%APPVEYOR_BUILD_NUMBER%_net6.0_win-x64_release.zip
# name: MPF (.NET 6.0, Release, Windows x64)
# - path: MPF_net7.0_win-x64.zip
# - path: MPF_%APPVEYOR_BUILD_NUMBER%_net7.0_win-x64_release.zip
# name: MPF (.NET 7.0, Release, Windows x64)
- path: MPF.Check-dbg_net48.zip
- path: MPF.Check_%APPVEYOR_BUILD_NUMBER%_net48_debug.zip
name: MPF Check (.NET Framework 4.8, Debug)
- path: MPF.Check-dbg_net6.0_win-x64.zip
- path: MPF.Check_%APPVEYOR_BUILD_NUMBER%_net6.0_win-x64_debug.zip
name: MPF.Check (.NET 6.0, Debug, Windows x64)
- path: MPF.Check-dbg_net6.0_linux-x64.zip
- path: MPF.Check_%APPVEYOR_BUILD_NUMBER%_net6.0_linux-x64_debug.zip
name: MPF.Check (.NET 6.0, Debug, Linux x64)
- path: MPF.Check-dbg_net6.0_osx-x64.zip
- path: MPF.Check_%APPVEYOR_BUILD_NUMBER%_net6.0_osx-x64_debug.zip
name: MPF.Check (.NET 6.0, Debug, OSX x64)
- path: MPF.Check-dbg_net7.0_win-x64.zip
- path: MPF.Check_%APPVEYOR_BUILD_NUMBER%_net7.0_win-x64_debug.zip
name: MPF.Check (.NET 7.0, Debug, Windows x64)
- path: MPF.Check-dbg_net7.0_linux-x64.zip
- path: MPF.Check_%APPVEYOR_BUILD_NUMBER%_net7.0_linux-x64_debug.zip
name: MPF.Check (.NET 7.0, Debug, Linux x64)
- path: MPF.Check-dbg_net7.0_osx-x64.zip
- path: MPF.Check_%APPVEYOR_BUILD_NUMBER%_net7.0_osx-x64_debug.zip
name: MPF.Check (.NET 7.0, Debug, OSX x64)
# - path: MPF.Check_net48.zip
# - path: MPF.Check_%APPVEYOR_BUILD_NUMBER%_net48_release.zip
# name: MPF Check (.NET Framework 4.8, Release)
# - path: MPF.Check_net6.0_win-x64.zip
# - path: MPF.Check_%APPVEYOR_BUILD_NUMBER%_net6.0_win-x64_release.zip
# name: MPF.Check (.NET 6.0, Release, Windows x64)
# - path: MPF.Check_net6.0_linux-x64.zip
# - path: MPF.Check_%APPVEYOR_BUILD_NUMBER%_net6.0_linux-x64_release.zip
# name: MPF.Check (.NET 6.0, Release, Linux x64)
# - path: MPF.Check_net6.0_osx-x64.zip
# - path: MPF.Check_%APPVEYOR_BUILD_NUMBER%_net6.0_osx-x64_release.zip
# name: MPF.Check (.NET 6.0, Release, OSX x64)
# - path: MPF.Check_net7.0_win-x64.zip
# - path: MPF.Check_%APPVEYOR_BUILD_NUMBER%_net7.0_win-x64_release.zip
# name: MPF.Check (.NET 7.0, Release, Windows x64)
# - path: MPF.Check_net7.0_linux-x64.zip
# - path: MPF.Check_%APPVEYOR_BUILD_NUMBER%_net7.0_linux-x64_release.zip
# name: MPF.Check (.NET 7.0, Release, Linux x64)
# - path: MPF.Check_net7.0_osx-x64.zip
# - path: MPF.Check_%APPVEYOR_BUILD_NUMBER%_net7.0_osx-x64_release.zip
# name: MPF.Check (.NET 7.0, Release, OSX x64)

View File

@@ -3,6 +3,7 @@
# This batch file assumes the following:
# - .NET 7.0 (or newer) SDK is installed and in PATH
# - zip is installed and in PATH
# - Git is installed and in PATH
# - The relevant commandline programs are already downloaded
# and put into their respective folders
#
@@ -15,74 +16,77 @@
# Set the current directory as a variable
BUILD_FOLDER=$PWD
# Set the current commit hash
COMMIT=`git log --pretty=%H -1`
# Restore Nuget packages for all builds
echo "Restoring Nuget packages"
dotnet restore
# .NET 6.0 Debug
echo "Building .NET 6.0 debug"
#dotnet publish MPF/MPF.csproj -f net6.0-windows -r win-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check/MPF.Check.csproj -f net6.0 -r win-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check/MPF.Check.csproj -f net6.0 -r linux-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check/MPF.Check.csproj -f net6.0 -r osx-x64 --self-contained true -p:PublishSingleFile=true
#dotnet publish MPF/MPF.csproj -f net6.0-windows -r win-x64 -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
dotnet publish MPF.Check/MPF.Check.csproj -f net6.0 -r win-x64 -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
dotnet publish MPF.Check/MPF.Check.csproj -f net6.0 -r linux-x64 -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
dotnet publish MPF.Check/MPF.Check.csproj -f net6.0 -r osx-x64 -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
# .NET 6.0 Release
echo "Building .NET 6.0 release"
#dotnet publish MPF/MPF.csproj -f net6.0-windows -r win-x64 -c Release --self-contained true -p:PublishSingleFile=true -p:PublishTrimmed=true
dotnet publish MPF.Check/MPF.Check.csproj -f net6.0 -r win-x64 -c Release --self-contained true -p:PublishSingleFile=true -p:PublishTrimmed=true
dotnet publish MPF.Check/MPF.Check.csproj -f net6.0 -r linux-x64 -c Release --self-contained true -p:PublishSingleFile=true -p:PublishTrimmed=true
dotnet publish MPF.Check/MPF.Check.csproj -f net6.0 -r osx-x64 -c Release --self-contained true -p:PublishSingleFile=true -p:PublishTrimmed=true
#dotnet publish MPF/MPF.csproj -f net6.0-windows -r win-x64 -c Release --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true -p:PublishTrimmed=true -p:DebugType=None -p:DebugSymbols=false
dotnet publish MPF.Check/MPF.Check.csproj -f net6.0 -r win-x64 -c Release --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true -p:PublishTrimmed=true -p:DebugType=None -p:DebugSymbols=false
dotnet publish MPF.Check/MPF.Check.csproj -f net6.0 -r linux-x64 -c Release --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true -p:PublishTrimmed=true -p:DebugType=None -p:DebugSymbols=false
dotnet publish MPF.Check/MPF.Check.csproj -f net6.0 -r osx-x64 -c Release --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true -p:PublishTrimmed=true -p:DebugType=None -p:DebugSymbols=false
# .NET 7.0 Debug
echo "Building .NET 7.0 debug"
#dotnet publish MPF/MPF.csproj -f net7.0-windows -r win-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check/MPF.Check.csproj -f net7.0 -r win-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check/MPF.Check.csproj -f net7.0 -r linux-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check/MPF.Check.csproj -f net7.0 -r osx-x64 --self-contained true -p:PublishSingleFile=true
#dotnet publish MPF/MPF.csproj -f net7.0-windows -r win-x64 -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
dotnet publish MPF.Check/MPF.Check.csproj -f net7.0 -r win-x64 -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
dotnet publish MPF.Check/MPF.Check.csproj -f net7.0 -r linux-x64 -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
dotnet publish MPF.Check/MPF.Check.csproj -f net7.0 -r osx-x64 -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
# .NET 7.0 Release
echo "Building .NET 7.0 release"
#dotnet publish MPF/MPF.csproj -f net7.0-windows -r win-x64 -c Release --self-contained true -p:PublishSingleFile=true -p:PublishTrimmed=true
dotnet publish MPF.Check/MPF.Check.csproj -f net7.0 -r win-x64 -c Release --self-contained true -p:PublishSingleFile=true -p:PublishTrimmed=true
dotnet publish MPF.Check/MPF.Check.csproj -f net7.0 -r linux-x64 -c Release --self-contained true -p:PublishSingleFile=true -p:PublishTrimmed=true
dotnet publish MPF.Check/MPF.Check.csproj -f net7.0 -r osx-x64 -c Release --self-contained true -p:PublishSingleFile=true -p:PublishTrimmed=true
#dotnet publish MPF/MPF.csproj -f net7.0-windows -r win-x64 -c Release --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true -p:PublishTrimmed=true -p:DebugType=None -p:DebugSymbols=false
dotnet publish MPF.Check/MPF.Check.csproj -f net7.0 -r win-x64 -c Release --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true -p:PublishTrimmed=true -p:DebugType=None -p:DebugSymbols=false
dotnet publish MPF.Check/MPF.Check.csproj -f net7.0 -r linux-x64 -c Release --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true -p:PublishTrimmed=true -p:DebugType=None -p:DebugSymbols=false
dotnet publish MPF.Check/MPF.Check.csproj -f net7.0 -r osx-x64 -c Release --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true -p:PublishTrimmed=true -p:DebugType=None -p:DebugSymbols=false
# Create MPF Debug archives
#cd $BUILD_FOLDER/MPF/bin/Debug/net6.0-windows/win-x64/publish/
#zip -r $BUILD_FOLDER/MPF-dbg_net6.0_win-x64.zip .
#zip -r $BUILD_FOLDER/MPF_net6.0_win-x64_debug.zip .
#cd $BUILD_FOLDER/MPF/bin/Debug/net7.0-windows/win-x64/publish/
#zip -r $BUILD_FOLDER/MPF-dbg_net7.0_win-x64.zip .
#zip -r $BUILD_FOLDER/MPF_net7.0_win-x64_debug.zip .
# Create MPF Release archives
#cd $BUILD_FOLDER/MPF/bin/Release/net6.0-windows/win-x64/publish/
#zip -r $BUILD_FOLDER/MPF_net6.0_win-x64.zip .
#zip -r $BUILD_FOLDER/MPF_net6.0_win-x64_release.zip .
#cd $BUILD_FOLDER/MPF/bin/Release/net7.0-windows/win-x64/publish/
#zip -r $BUILD_FOLDER/MPF_net7.0_win-x64.zip .
#zip -r $BUILD_FOLDER/MPF_net7.0_win-x64_release.zip .
# Create MPF.Check Debug archives
cd $BUILD_FOLDER/MPF.Check/bin/Debug/net6.0/win-x64/publish/
zip -r $BUILD_FOLDER/MPF.Check-dbg_net6.0_win-x64.zip .
zip -r $BUILD_FOLDER/MPF.Check_net6.0_win-x64_debug.zip .
cd $BUILD_FOLDER/MPF.Check/bin/Debug/net6.0/linux-x64/publish/
zip -r $BUILD_FOLDER/MPF.Check-dbg_net6.0_linux-x64.zip .
zip -r $BUILD_FOLDER/MPF.Check_net6.0_linux-x64_debug.zip .
cd $BUILD_FOLDER/MPF.Check/bin/Debug/net6.0/osx-x64/publish/
zip -r $BUILD_FOLDER/MPF.Check-dbg_net6.0_osx-x64.zip .
zip -r $BUILD_FOLDER/MPF.Check_net6.0_osx-x64_debug.zip .
cd $BUILD_FOLDER/MPF.Check/bin/Debug/net7.0/win-x64/publish/
zip -r $BUILD_FOLDER/MPF.Check-dbg_net7.0_win-x64.zip .
zip -r $BUILD_FOLDER/MPF.Check_net7.0_win-x64_debug.zip .
cd $BUILD_FOLDER/MPF.Check/bin/Debug/net7.0/linux-x64/publish/
zip -r $BUILD_FOLDER/MPF.Check-dbg_net7.0_linux-x64.zip .
zip -r $BUILD_FOLDER/MPF.Check_net7.0_linux-x64_debug.zip .
cd $BUILD_FOLDER/MPF.Check/bin/Debug/net7.0/osx-x64/publish/
zip -r $BUILD_FOLDER/MPF.Check-dbg_net7.0_osx-x64.zip .
zip -r $BUILD_FOLDER/MPF.Check_net7.0_osx-x64_debug.zip .
# Create MPF.Check Release archives
cd $BUILD_FOLDER/MPF.Check/bin/Release/net6.0/win-x64/publish/
zip -r $BUILD_FOLDER/MPF.Check_net6.0_win-x64.zip .
zip -r $BUILD_FOLDER/MPF.Check_net6.0_win-x64_release.zip .
cd $BUILD_FOLDER/MPF.Check/bin/Release/net6.0/linux-x64/publish/
zip -r $BUILD_FOLDER/MPF.Check_net6.0_linux-x64.zip .
zip -r $BUILD_FOLDER/MPF.Check_net6.0_linux-x64_release.zip .
cd $BUILD_FOLDER/MPF.Check/bin/Release/net6.0/osx-x64/publish/
zip -r $BUILD_FOLDER/MPF.Check_net6.0_osx-x64.zip .
zip -r $BUILD_FOLDER/MPF.Check_net6.0_osx-x64_release.zip .
cd $BUILD_FOLDER/MPF.Check/bin/Release/net7.0/win-x64/publish/
zip -r $BUILD_FOLDER/MPF.Check_net7.0_win-x64.zip .
zip -r $BUILD_FOLDER/MPF.Check_net7.0_win-x64_release.zip .
cd $BUILD_FOLDER/MPF.Check/bin/Release/net7.0/linux-x64/publish/
zip -r $BUILD_FOLDER/MPF.Check_net7.0_linux-x64.zip .
zip -r $BUILD_FOLDER/MPF.Check_net7.0_linux-x64_release.zip .
cd $BUILD_FOLDER/MPF.Check/bin/Release/net7.0/osx-x64/publish/
zip -r $BUILD_FOLDER/MPF.Check_net7.0_osx-x64.zip .
zip -r $BUILD_FOLDER/MPF.Check_net7.0_osx-x64_release.zip .

View File

@@ -4,6 +4,7 @@ REM This batch file assumes the following:
REM - .NET Framework 4.8 SDK is installed and in PATH
REM - .NET 7.0 (or newer) SDK is installed and in PATH
REM - 7-zip commandline (7z.exe) is installed and in PATH
REM - Git for Windows is installed and in PATH
REM - The relevant commandline programs are already downloaded
REM and put into their respective folders
REM
@@ -13,92 +14,95 @@ REM in an unpredictable way and result in an incomplete output.
REM Set the current directory as a variable
set BUILD_FOLDER=%~dp0
REM Set the current commit hash
for /f %%i in ('git log --pretty^=%%H -1') do set COMMIT=%%i
REM Restore Nuget packages for all builds
echo Restoring Nuget packages
dotnet restore
REM .NET Framework 4.8 Debug
echo Building .NET Framework 4.8 debug
msbuild MPF\MPF.csproj -target:Publish -property:TargetFramework=net48 -property:RuntimeIdentifiers=win7-x64
msbuild MPF.Check\MPF.Check.csproj -target:Publish -property:TargetFramework=net48 -property:RuntimeIdentifiers=win7-x64
dotnet publish MPF\MPF.csproj -f net48 -r win7-x64 -c Debug --self-contained true --version-suffix %COMMIT%
dotnet publish MPF.Check\MPF.Check.csproj -f net48 -r win7-x64 -c Debug --self-contained true --version-suffix %COMMIT%
REM .NET Framework 4.8 Release
echo Building .NET Framework 4.8 release
msbuild MPF\MPF.csproj -target:Publish -property:TargetFramework=net48 -property:Configuration=Release -property:RuntimeIdentifiers=win7-x64
msbuild MPF.Check\MPF.Check.csproj -target:Publish -property:TargetFramework=net48 -property:Configuration=Release -property:RuntimeIdentifiers=win7-x64
dotnet publish MPF\MPF.csproj -f net48 -r win7-x64 -c Release --self-contained true --version-suffix %COMMIT% -p:DebugType=None -p:DebugSymbols=false
dotnet publish MPF.Check\MPF.Check.csproj -f net48 -r win7-x64 -c Release --self-contained true --version-suffix %COMMIT% -p:DebugType=None -p:DebugSymbols=false
REM .NET 6.0 Debug
echo Building .NET 6.0 debug
dotnet publish MPF\MPF.csproj -f net6.0-windows -r win-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r win-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r linux-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r osx-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF\MPF.csproj -f net6.0-windows -r win-x64 -c Debug --self-contained true --version-suffix %COMMIT% -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r win-x64 -c Debug --self-contained true --version-suffix %COMMIT% -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r linux-x64 -c Debug --self-contained true --version-suffix %COMMIT% -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r osx-x64 -c Debug --self-contained true --version-suffix %COMMIT% -p:PublishSingleFile=true
REM .NET 6.0 Release
echo Building .NET 6.0 release
dotnet publish MPF\MPF.csproj -f net6.0-windows -r win-x64 -c Release --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r win-x64 -c Release --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r linux-x64 -c Release --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r osx-x64 -c Release --self-contained true -p:PublishSingleFile=true
dotnet publish MPF\MPF.csproj -f net6.0-windows -r win-x64 -c Release --self-contained true --version-suffix %COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r win-x64 -c Release --self-contained true --version-suffix %COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r linux-x64 -c Release --self-contained true --version-suffix %COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
dotnet publish MPF.Check\MPF.Check.csproj -f net6.0 -r osx-x64 -c Release --self-contained true --version-suffix %COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
REM .NET 7.0 Debug
echo Building .NET 7.0 debug
dotnet publish MPF\MPF.csproj -f net7.0-windows -r win-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r win-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r linux-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r osx-x64 --self-contained true -p:PublishSingleFile=true
dotnet publish MPF\MPF.csproj -f net7.0-windows -r win-x64 -c Debug --self-contained true --version-suffix %COMMIT% -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r win-x64 -c Debug --self-contained true --version-suffix %COMMIT% -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r linux-x64 -c Debug --self-contained true --version-suffix %COMMIT% -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r osx-x64 -c Debug --self-contained true --version-suffix %COMMIT% -p:PublishSingleFile=true
REM .NET 7.0 Release
echo Building .NET 7.0 release
dotnet publish MPF\MPF.csproj -f net7.0-windows -r win-x64 -c Release --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r win-x64 -c Release --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r linux-x64 -c Release --self-contained true -p:PublishSingleFile=true
dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r osx-x64 -c Release --self-contained true -p:PublishSingleFile=true
dotnet publish MPF\MPF.csproj -f net7.0-windows -r win-x64 -c Release --self-contained true --version-suffix %COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r win-x64 -c Release --self-contained true --version-suffix %COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r linux-x64 -c Release --self-contained true --version-suffix %COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
dotnet publish MPF.Check\MPF.Check.csproj -f net7.0 -r osx-x64 -c Release --self-contained true --version-suffix %COMMIT% -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
REM Create MPF Debug archives
cd %BUILD_FOLDER%\MPF\bin\Debug\net48\publish\
7z a -tzip %BUILD_FOLDER%\MPF-dbg_net48.zip *
cd %BUILD_FOLDER%\MPF\bin\Debug\net48\win7-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF_net48_debug.zip *
cd %BUILD_FOLDER%\MPF\bin\Debug\net6.0-windows\win-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF-dbg_net6.0_win-x64.zip *
7z a -tzip %BUILD_FOLDER%\MPF_net6.0_win-x64_debug.zip *
cd %BUILD_FOLDER%\MPF\bin\Debug\net7.0-windows\win-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF-dbg_net7.0_win-x64.zip *
7z a -tzip %BUILD_FOLDER%\MPF_net7.0_win-x64_debug.zip *
REM Create MPF Release archives
cd %BUILD_FOLDER%\MPF\bin\Release\net48\publish\
7z a -tzip %BUILD_FOLDER%\MPF_net48.zip *
cd %BUILD_FOLDER%\MPF\bin\Release\net48\win7-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF_net48_release.zip *
cd %BUILD_FOLDER%\MPF\bin\Release\net6.0-windows\win-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF_net6.0_win-x64.zip *
7z a -tzip %BUILD_FOLDER%\MPF_net6.0_win-x64_release.zip *
cd %BUILD_FOLDER%\MPF\bin\Release\net7.0-windows\win-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF_net7.0_win-x64.zip *
7z a -tzip %BUILD_FOLDER%\MPF_net7.0_win-x64_release.zip *
REM Create MPF.Check Debug archives
cd %BUILD_FOLDER%\MPF.Check\bin\Debug\net48\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check-dbg_net48.zip *
cd %BUILD_FOLDER%\MPF.Check\bin\Debug\net48\win7-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check_net48_debug.zip *
cd %BUILD_FOLDER%\MPF.Check\bin\Debug\net6.0\win-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check-dbg_net6.0_win-x64.zip *
7z a -tzip %BUILD_FOLDER%\MPF.Check_net6.0_win-x64_debug.zip *
cd %BUILD_FOLDER%\MPF.Check\bin\Debug\net6.0\linux-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check-dbg_net6.0_linux-x64.zip *
7z a -tzip %BUILD_FOLDER%\MPF.Check_net6.0_linux-x64_debug.zip *
cd %BUILD_FOLDER%\MPF.Check\bin\Debug\net6.0\osx-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check-dbg_net6.0_osx-x64.zip *
7z a -tzip %BUILD_FOLDER%\MPF.Check_net6.0_osx-x64_debug.zip *
cd %BUILD_FOLDER%\MPF.Check\bin\Debug\net7.0\win-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check-dbg_net7.0_win-x64.zip *
7z a -tzip %BUILD_FOLDER%\MPF.Check_net7.0_win-x64_debug.zip *
cd %BUILD_FOLDER%\MPF.Check\bin\Debug\net7.0\linux-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check-dbg_net7.0_linux-x64.zip *
7z a -tzip %BUILD_FOLDER%\MPF.Check_net7.0_linux-x64_debug.zip *
cd %BUILD_FOLDER%\MPF.Check\bin\Debug\net7.0\osx-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check-dbg_net7.0_osx-x64.zip *
7z a -tzip %BUILD_FOLDER%\MPF.Check_net7.0_osx-x64_debug.zip *
REM Create MPF.Check Release archives
cd %BUILD_FOLDER%\MPF.Check\bin\Release\net48\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check_net48.zip *
cd %BUILD_FOLDER%\MPF.Check\bin\Release\net48\win7-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check_net48_release.zip *
cd %BUILD_FOLDER%\MPF.Check\bin\Release\net6.0\win-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check_net6.0_win-x64.zip *
7z a -tzip %BUILD_FOLDER%\MPF.Check_net6.0_win-x64_release.zip *
cd %BUILD_FOLDER%\MPF.Check\bin\Release\net6.0\linux-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check_net6.0_linux-x64.zip *
7z a -tzip %BUILD_FOLDER%\MPF.Check_net6.0_linux-x64_release.zip *
cd %BUILD_FOLDER%\MPF.Check\bin\Release\net6.0\osx-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check_net6.0_osx-x64.zip *
7z a -tzip %BUILD_FOLDER%\MPF.Check_net6.0_osx-x64_release.zip *
cd %BUILD_FOLDER%\MPF.Check\bin\Release\net7.0\win-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check_net7.0_win-x64.zip *
7z a -tzip %BUILD_FOLDER%\MPF.Check_net7.0_win-x64_release.zip *
cd %BUILD_FOLDER%\MPF.Check\bin\Release\net7.0\linux-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check_net7.0_linux-x64.zip *
7z a -tzip %BUILD_FOLDER%\MPF.Check_net7.0_linux-x64_release.zip *
cd %BUILD_FOLDER%\MPF.Check\bin\Release\net7.0\osx-x64\publish\
7z a -tzip %BUILD_FOLDER%\MPF.Check_net7.0_osx-x64.zip *
7z a -tzip %BUILD_FOLDER%\MPF.Check_net7.0_osx-x64_release.zip *