mirror of
https://github.com/SabreTools/MPF.git
synced 2026-07-02 17:24:48 +00:00
Support ancient .NET in Core
This does not include .NET Framework 4.0 due to some issues with libraries.
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
- Add Bandai Pippin detection
|
||||
- Zip manufacturer files for Redumper
|
||||
- Fix BE flag logic bug in DIC
|
||||
- Support ancient .NET in Core
|
||||
|
||||
### 3.0.0 (2023-11-14)
|
||||
|
||||
|
||||
@@ -14,21 +14,33 @@ namespace MPF.Core.Data
|
||||
public const string StopDumping = "Stop Dumping";
|
||||
|
||||
// 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 };
|
||||
public static readonly byte[] SaturnSectorZeroStart = [0x53, 0x45, 0x47, 0x41, 0x20, 0x53, 0x45, 0x47, 0x41, 0x53, 0x41, 0x54, 0x55, 0x52, 0x4E, 0x20];
|
||||
|
||||
// Lists of known drive speed ranges
|
||||
#if NET40
|
||||
public static IList<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 IList<int> DVD { get; } = CD.Where(s => s <= 24).ToList();
|
||||
public static IList<int> HDDVD { get; } = CD.Where(s => s <= 24).ToList();
|
||||
public static IList<int> BD { get; } = CD.Where(s => s <= 16).ToList();
|
||||
public static IList<int> Unknown { get; } = new List<int> { 1 };
|
||||
#else
|
||||
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 };
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Get list of all drive speeds for a given MediaType
|
||||
/// </summary>
|
||||
/// <param name="type">MediaType? that represents the current item</param>
|
||||
/// <returns>Read-only list of drive speeds</returns>
|
||||
#if NET40
|
||||
public static IList<int> GetSpeedsForMediaType(MediaType? type)
|
||||
#else
|
||||
public static IReadOnlyList<int> GetSpeedsForMediaType(MediaType? type)
|
||||
#endif
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
using Microsoft.Management.Infrastructure;
|
||||
using Microsoft.Management.Infrastructure.Generic;
|
||||
#endif
|
||||
using MPF.Core.Converters;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
@@ -61,7 +63,7 @@ namespace MPF.Core.Data
|
||||
{
|
||||
get
|
||||
{
|
||||
string volumeLabel = Template.DiscNotDetected;
|
||||
string? volumeLabel = Template.DiscNotDetected;
|
||||
if (this.MarkedActive)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(this.VolumeLabel))
|
||||
@@ -71,7 +73,7 @@ namespace MPF.Core.Data
|
||||
}
|
||||
|
||||
foreach (char c in Path.GetInvalidFileNameChars())
|
||||
volumeLabel = volumeLabel.Replace(c, '_');
|
||||
volumeLabel = volumeLabel?.Replace(c, '_');
|
||||
|
||||
return volumeLabel;
|
||||
}
|
||||
@@ -109,7 +111,7 @@ namespace MPF.Core.Data
|
||||
|
||||
// Sanitize a Windows-formatted long device path
|
||||
if (devicePath.StartsWith("\\\\.\\"))
|
||||
devicePath = devicePath["\\\\.\\".Length..];
|
||||
devicePath = devicePath.Substring("\\\\.\\".Length);
|
||||
|
||||
// Create and validate the drive info object
|
||||
var driveInfo = new DriveInfo(devicePath);
|
||||
@@ -249,7 +251,7 @@ namespace MPF.Core.Data
|
||||
public RedumpSystem? GetRedumpSystem(RedumpSystem? defaultValue)
|
||||
{
|
||||
// If we can't read the media in that drive, we can't do anything
|
||||
if (!Directory.Exists(this.Name))
|
||||
if (string.IsNullOrWhiteSpace(this.Name) || !Directory.Exists(this.Name))
|
||||
return defaultValue;
|
||||
|
||||
// We're going to assume for floppies, HDDs, and removable drives
|
||||
@@ -456,7 +458,7 @@ namespace MPF.Core.Data
|
||||
return null;
|
||||
|
||||
// Audio CD
|
||||
if (this.VolumeLabel.Equals("Audio CD", StringComparison.OrdinalIgnoreCase))
|
||||
if (this.VolumeLabel!.Equals("Audio CD", StringComparison.OrdinalIgnoreCase))
|
||||
return RedumpSystem.AudioCD;
|
||||
|
||||
// Microsoft Xbox
|
||||
@@ -547,6 +549,7 @@ namespace MPF.Core.Data
|
||||
}
|
||||
|
||||
// Find and update all floppy drives
|
||||
#if NET462_OR_GREATER
|
||||
try
|
||||
{
|
||||
CimSession session = CimSession.Create(null);
|
||||
@@ -567,6 +570,7 @@ namespace MPF.Core.Data
|
||||
{
|
||||
// No-op
|
||||
}
|
||||
#endif
|
||||
|
||||
return drives;
|
||||
}
|
||||
|
||||
@@ -6,14 +6,18 @@
|
||||
public enum Hash
|
||||
{
|
||||
CRC32,
|
||||
#if NET6_0_OR_GREATER
|
||||
CRC64,
|
||||
#endif
|
||||
MD5,
|
||||
SHA1,
|
||||
SHA256,
|
||||
SHA384,
|
||||
SHA512,
|
||||
#if NET6_0_OR_GREATER
|
||||
XxHash32,
|
||||
XxHash64,
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace MPF.Core.Data
|
||||
}
|
||||
|
||||
// Comments start with ';'
|
||||
else if (line.StartsWith(";"))
|
||||
else if (line!.StartsWith(";"))
|
||||
{
|
||||
// No-op, we don't process comments
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BinaryObjectScanner;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.Modules;
|
||||
using MPF.Core.Utilities;
|
||||
@@ -75,14 +74,18 @@ namespace MPF.Core
|
||||
/// <summary>
|
||||
/// Event handler for data returned from a process
|
||||
/// </summary>
|
||||
#if NET40
|
||||
private void OutputToLog(object? proc, BaseParameters.StringEventArgs args) => outputQueue?.Enqueue(args.Value);
|
||||
#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);
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for a full DumpEnvironment object from user information
|
||||
@@ -256,7 +259,7 @@ namespace MPF.Core
|
||||
/// <returns>Result instance with the outcome</returns>
|
||||
public async Task<Result> VerifyAndSaveDumpOutput(
|
||||
IProgress<Result>? resultProgress = null,
|
||||
IProgress<ProtectionProgress>? protectionProgress = null,
|
||||
IProgress<BinaryObjectScanner.ProtectionProgress>? protectionProgress = null,
|
||||
Func<SubmissionInfo?, (bool?, SubmissionInfo?)>? processUserInfo = null,
|
||||
SubmissionInfo? seedInfo = null)
|
||||
{
|
||||
@@ -432,8 +435,8 @@ namespace MPF.Core
|
||||
{
|
||||
StartInfo = new ProcessStartInfo()
|
||||
{
|
||||
FileName = parameters.ExecutablePath,
|
||||
Arguments = parameters.GenerateParameters(),
|
||||
FileName = parameters.ExecutablePath!,
|
||||
Arguments = parameters.GenerateParameters()!,
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardInput = true,
|
||||
@@ -477,7 +480,7 @@ namespace MPF.Core
|
||||
return Result.Failure($"Error! {Parameters.ExecutablePath} does not exist!");
|
||||
|
||||
// Validate that the dumping drive doesn't contain the executable
|
||||
string fullExecutablePath = Path.GetFullPath(Parameters.ExecutablePath);
|
||||
string fullExecutablePath = Path.GetFullPath(Parameters.ExecutablePath!);
|
||||
if (Drive?.Name != null && fullExecutablePath.StartsWith(Drive.Name))
|
||||
return Result.Failure("Error! Cannot dump same drive that executable resides on!");
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
#if NET6_0_OR_GREATER
|
||||
using System.IO.Hashing;
|
||||
#endif
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading.Tasks;
|
||||
@@ -16,7 +18,11 @@ namespace MPF.Core.Hashing
|
||||
/// <summary>
|
||||
/// Hash type associated with the current state
|
||||
/// </summary>
|
||||
#if NETFRAMEWORK || NETCOREAPP3_1
|
||||
public Hash HashType { get; private set; }
|
||||
#else
|
||||
public Hash HashType { get; init; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Current hash in bytes
|
||||
@@ -71,14 +77,18 @@ namespace MPF.Core.Hashing
|
||||
_hasher = HashType switch
|
||||
{
|
||||
Hash.CRC32 => new Crc32(),
|
||||
#if NET6_0_OR_GREATER
|
||||
Hash.CRC64 => new Crc64(),
|
||||
#endif
|
||||
Hash.MD5 => MD5.Create(),
|
||||
Hash.SHA1 => SHA1.Create(),
|
||||
Hash.SHA256 => SHA256.Create(),
|
||||
Hash.SHA384 => SHA384.Create(),
|
||||
Hash.SHA512 => SHA512.Create(),
|
||||
#if NET6_0_OR_GREATER
|
||||
Hash.XxHash32 => new XxHash32(),
|
||||
Hash.XxHash64 => new XxHash64(),
|
||||
#endif
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
@@ -156,14 +166,18 @@ namespace MPF.Core.Hashing
|
||||
var hashers = new Dictionary<Hash, Hasher>
|
||||
{
|
||||
{ Hash.CRC32, new Hasher(Hash.CRC32) },
|
||||
#if NET6_0_OR_GREATER
|
||||
{ Hash.CRC64, new Hasher(Hash.CRC64) },
|
||||
#endif
|
||||
{ Hash.MD5, new Hasher(Hash.MD5) },
|
||||
{ Hash.SHA1, new Hasher(Hash.SHA1) },
|
||||
{ Hash.SHA256, new Hasher(Hash.SHA256) },
|
||||
{ Hash.SHA384, new Hasher(Hash.SHA384) },
|
||||
{ Hash.SHA512, new Hasher(Hash.SHA512) },
|
||||
#if NET6_0_OR_GREATER
|
||||
{ Hash.XxHash32, new Hasher(Hash.XxHash32) },
|
||||
{ Hash.XxHash64, new Hasher(Hash.XxHash64) },
|
||||
#endif
|
||||
};
|
||||
|
||||
// Initialize the hashing helpers
|
||||
@@ -216,15 +230,18 @@ namespace MPF.Core.Hashing
|
||||
|
||||
// Get the results
|
||||
hashDict[Hash.CRC32] = hashers[Hash.CRC32].CurrentHashString;
|
||||
#if NET6_0_OR_GREATER
|
||||
hashDict[Hash.CRC64] = hashers[Hash.CRC64].CurrentHashString;
|
||||
#endif
|
||||
hashDict[Hash.MD5] = hashers[Hash.MD5].CurrentHashString;
|
||||
hashDict[Hash.SHA1] = hashers[Hash.SHA1].CurrentHashString;
|
||||
hashDict[Hash.SHA256] = hashers[Hash.SHA256].CurrentHashString;
|
||||
hashDict[Hash.SHA384] = hashers[Hash.SHA384].CurrentHashString;
|
||||
hashDict[Hash.SHA512] = hashers[Hash.SHA512].CurrentHashString;
|
||||
#if NET6_0_OR_GREATER
|
||||
hashDict[Hash.XxHash32] = hashers[Hash.XxHash32].CurrentHashString;
|
||||
hashDict[Hash.XxHash64] = hashers[Hash.XxHash64].CurrentHashString;
|
||||
hashDict[Hash.CRC64] = hashers[Hash.CRC64].CurrentHashString;
|
||||
#endif
|
||||
|
||||
// Dispose of the hashers
|
||||
loadBuffer.Dispose();
|
||||
@@ -272,7 +289,11 @@ namespace MPF.Core.Hashing
|
||||
/// <remarks>NonCryptographicHashAlgorithm implementations do not need finalization</remarks>
|
||||
public void Terminate()
|
||||
{
|
||||
#if NET40 || NET452
|
||||
byte[] emptyBuffer = [];
|
||||
#else
|
||||
byte[] emptyBuffer = Array.Empty<byte>();
|
||||
#endif
|
||||
switch (_hasher)
|
||||
{
|
||||
case HashAlgorithm ha:
|
||||
|
||||
184
MPF.Core/Hashing/OptimizedCRC.cs
Normal file
184
MPF.Core/Hashing/OptimizedCRC.cs
Normal file
@@ -0,0 +1,184 @@
|
||||
#if NETFRAMEWORK || NETCOREAPP3_1 || NET5_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
|
||||
{
|
||||
/// <summary>
|
||||
/// Shell class to trick older versions into using CRC-32 properly
|
||||
/// </summary>
|
||||
internal abstract class NonCryptographicHashAlgorithm
|
||||
{
|
||||
#if NET40
|
||||
/// <summary>
|
||||
/// When overridden in a derived class, appends the contents of source to
|
||||
/// the data already processed for the current hash computation.
|
||||
/// </summary>
|
||||
/// <param name="source">The data to process.</param>
|
||||
public abstract void Append(byte[] source);
|
||||
#else
|
||||
/// <summary>
|
||||
/// When overridden in a derived class, appends the contents of source to
|
||||
/// the data already processed for the current hash computation.
|
||||
/// </summary>
|
||||
/// <param name="source">The data to process.</param>
|
||||
public abstract void Append(ReadOnlySpan<byte> source);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current computed hash value without modifying accumulated state.
|
||||
/// </summary>
|
||||
/// <returns>The hash value for the data already provided.</returns>
|
||||
public abstract byte[] GetCurrentHash();
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// Some changes have been made to this code to make it more similar to the System.IO.Hashing implementations
|
||||
/// </remarks>
|
||||
internal class Crc32 : NonCryptographicHashAlgorithm, IDisposable
|
||||
{
|
||||
private const uint kCrcPoly = 0xEDB88320;
|
||||
private const uint kInitial = 0xFFFFFFFF;
|
||||
private const int CRC_NUM_TABLES = 8;
|
||||
private static readonly uint[] Table;
|
||||
|
||||
static Crc32()
|
||||
{
|
||||
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 Crc32()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset CRC
|
||||
/// </summary>
|
||||
public void Init()
|
||||
{
|
||||
UnsignedValue = kInitial;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[] GetCurrentHash()
|
||||
{
|
||||
return BitConverter.GetBytes(~UnsignedValue);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET40
|
||||
public override void Append(byte[] source)
|
||||
{
|
||||
Update(source, 0, source.Length);
|
||||
}
|
||||
#else
|
||||
public override void Append(ReadOnlySpan<byte> source)
|
||||
{
|
||||
byte[] sourceBytes = source.ToArray();
|
||||
Update(sourceBytes, 0, sourceBytes.Length);
|
||||
}
|
||||
#endif
|
||||
|
||||
private void Update(byte[] data, int offset, int count)
|
||||
{
|
||||
_ = new ArraySegment<byte>(data, offset, count); // check arguments
|
||||
if (count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var table = 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;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
UnsignedValue = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -9,7 +9,6 @@ using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
using System.Xml.Serialization;
|
||||
using BinaryObjectScanner;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.Modules;
|
||||
using MPF.Core.Utilities;
|
||||
@@ -104,7 +103,7 @@ namespace MPF.Core
|
||||
/// <param name="options">Options object that determines what to scan</param>
|
||||
/// <param name="progress">Optional progress callback</param>
|
||||
/// <returns>Detected copy protection(s) if possible, null on error</returns>
|
||||
internal static async Task<(string?, Dictionary<string, List<string>>?)> GetCopyProtection(Drive? drive, Data.Options options, IProgress<ProtectionProgress>? progress = null)
|
||||
internal static async Task<(string?, Dictionary<string, List<string>>?)> GetCopyProtection(Drive? drive, Data.Options options, IProgress<BinaryObjectScanner.ProtectionProgress>? progress = null)
|
||||
{
|
||||
if (options.ScanForProtection && drive?.Name != null)
|
||||
{
|
||||
@@ -980,7 +979,7 @@ namespace MPF.Core
|
||||
return null;
|
||||
|
||||
// Standardized "S" serials
|
||||
if (serial.StartsWith("S"))
|
||||
if (serial!.StartsWith("S"))
|
||||
{
|
||||
// string publisher = serial[0] + serial[1];
|
||||
// char secondRegion = serial[3];
|
||||
@@ -1135,8 +1134,13 @@ namespace MPF.Core
|
||||
}
|
||||
else
|
||||
{
|
||||
string entryName = file[outputDirectory.Length..].TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||
string entryName = file.Substring(outputDirectory!.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||
|
||||
#if NETFRAMEWORK || NETCOREAPP3_1 || NET5_0
|
||||
zf.CreateEntryFromFile(file, entryName, CompressionLevel.Optimal);
|
||||
#else
|
||||
zf.CreateEntryFromFile(file, entryName, CompressionLevel.SmallestSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
// If the file is MPF-specific, don't delete
|
||||
@@ -1256,8 +1260,8 @@ namespace MPF.Core
|
||||
AddIfExists(output, Template.FullyMatchingIDField, info.FullyMatchedID?.ToString(), 1);
|
||||
AddIfExists(output, Template.PartiallyMatchingIDsField, info.PartiallyMatchedIDs, 1);
|
||||
AddIfExists(output, Template.RegionField, info.CommonDiscInfo?.Region.LongName() ?? "SPACE! (CHANGE THIS)", 1);
|
||||
AddIfExists(output, Template.LanguagesField, (info.CommonDiscInfo?.Languages ?? new Language?[] { null }).Select(l => l.LongName() ?? "SILENCE! (CHANGE THIS)").ToArray(), 1);
|
||||
AddIfExists(output, Template.PlaystationLanguageSelectionViaField, (info.CommonDiscInfo?.LanguageSelection ?? Array.Empty<LanguageSelection?>()).Select(l => l.LongName()).ToArray(), 1);
|
||||
AddIfExists(output, Template.LanguagesField, (info.CommonDiscInfo?.Languages ?? [null]).Select(l => l.LongName() ?? "SILENCE! (CHANGE THIS)").ToArray(), 1);
|
||||
AddIfExists(output, Template.PlaystationLanguageSelectionViaField, (info.CommonDiscInfo?.LanguageSelection ?? []).Select(l => l.LongName()).ToArray(), 1);
|
||||
AddIfExists(output, Template.DiscSerialField, info.CommonDiscInfo?.Serial, 1);
|
||||
|
||||
// All ringcode information goes in an indented area
|
||||
@@ -1383,12 +1387,12 @@ namespace MPF.Core
|
||||
output.Add(""); output.Add("Copy Protection:");
|
||||
if (info.CommonDiscInfo?.System == RedumpSystem.SonyPlayStation)
|
||||
{
|
||||
AddIfExists(output, Template.PlayStationAntiModchipField, info.CopyProtection.AntiModchip.LongName(), 1);
|
||||
AddIfExists(output, Template.PlayStationAntiModchipField, info.CopyProtection!.AntiModchip.LongName(), 1);
|
||||
AddIfExists(output, Template.PlayStationLibCryptField, info.CopyProtection.LibCrypt.LongName(), 1);
|
||||
AddIfExists(output, Template.SubIntentionField, info.CopyProtection.LibCryptData, 1);
|
||||
}
|
||||
|
||||
AddIfExists(output, Template.CopyProtectionField, info.CopyProtection.Protection, 1);
|
||||
AddIfExists(output, Template.CopyProtectionField, info.CopyProtection!.Protection, 1);
|
||||
AddIfExists(output, Template.SubIntentionField, info.CopyProtection.SecuROMData, 1);
|
||||
}
|
||||
|
||||
@@ -1401,7 +1405,7 @@ namespace MPF.Core
|
||||
if (!string.IsNullOrWhiteSpace(info.TracksAndWriteOffsets?.ClrMameProData))
|
||||
{
|
||||
output.Add(""); output.Add("Tracks and Write Offsets:");
|
||||
AddIfExists(output, Template.DATField, info.TracksAndWriteOffsets.ClrMameProData + "\n", 1);
|
||||
AddIfExists(output, Template.DATField, info.TracksAndWriteOffsets!.ClrMameProData + "\n", 1);
|
||||
AddIfExists(output, Template.CuesheetField, info.TracksAndWriteOffsets.Cuesheet, 1);
|
||||
var offset = info.TracksAndWriteOffsets.OtherWriteOffsets;
|
||||
if (Int32.TryParse(offset, out int i))
|
||||
@@ -1880,7 +1884,7 @@ namespace MPF.Core
|
||||
return files;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Normalization
|
||||
|
||||
@@ -1894,7 +1898,7 @@ namespace MPF.Core
|
||||
{
|
||||
// If we have no set languages, then assume English
|
||||
if (languages == null || languages.Length == 0)
|
||||
languages = new Language[] { Language.English };
|
||||
languages = [Language.English];
|
||||
|
||||
// Loop through all of the given languages
|
||||
foreach (var language in languages)
|
||||
@@ -2358,7 +2362,7 @@ namespace MPF.Core
|
||||
return string.Empty;
|
||||
|
||||
// Remove quotes from path
|
||||
path = path.Replace("\"", string.Empty);
|
||||
path = path!.Replace("\"", string.Empty);
|
||||
|
||||
// Try getting the combined path and returning that directly
|
||||
string fullPath = getFullPath ? Path.GetFullPath(path) : path;
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
|
||||
<Copyright>Copyright (c)2019-2023</Copyright>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<VersionPrefix>3.0.0</VersionPrefix>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski;ReignStumble;Jakz</Authors>
|
||||
<Description>Common code for all MPF implementations</Description>
|
||||
<Copyright>Copyright (c) Matt Nadareski 2019-2023</Copyright>
|
||||
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/SabreTools/MPF</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -17,16 +26,30 @@
|
||||
<PackageReference Include="BinaryObjectScanner" PrivateAssets="build; analyzers" ExcludeAssets="contentFiles" Version="3.0.0" GeneratePathProperty="true">
|
||||
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="psxt001z" Version="0.21.0-beta2" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.2.0" />
|
||||
<PackageReference Include="SabreTools.RedumpLib" Version="1.2.0" />
|
||||
<PackageReference Include="SabreTools.Serialization" Version="1.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="!$(TargetFramework.StartsWith(`net40`))">
|
||||
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="$(TargetFramework.StartsWith(`net40`)) OR $(TargetFramework.StartsWith(`net452`))">
|
||||
<PackageReference Include="Microsoft.Net.Http" Version="2.2.29" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="!$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net452`))">
|
||||
<PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0" />
|
||||
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" />
|
||||
<PackageReference Include="System.IO.Hashing" Version="8.0.0" />
|
||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="$(TargetFramework.StartsWith(`net6`)) OR $(TargetFramework.StartsWith(`net7`)) OR $(TargetFramework.StartsWith(`net8`))">
|
||||
<PackageReference Include="System.IO.Hashing" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -226,9 +226,9 @@ namespace MPF.Core.Modules.Aaru
|
||||
if (!string.IsNullOrWhiteSpace(discType) && !string.IsNullOrWhiteSpace(discSubType))
|
||||
fullDiscType = $"{discType} ({discSubType})";
|
||||
else if (!string.IsNullOrWhiteSpace(discType) && string.IsNullOrWhiteSpace(discSubType))
|
||||
fullDiscType = discType;
|
||||
fullDiscType = discType!;
|
||||
else if (string.IsNullOrWhiteSpace(discType) && !string.IsNullOrWhiteSpace(discSubType))
|
||||
fullDiscType = discSubType;
|
||||
fullDiscType = discSubType!;
|
||||
|
||||
info.DumpingInfo.ReportedDiscType = fullDiscType;
|
||||
}
|
||||
@@ -1630,7 +1630,7 @@ namespace MPF.Core.Modules.Aaru
|
||||
|
||||
// Now split the string into parts for easier validation
|
||||
// https://stackoverflow.com/questions/14655023/split-a-string-that-has-white-spaces-unless-they-are-enclosed-within-quotes
|
||||
parameters = parameters.Trim();
|
||||
parameters = parameters!.Trim();
|
||||
List<string> parts = Regex.Matches(parameters, @"[\""].+?[\""]|[^ ]+", RegexOptions.Compiled)
|
||||
.Cast<Match>()
|
||||
.Select(m => m.Value)
|
||||
@@ -2384,7 +2384,11 @@ namespace MPF.Core.Modules.Aaru
|
||||
var cueFiles = new List<CueFile>();
|
||||
var cueSheet = new CueSheet
|
||||
{
|
||||
#if NET40 || NET452
|
||||
Performer = string.Join(", ", cicmSidecar.Performer ?? []),
|
||||
#else
|
||||
Performer = string.Join(", ", cicmSidecar.Performer ?? Array.Empty<string>()),
|
||||
#endif
|
||||
};
|
||||
|
||||
// Only care about OpticalDisc types
|
||||
@@ -2931,16 +2935,24 @@ namespace MPF.Core.Modules.Aaru
|
||||
/// Generate a single 16-byte sector line from a byte array
|
||||
/// </summary>
|
||||
/// <param name="row">Row ID for outputting</param>
|
||||
/// <param name="bytes">Byte span representing the data to write</param>
|
||||
/// <param name="bytes">Bytes representing the data to write</param>
|
||||
/// <returns>Formatted string representing the sector line</returns>
|
||||
#if NET40
|
||||
private static string? GenerateSectorOutputLine(string row, 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)
|
||||
return null;
|
||||
|
||||
string pvdLine = $"{row} : ";
|
||||
#if NETFRAMEWORK || NETCOREAPP3_1 || NET5_0
|
||||
pvdLine += BitConverter.ToString(bytes.Slice(0, 8).ToArray()).Replace("-", " ");
|
||||
#else
|
||||
pvdLine += BitConverter.ToString(bytes[..8].ToArray()).Replace("-", " ");
|
||||
#endif
|
||||
pvdLine += " ";
|
||||
pvdLine += BitConverter.ToString(bytes.Slice(8, 8).ToArray().ToArray()).Replace("-", " ");
|
||||
pvdLine += " ";
|
||||
@@ -3086,7 +3098,7 @@ namespace MPF.Core.Modules.Aaru
|
||||
// Initialize on seeing the open tag
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
continue;
|
||||
else if (line.StartsWith("<BadBlocks>"))
|
||||
else if (line!.StartsWith("<BadBlocks>"))
|
||||
totalErrors = 0;
|
||||
else if (line.StartsWith("</BadBlocks>"))
|
||||
return totalErrors ?? -1;
|
||||
@@ -3400,6 +3412,6 @@ namespace MPF.Core.Modules.Aaru
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,27 @@ namespace MPF.Core.Modules
|
||||
{
|
||||
#region Event Handlers
|
||||
|
||||
#if NET40
|
||||
/// <summary>
|
||||
/// Wrapper event args class for old .NET
|
||||
/// </summary>
|
||||
public class StringEventArgs : EventArgs
|
||||
{
|
||||
public string Value { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Geneeic way of reporting a message
|
||||
/// </summary>
|
||||
/// <param name="message">String value to report</param>
|
||||
public EventHandler<StringEventArgs>? ReportStatus;
|
||||
#else
|
||||
/// <summary>
|
||||
/// Geneeic way of reporting a message
|
||||
/// </summary>
|
||||
/// <param name="message">String value to report</param>
|
||||
public EventHandler<string>? ReportStatus;
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -261,7 +277,7 @@ namespace MPF.Core.Modules
|
||||
// Create the start info
|
||||
var startInfo = new ProcessStartInfo()
|
||||
{
|
||||
FileName = ExecutablePath,
|
||||
FileName = ExecutablePath!,
|
||||
Arguments = GenerateParameters() ?? "",
|
||||
CreateNoWindow = !separateWindow,
|
||||
UseShellExecute = separateWindow,
|
||||
@@ -1104,7 +1120,7 @@ namespace MPF.Core.Modules
|
||||
return null;
|
||||
|
||||
if (trimLength > -1)
|
||||
hex = hex[..trimLength];
|
||||
hex = hex.Substring(0, trimLength);
|
||||
|
||||
return Regex.Replace(hex, ".{32}", "$0\n", RegexOptions.Compiled);
|
||||
}
|
||||
@@ -1117,6 +1133,6 @@ namespace MPF.Core.Modules
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,12 +170,12 @@ namespace MPF.Core.Modules.CleanRip
|
||||
var line = sr.ReadLine()?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
continue;
|
||||
else if (line.StartsWith("CRC32"))
|
||||
crc = line[7..].ToLowerInvariant();
|
||||
else if (line!.StartsWith("CRC32"))
|
||||
crc = line.Substring(7).ToLowerInvariant();
|
||||
else if (line.StartsWith("MD5"))
|
||||
md5 = line[5..];
|
||||
md5 = line.Substring(5);
|
||||
else if (line.StartsWith("SHA-1"))
|
||||
sha1 = line[7..];
|
||||
sha1 = line.Substring(7);
|
||||
}
|
||||
|
||||
return new Datafile
|
||||
@@ -256,12 +256,12 @@ namespace MPF.Core.Modules.CleanRip
|
||||
var line = sr.ReadLine()?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
continue;
|
||||
else if (line.StartsWith("CRC32"))
|
||||
crc = line[7..].ToLowerInvariant();
|
||||
else if (line!.StartsWith("CRC32"))
|
||||
crc = line.Substring(7).ToLowerInvariant();
|
||||
else if (line.StartsWith("MD5"))
|
||||
md5 = line[5..];
|
||||
md5 = line.Substring(5);
|
||||
else if (line.StartsWith("SHA-1"))
|
||||
sha1 = line[7..];
|
||||
sha1 = line.Substring(7);
|
||||
}
|
||||
|
||||
return $"<rom name=\"{Path.GetFileName(iso)}\" size=\"{size}\" crc=\"{crc}\" md5=\"{md5}\" sha1=\"{sha1}\" />";
|
||||
@@ -304,17 +304,17 @@ namespace MPF.Core.Modules.CleanRip
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (line.StartsWith("Version"))
|
||||
else if (line!.StartsWith("Version"))
|
||||
{
|
||||
version = line["Version: ".Length..];
|
||||
version = line.Substring("Version: ".Length);
|
||||
}
|
||||
else if (line.StartsWith("Internal Name"))
|
||||
{
|
||||
name = line["Internal Name: ".Length..];
|
||||
name = line.Substring("Internal Name: ".Length);
|
||||
}
|
||||
else if (line.StartsWith("Filename"))
|
||||
{
|
||||
string serial = line["Filename: ".Length..];
|
||||
string serial = line.Substring("Filename: ".Length);
|
||||
|
||||
// char gameType = serial[0];
|
||||
// string gameid = serial[1] + serial[2];
|
||||
|
||||
@@ -1940,7 +1940,7 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
|
||||
// Now split the string into parts for easier validation
|
||||
// https://stackoverflow.com/questions/14655023/split-a-string-that-has-white-spaces-unless-they-are-enclosed-within-quotes
|
||||
parameters = parameters.Trim();
|
||||
parameters = parameters!.Trim();
|
||||
List<string> parts = Regex.Matches(parameters, @"[\""].+?[\""]|[^ ]+", RegexOptions.Compiled)
|
||||
.Cast<Match>()
|
||||
.Select(m => m.Value)
|
||||
@@ -2697,25 +2697,25 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
if (line.StartsWith("DiscType:"))
|
||||
{
|
||||
// DiscType: <discType>
|
||||
string identifier = line["DiscType: ".Length..];
|
||||
string identifier = line.Substring("DiscType: ".Length);
|
||||
discTypeOrBookTypeSet.Add(identifier);
|
||||
}
|
||||
else if (line.StartsWith("DiscTypeIdentifier:"))
|
||||
{
|
||||
// DiscTypeIdentifier: <discType>
|
||||
string identifier = line["DiscTypeIdentifier: ".Length..];
|
||||
string identifier = line.Substring("DiscTypeIdentifier: ".Length);
|
||||
discTypeOrBookTypeSet.Add(identifier);
|
||||
}
|
||||
else if (line.StartsWith("DiscTypeSpecific:"))
|
||||
{
|
||||
// DiscTypeSpecific: <discType>
|
||||
string identifier = line["DiscTypeSpecific: ".Length..];
|
||||
string identifier = line.Substring("DiscTypeSpecific: ".Length);
|
||||
discTypeOrBookTypeSet.Add(identifier);
|
||||
}
|
||||
else if (line.StartsWith("BookType:"))
|
||||
{
|
||||
// BookType: <discType>
|
||||
string identifier = line["BookType: ".Length..];
|
||||
string identifier = line.Substring("BookType: ".Length);
|
||||
discTypeOrBookTypeSet.Add(identifier);
|
||||
}
|
||||
|
||||
@@ -2767,9 +2767,9 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
break;
|
||||
|
||||
if (line.StartsWith("CopyrightProtectionType"))
|
||||
copyrightProtectionSystemType = line["CopyrightProtectionType: ".Length..];
|
||||
copyrightProtectionSystemType = line.Substring("CopyrightProtectionType: ".Length);
|
||||
else if (line.StartsWith("RegionManagementInformation"))
|
||||
region = line["RegionManagementInformation: ".Length..];
|
||||
region = line.Substring("RegionManagementInformation: ".Length);
|
||||
|
||||
line = sr.ReadLine()?.Trim();
|
||||
}
|
||||
@@ -2792,7 +2792,7 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
|
||||
if (line.StartsWith("DecryptedDiscKey"))
|
||||
{
|
||||
decryptedDiscKey = line["DecryptedDiscKey[020]: ".Length..];
|
||||
decryptedDiscKey = line.Substring("DecryptedDiscKey[020]: ".Length);
|
||||
}
|
||||
else if (line.StartsWith("LBA:"))
|
||||
{
|
||||
@@ -2805,7 +2805,7 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
var match = Regex.Match(line, @"^LBA:\s*[0-9]+, Filename: (.*?), No TitleKey$", RegexOptions.Compiled);
|
||||
string matchedFilename = match.Groups[1].Value;
|
||||
if (matchedFilename.EndsWith(";1"))
|
||||
matchedFilename = matchedFilename[..^2];
|
||||
matchedFilename = matchedFilename.Substring(0, matchedFilename.Length - 2);
|
||||
|
||||
vobKeys += $"{matchedFilename} Title Key: No Title Key\n";
|
||||
}
|
||||
@@ -2814,7 +2814,7 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
var match = Regex.Match(line, @"^LBA:\s*[0-9]+, Filename: (.*?), EncryptedTitleKey: .*?, DecryptedTitleKey: (.*?)$", RegexOptions.Compiled);
|
||||
string matchedFilename = match.Groups[1].Value;
|
||||
if (matchedFilename.EndsWith(";1"))
|
||||
matchedFilename = matchedFilename[..^2];
|
||||
matchedFilename = matchedFilename.Substring(0, matchedFilename.Length - 2);
|
||||
|
||||
vobKeys += $"{matchedFilename} Title Key: {match.Groups[2].Value}\n";
|
||||
}
|
||||
@@ -2876,14 +2876,14 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
{
|
||||
totalErrors ??= 0;
|
||||
|
||||
if (Int64.TryParse(line["Total errors: ".Length..].Trim(), out long te))
|
||||
if (Int64.TryParse(line.Substring("Total errors: ".Length).Trim(), out long te))
|
||||
totalErrors += te;
|
||||
}
|
||||
else if (line.StartsWith("Total warnings"))
|
||||
{
|
||||
totalErrors ??= 0;
|
||||
|
||||
if (Int64.TryParse(line["Total warnings: ".Length..].Trim(), out long tw))
|
||||
if (Int64.TryParse(line.Substring("Total warnings: ".Length).Trim(), out long tw))
|
||||
totalErrors += tw;
|
||||
}
|
||||
}
|
||||
@@ -2914,12 +2914,12 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
// Now read it in cutting it into lines for easier parsing
|
||||
try
|
||||
{
|
||||
string[] header = segaHeader.Split('\n');
|
||||
string versionLine = header[4][58..];
|
||||
string dateLine = header[5][58..];
|
||||
serial = versionLine[..10].TrimEnd();
|
||||
string[] header = segaHeader!.Split('\n');
|
||||
string versionLine = header[4].Substring(58);
|
||||
string dateLine = header[5].Substring(58);
|
||||
serial = versionLine.Substring(0, 10).TrimEnd();
|
||||
version = versionLine.Substring(10, 6).TrimStart('V', 'v');
|
||||
date = dateLine[..8];
|
||||
date = dateLine.Substring(0, 8);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
@@ -2956,17 +2956,17 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
if (string.IsNullOrEmpty(manufacturer) && line.StartsWith("VendorId"))
|
||||
{
|
||||
// VendorId: <manufacturer>
|
||||
manufacturer = line["VendorId: ".Length..];
|
||||
manufacturer = line.Substring("VendorId: ".Length);
|
||||
}
|
||||
else if (string.IsNullOrEmpty(model) && line.StartsWith("ProductId"))
|
||||
{
|
||||
// ProductId: <model>
|
||||
model = line["ProductId: ".Length..];
|
||||
model = line.Substring("ProductId: ".Length);
|
||||
}
|
||||
else if (string.IsNullOrEmpty(firmware) && line.StartsWith("ProductRevisionLevel"))
|
||||
{
|
||||
// ProductRevisionLevel: <firmware>
|
||||
firmware = line["ProductRevisionLevel: ".Length..];
|
||||
firmware = line.Substring("ProductRevisionLevel: ".Length);
|
||||
}
|
||||
|
||||
line = sr.ReadLine();
|
||||
@@ -3117,7 +3117,7 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
// TODO: Are there any examples of 3+ session discs?
|
||||
|
||||
// Read the first session lead-out
|
||||
var firstSessionLeadOutLengthString = line?["Lead-out length of 1st session: ".Length..];
|
||||
var firstSessionLeadOutLengthString = line?.Substring("Lead-out length of 1st session: ".Length);
|
||||
line = sr.ReadLine()?.Trim();
|
||||
if (line == null)
|
||||
return null;
|
||||
@@ -3126,12 +3126,12 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
string? secondSessionLeadInLengthString = null;
|
||||
while (line?.StartsWith("Lead-in length") == false)
|
||||
{
|
||||
secondSessionLeadInLengthString = line?["Lead-in length of 2nd session: ".Length..];
|
||||
secondSessionLeadInLengthString = line?.Substring("Lead-in length of 2nd session: ".Length);
|
||||
line = sr.ReadLine()?.Trim();
|
||||
}
|
||||
|
||||
// Read the second session pregap
|
||||
var secondSessionPregapLengthString = line?["Pregap length of 1st track of 2nd session: ".Length..];
|
||||
var secondSessionPregapLengthString = line?.Substring("Pregap length of 1st track of 2nd session: ".Length);
|
||||
|
||||
// Calculate the session gap total
|
||||
if (!int.TryParse(firstSessionLeadOutLengthString, out int firstSessionLeadOutLength))
|
||||
@@ -3354,12 +3354,12 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
// Now read it in cutting it into lines for easier parsing
|
||||
try
|
||||
{
|
||||
string[] header = segaHeader.Split('\n');
|
||||
string serialVersionLine = header[2][58..];
|
||||
string dateLine = header[3][58..];
|
||||
serial = serialVersionLine[..10].Trim();
|
||||
string[] header = segaHeader!.Split('\n');
|
||||
string serialVersionLine = header[2].Substring(58);
|
||||
string dateLine = header[3].Substring(58);
|
||||
serial = serialVersionLine.Substring(0, 10).Trim();
|
||||
version = serialVersionLine.Substring(10, 6).TrimStart('V', 'v');
|
||||
date = dateLine[..8];
|
||||
date = dateLine.Substring(0, 8);
|
||||
date = $"{date[0]}{date[1]}{date[2]}{date[3]}-{date[4]}{date[5]}-{date[6]}{date[7]}";
|
||||
return true;
|
||||
}
|
||||
@@ -3387,17 +3387,17 @@ namespace MPF.Core.Modules.DiscImageCreator
|
||||
// Now read it in cutting it into lines for easier parsing
|
||||
try
|
||||
{
|
||||
string[] header = segaHeader.Split('\n');
|
||||
string serialVersionLine = header[8][58..];
|
||||
string dateLine = header[1][58..];
|
||||
string[] header = segaHeader!.Split('\n');
|
||||
string serialVersionLine = header[8].Substring(58);
|
||||
string dateLine = header[1].Substring(58);
|
||||
serial = serialVersionLine.Substring(3, 8).TrimEnd('-', ' ');
|
||||
date = dateLine[8..].Trim();
|
||||
date = dateLine.Substring(8).Trim();
|
||||
|
||||
// Properly format the date string, if possible
|
||||
string[] dateSplit = date.Split('.');
|
||||
|
||||
if (dateSplit.Length == 1)
|
||||
dateSplit = new string[] { date[..4], date[4..] };
|
||||
dateSplit = [date.Substring(0, 4), date.Substring(4)];
|
||||
|
||||
string month = dateSplit[1];
|
||||
dateSplit[1] = month switch
|
||||
|
||||
@@ -1016,7 +1016,7 @@ namespace MPF.Core.Modules.Redumper
|
||||
|
||||
// Now split the string into parts for easier validation
|
||||
// https://stackoverflow.com/questions/14655023/split-a-string-that-has-white-spaces-unless-they-are-enclosed-within-quotes
|
||||
parameters = parameters.Trim();
|
||||
parameters = parameters!.Trim();
|
||||
List<string> parts = Regex.Matches(parameters, @"([a-zA-Z\-]*=)?[\""].+?[\""]|[^ ]+", RegexOptions.Compiled)
|
||||
.Cast<Match>()
|
||||
.Select(m => m.Value)
|
||||
@@ -1105,12 +1105,12 @@ namespace MPF.Core.Modules.Redumper
|
||||
// Image Path
|
||||
stringValue = ProcessStringParameter(parts, FlagStrings.ImagePath, ref i);
|
||||
if (!string.IsNullOrWhiteSpace(stringValue))
|
||||
ImagePathValue = $"\"{stringValue.Trim('"')}\"";
|
||||
ImagePathValue = $"\"{stringValue!.Trim('"')}\"";
|
||||
|
||||
// Image Name
|
||||
stringValue = ProcessStringParameter(parts, FlagStrings.ImageName, ref i);
|
||||
if (!string.IsNullOrWhiteSpace(stringValue))
|
||||
ImageNameValue = $"\"{stringValue.Trim('"')}\"";
|
||||
ImageNameValue = $"\"{stringValue!.Trim('"')}\"";
|
||||
|
||||
// Overwrite
|
||||
ProcessFlagParameter(parts, FlagStrings.Overwrite, ref i);
|
||||
@@ -1352,7 +1352,7 @@ namespace MPF.Core.Modules.Redumper
|
||||
if (line.StartsWith("current profile:"))
|
||||
{
|
||||
// current profile: <discType>
|
||||
discTypeOrBookType = line["current profile: ".Length..];
|
||||
discTypeOrBookType = line.Substring("current profile: ".Length);
|
||||
}
|
||||
|
||||
line = sr.ReadLine();
|
||||
@@ -1394,17 +1394,17 @@ namespace MPF.Core.Modules.Redumper
|
||||
{
|
||||
if (line.StartsWith("protection system type"))
|
||||
{
|
||||
copyrightProtectionSystemType = line["protection system type: ".Length..];
|
||||
copyrightProtectionSystemType = line.Substring("protection system type: ".Length);
|
||||
if (copyrightProtectionSystemType == "none" || copyrightProtectionSystemType == "<none>")
|
||||
copyrightProtectionSystemType = "No";
|
||||
}
|
||||
else if (line.StartsWith("region management information:"))
|
||||
{
|
||||
region = line["region management information: ".Length..];
|
||||
region = line.Substring("region management information: ".Length);
|
||||
}
|
||||
else if (line.StartsWith("disc key"))
|
||||
{
|
||||
decryptedDiscKey = line["disc key: ".Length..].Replace(':', ' ');
|
||||
decryptedDiscKey = line.Substring("disc key: ".Length).Replace(':', ' ');
|
||||
}
|
||||
else if (line.StartsWith("title keys"))
|
||||
{
|
||||
@@ -1488,7 +1488,7 @@ namespace MPF.Core.Modules.Redumper
|
||||
break;
|
||||
|
||||
// REDUMP.ORG errors: <error count>
|
||||
string[] parts = line.Split(' ');
|
||||
string[] parts = line!.Split(' ');
|
||||
if (long.TryParse(parts[2], out long redump))
|
||||
return redump;
|
||||
else
|
||||
@@ -1596,24 +1596,24 @@ namespace MPF.Core.Modules.Redumper
|
||||
else if (line.StartsWith("layer break:"))
|
||||
{
|
||||
// layer break: <layerbreak>
|
||||
layerbreak1 = line["layer break: ".Length..].Trim();
|
||||
layerbreak1 = line.Substring("layer break: ".Length).Trim();
|
||||
}
|
||||
|
||||
// Multi-layer discs have the layer in the name
|
||||
else if (line.StartsWith("layer break (layer: 0):"))
|
||||
{
|
||||
// layer break (layer: 0): <layerbreak>
|
||||
layerbreak1 = line["layer break (layer: 0): ".Length..].Trim();
|
||||
layerbreak1 = line.Substring("layer break (layer: 0): ".Length).Trim();
|
||||
}
|
||||
else if (line.StartsWith("layer break (layer: 1):"))
|
||||
{
|
||||
// layer break (layer: 1): <layerbreak>
|
||||
layerbreak2 = line["layer break (layer: 1): ".Length..].Trim();
|
||||
layerbreak2 = line.Substring("layer break (layer: 1): ".Length).Trim();
|
||||
}
|
||||
else if (line.StartsWith("layer break (layer: 2):"))
|
||||
{
|
||||
// layer break (layer: 2): <layerbreak>
|
||||
layerbreak3 = line["layer break (layer: 2): ".Length..].Trim();
|
||||
layerbreak3 = line.Substring("layer break (layer: 2): ".Length).Trim();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1658,11 +1658,11 @@ namespace MPF.Core.Modules.Redumper
|
||||
|
||||
// Store the first session range
|
||||
if (line.Contains("session 1:"))
|
||||
firstSession = line["session 1: ".Length..].Trim();
|
||||
firstSession = line.Substring("session 1: ".Length).Trim();
|
||||
|
||||
// Store the secomd session range
|
||||
else if (line.Contains("session 2:"))
|
||||
secondSession = line["session 2: ".Length..].Trim();
|
||||
secondSession = line.Substring("session 2: ".Length).Trim();
|
||||
}
|
||||
|
||||
// If either is blank, we don't have multisession
|
||||
@@ -1884,7 +1884,7 @@ namespace MPF.Core.Modules.Redumper
|
||||
{
|
||||
string? line = sr.ReadLine()?.TrimStart();
|
||||
if (line?.StartsWith("non-zero data sample range") == true)
|
||||
return line["non-zero data sample range: [".Length..].Trim().Split(' ')[0];
|
||||
return line.Substring("non-zero data sample range: [".Length).Trim().Split(' ')[0];
|
||||
}
|
||||
|
||||
// We couldn't detect it then
|
||||
@@ -1914,12 +1914,12 @@ namespace MPF.Core.Modules.Redumper
|
||||
// Now read it in cutting it into lines for easier parsing
|
||||
try
|
||||
{
|
||||
string[] header = segaHeader.Split('\n');
|
||||
string serialVersionLine = header[2][58..];
|
||||
string dateLine = header[3][58..];
|
||||
serial = serialVersionLine[..10].Trim();
|
||||
string[] header = segaHeader!.Split('\n');
|
||||
string serialVersionLine = header[2].Substring(58);
|
||||
string dateLine = header[3].Substring(58);
|
||||
serial = serialVersionLine.Substring(0, 10).Trim();
|
||||
version = serialVersionLine.Substring(10, 6).TrimStart('V', 'v');
|
||||
date = dateLine[..8];
|
||||
date = dateLine.Substring(0, 8);
|
||||
date = $"{date[0]}{date[1]}{date[2]}{date[3]}-{date[4]}{date[5]}-{date[6]}{date[7]}";
|
||||
return true;
|
||||
}
|
||||
@@ -2052,19 +2052,19 @@ namespace MPF.Core.Modules.Redumper
|
||||
|
||||
if (line.StartsWith("build date:"))
|
||||
{
|
||||
buildDate = line["build date: ".Length..].Trim();
|
||||
buildDate = line.Substring("build date: ".Length).Trim();
|
||||
}
|
||||
else if (line.StartsWith("serial:"))
|
||||
{
|
||||
serial = line["serial: ".Length..].Trim();
|
||||
serial = line.Substring("serial: ".Length).Trim();
|
||||
}
|
||||
else if (line.StartsWith("region:"))
|
||||
{
|
||||
region = line["region: ".Length..].Trim();
|
||||
region = line.Substring("region: ".Length).Trim();
|
||||
}
|
||||
else if (line.StartsWith("regions:"))
|
||||
{
|
||||
region = line["regions: ".Length..].Trim();
|
||||
region = line.Substring("regions: ".Length).Trim();
|
||||
}
|
||||
else if (line.StartsWith("header:"))
|
||||
{
|
||||
@@ -2109,7 +2109,7 @@ namespace MPF.Core.Modules.Redumper
|
||||
{
|
||||
string? line = sr.ReadLine()?.TrimStart();
|
||||
if (line?.StartsWith("Universal Hash") == true)
|
||||
return line["Universal Hash (SHA-1): ".Length..].Trim();
|
||||
return line.Substring("Universal Hash (SHA-1): ".Length).Trim();
|
||||
}
|
||||
|
||||
// We couldn't detect it then
|
||||
@@ -2141,7 +2141,7 @@ namespace MPF.Core.Modules.Redumper
|
||||
{
|
||||
string? line = sr.ReadLine()?.TrimStart();
|
||||
if (line?.StartsWith("disc write offset") == true)
|
||||
return line["disc write offset: ".Length..].Trim();
|
||||
return line.Substring("disc write offset: ".Length).Trim();
|
||||
}
|
||||
|
||||
// We couldn't detect it then
|
||||
|
||||
@@ -203,7 +203,7 @@ namespace MPF.Core.Modules.UmdImageCreator
|
||||
break;
|
||||
|
||||
if (line.StartsWith("TITLE") && title == null)
|
||||
title = line["TITLE: ".Length..];
|
||||
title = line.Substring("TITLE: ".Length);
|
||||
else if (line.StartsWith("DISC_VERSION") && umdversion == null)
|
||||
umdversion = line.Split(' ')[1];
|
||||
else if (line.StartsWith("pspUmdTypes"))
|
||||
|
||||
@@ -4,8 +4,6 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using BinaryObjectScanner;
|
||||
using BinaryObjectScanner.Protection;
|
||||
using psxt001z;
|
||||
|
||||
#pragma warning disable SYSLIB1045 // Convert to 'GeneratedRegexAttribute'.
|
||||
@@ -21,13 +19,13 @@ namespace MPF.Core
|
||||
/// <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, Data.Options options, IProgress<ProtectionProgress>? progress = null)
|
||||
public static async Task<(Dictionary<string, List<string>>?, string?)> RunProtectionScanOnPath(string path, Data.Options options, IProgress<BinaryObjectScanner.ProtectionProgress>? progress = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var found = await Task.Run(() =>
|
||||
{
|
||||
var scanner = new Scanner(
|
||||
var scanner = new BinaryObjectScanner.Scanner(
|
||||
options.ScanArchivesForProtection,
|
||||
scanContents: true, // Hardcoded value to avoid issues
|
||||
scanGameEngines: false, // Hardcoded value to avoid issues
|
||||
@@ -99,7 +97,7 @@ namespace MPF.Core
|
||||
{
|
||||
try
|
||||
{
|
||||
var antiModchip = new PSXAntiModchip();
|
||||
var antiModchip = new BinaryObjectScanner.Protection.PSXAntiModchip();
|
||||
foreach (string file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories))
|
||||
{
|
||||
try
|
||||
@@ -142,9 +140,15 @@ namespace MPF.Core
|
||||
if (foundProtections.Any(p => p.StartsWith("[Exception opening file")))
|
||||
{
|
||||
foundProtections = foundProtections.Where(p => !p.StartsWith("[Exception opening file"));
|
||||
#if NET40 || NET452 || NET462
|
||||
var tempList = new List<string> { "Exception occurred while scanning [RESCAN NEEDED]" };
|
||||
tempList.AddRange(foundProtections);
|
||||
foundProtections = tempList.OrderBy(p => p);
|
||||
#else
|
||||
foundProtections = foundProtections
|
||||
.Prepend("Exception occurred while scanning [RESCAN NEEDED]")
|
||||
.OrderBy(p => p);
|
||||
#endif
|
||||
}
|
||||
|
||||
// ActiveMARK
|
||||
@@ -225,7 +229,16 @@ namespace MPF.Core
|
||||
.Where(p => p != "Cactus Data Shield 300 (Confirm presence of other CDS-300 files)");
|
||||
|
||||
if (foundProtections.Any(p => !p.StartsWith("SafeDisc")))
|
||||
{
|
||||
#if NET40 || NET452 || NET462
|
||||
var tempList = new List<string>();
|
||||
tempList.AddRange(foundProtections);
|
||||
tempList.Add("Cactus Data Shield 300");
|
||||
foundProtections = tempList;
|
||||
#else
|
||||
foundProtections = foundProtections.Append("Cactus Data Shield 300");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// SafeDisc
|
||||
|
||||
@@ -7,7 +7,6 @@ using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using BinaryObjectScanner;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.Modules;
|
||||
using Newtonsoft.Json;
|
||||
@@ -90,8 +89,12 @@ namespace MPF.Core
|
||||
|
||||
// Loop through and get the main node, if possible
|
||||
XmlNode? mainNode = null;
|
||||
foreach (XmlNode tempNode in bodyNode.ChildNodes)
|
||||
foreach (XmlNode? tempNode in bodyNode.ChildNodes)
|
||||
{
|
||||
// Invalid nodes are skipped
|
||||
if (tempNode == null)
|
||||
continue;
|
||||
|
||||
// We only care about div elements
|
||||
if (!string.Equals(tempNode.Name, "div", StringComparison.OrdinalIgnoreCase))
|
||||
continue;
|
||||
@@ -113,8 +116,12 @@ namespace MPF.Core
|
||||
return null;
|
||||
|
||||
// Try to find elements as we're going
|
||||
foreach (XmlNode childNode in mainNode.ChildNodes)
|
||||
foreach (XmlNode? childNode in mainNode.ChildNodes)
|
||||
{
|
||||
// Invalid nodes are skipped
|
||||
if (childNode == null)
|
||||
continue;
|
||||
|
||||
// The title is the only thing in h1 tags
|
||||
if (string.Equals(childNode.Name, "h1", StringComparison.OrdinalIgnoreCase))
|
||||
info.CommonDiscInfo.Title = childNode.InnerText;
|
||||
@@ -132,8 +139,12 @@ namespace MPF.Core
|
||||
continue;
|
||||
|
||||
// The game node contains multiple other elements
|
||||
foreach (XmlNode gameNode in childNode.ChildNodes)
|
||||
foreach (XmlNode? gameNode in childNode.ChildNodes)
|
||||
{
|
||||
// Invalid nodes are skipped
|
||||
if (gameNode == null)
|
||||
continue;
|
||||
|
||||
// Table elements contain multiple other parts of information
|
||||
if (string.Equals(gameNode.Name, "table", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
@@ -150,8 +161,12 @@ namespace MPF.Core
|
||||
continue;
|
||||
|
||||
// Loop through each of the rows
|
||||
foreach (XmlNode gameInfoNode in gameNode.ChildNodes)
|
||||
foreach (XmlNode? gameInfoNode in gameNode.ChildNodes)
|
||||
{
|
||||
// Invalid nodes are skipped
|
||||
if (gameInfoNode == null)
|
||||
continue;
|
||||
|
||||
// If we run into anything not a row, ignore it
|
||||
if (!string.Equals(gameInfoNode.Name, "tr", StringComparison.OrdinalIgnoreCase))
|
||||
continue;
|
||||
@@ -288,7 +303,7 @@ namespace MPF.Core
|
||||
Data.Options options,
|
||||
BaseParameters? parameters,
|
||||
IProgress<Result>? resultProgress = null,
|
||||
IProgress<ProtectionProgress>? protectionProgress = null)
|
||||
IProgress<BinaryObjectScanner.ProtectionProgress>? protectionProgress = null)
|
||||
{
|
||||
// Ensure the current disc combination should exist
|
||||
if (!system.MediaTypes().Contains(mediaType))
|
||||
@@ -692,12 +707,20 @@ namespace MPF.Core
|
||||
/// <param name="info">Existing SubmissionInfo object to fill</param>
|
||||
/// <param name="id">Redump disc ID to retrieve</param>
|
||||
/// <param name="includeAllData">True to include all pullable information, false to do bare minimum</param>
|
||||
#if NETFRAMEWORK
|
||||
public async static Task<bool> FillFromId(RedumpWebClient wc, SubmissionInfo info, int id, bool includeAllData)
|
||||
#else
|
||||
public async static Task<bool> FillFromId(RedumpHttpClient wc, SubmissionInfo info, int id, bool includeAllData)
|
||||
#endif
|
||||
{
|
||||
// Ensure that required sections exist
|
||||
info = EnsureAllSections(info);
|
||||
|
||||
#if NETFRAMEWORK
|
||||
var discData = await Task.Run(() => wc.DownloadSingleSiteID(id));
|
||||
#else
|
||||
var discData = await wc.DownloadSingleSiteID(id);
|
||||
#endif
|
||||
if (string.IsNullOrEmpty(discData))
|
||||
return false;
|
||||
|
||||
@@ -711,7 +734,7 @@ namespace MPF.Core
|
||||
int firstParenLocation = title.IndexOf(" (");
|
||||
if (firstParenLocation >= 0)
|
||||
{
|
||||
info.CommonDiscInfo!.Title = title[..firstParenLocation];
|
||||
info.CommonDiscInfo!.Title = title.Substring(0, firstParenLocation);
|
||||
var subMatches = Constants.DiscNumberLetterRegex.Matches(title);
|
||||
foreach (Match subMatch in subMatches.Cast<Match>())
|
||||
{
|
||||
@@ -1069,12 +1092,17 @@ namespace MPF.Core
|
||||
|
||||
// Set the current dumper based on username
|
||||
info.DumpersAndStatus ??= new DumpersAndStatusSection();
|
||||
info.DumpersAndStatus.Dumpers = new string[] { options.RedumpUsername };
|
||||
info.DumpersAndStatus.Dumpers = [options.RedumpUsername!];
|
||||
info.PartiallyMatchedIDs = new List<int>();
|
||||
|
||||
// Login to Redump
|
||||
#if NETFRAMEWORK
|
||||
using var wc = new RedumpWebClient();
|
||||
bool? loggedIn = wc.Login(options.RedumpUsername!, options.RedumpPassword!);
|
||||
#else
|
||||
using var wc = new RedumpHttpClient();
|
||||
bool? loggedIn = await wc.Login(options.RedumpUsername, options.RedumpPassword);
|
||||
#endif
|
||||
if (loggedIn == null)
|
||||
{
|
||||
resultProgress?.Report(Result.Failure("There was an unknown error connecting to Redump"));
|
||||
@@ -1094,7 +1122,11 @@ namespace MPF.Core
|
||||
resultProgress?.Report(Result.Success("Finding disc matches on Redump..."));
|
||||
var splitData = info.TracksAndWriteOffsets?.ClrMameProData?.TrimEnd('\n')?.Split('\n');
|
||||
int trackCount = splitData?.Length ?? 0;
|
||||
#if NET40 || NET452
|
||||
foreach (string hashData in splitData ?? [])
|
||||
#else
|
||||
foreach (string hashData in splitData ?? Array.Empty<string>())
|
||||
#endif
|
||||
{
|
||||
// Catch any errant blank lines
|
||||
if (string.IsNullOrWhiteSpace(hashData))
|
||||
@@ -1270,7 +1302,7 @@ namespace MPF.Core
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
@@ -1342,7 +1374,11 @@ namespace MPF.Core
|
||||
/// <param name="query">Query string to attempt to search for</param>
|
||||
/// <param name="filterForwardSlashes">True to filter forward slashes, false otherwise</param>
|
||||
/// <returns>All disc IDs for the given query, null on error</returns>
|
||||
#if NETFRAMEWORK
|
||||
private async static Task<List<int>?> ListSearchResults(RedumpWebClient wc, string? query, bool filterForwardSlashes = true)
|
||||
#else
|
||||
private async static Task<List<int>?> ListSearchResults(RedumpHttpClient wc, string? query, bool filterForwardSlashes = true)
|
||||
#endif
|
||||
{
|
||||
// If there is an invalid query
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
@@ -1351,7 +1387,7 @@ namespace MPF.Core
|
||||
var ids = new List<int>();
|
||||
|
||||
// Strip quotes
|
||||
query = query.Trim('"', '\'');
|
||||
query = query!.Trim('"', '\'');
|
||||
|
||||
// Special characters become dashes
|
||||
query = query.Replace(' ', '-');
|
||||
@@ -1368,7 +1404,11 @@ namespace MPF.Core
|
||||
int pageNumber = 1;
|
||||
while (true)
|
||||
{
|
||||
#if NETFRAMEWORK
|
||||
List<int> pageIds = await Task.Run(() => wc.CheckSingleSitePage(string.Format(Constants.QuickSearchUrl, query, pageNumber++)));
|
||||
#else
|
||||
List<int> pageIds = await wc.CheckSingleSitePage(string.Format(Constants.QuickSearchUrl, query, pageNumber++));
|
||||
#endif
|
||||
ids.AddRange(pageIds);
|
||||
if (pageIds.Count <= 1)
|
||||
break;
|
||||
@@ -1391,7 +1431,11 @@ namespace MPF.Core
|
||||
/// <param name="hashData">DAT-formatted hash data to parse out</param>
|
||||
/// <param name="resultProgress">Optional result progress callback</param>
|
||||
/// <returns>True if the track was found, false otherwise; List of found values, if possible</returns>
|
||||
#if NETFRAMEWORK
|
||||
private async static Task<(bool, List<int>?)> ValidateSingleTrack(RedumpWebClient wc, SubmissionInfo info, string hashData, IProgress<Result>? resultProgress = null)
|
||||
#else
|
||||
private async static Task<(bool, List<int>?)> ValidateSingleTrack(RedumpHttpClient wc, SubmissionInfo info, string hashData, IProgress<Result>? resultProgress = null)
|
||||
#endif
|
||||
{
|
||||
// If the line isn't parseable, we can't validate
|
||||
if (!InfoTool.GetISOHashValues(hashData, out long _, out var _, out var _, out var sha1))
|
||||
@@ -1430,7 +1474,11 @@ namespace MPF.Core
|
||||
/// <param name="info">Existing SubmissionInfo object to fill</param>
|
||||
/// <param name="resultProgress">Optional result progress callback</param>
|
||||
/// <returns>True if the track was found, false otherwise; List of found values, if possible</returns>
|
||||
#if NETFRAMEWORK
|
||||
private async static Task<(bool, List<int>?)> ValidateUniversalHash(RedumpWebClient wc, SubmissionInfo info, IProgress<Result>? resultProgress = null)
|
||||
#else
|
||||
private async static Task<(bool, List<int>?)> ValidateUniversalHash(RedumpHttpClient wc, SubmissionInfo info, IProgress<Result>? resultProgress = null)
|
||||
#endif
|
||||
{
|
||||
// If we don't have special fields
|
||||
if (info.CommonDiscInfo?.CommentsSpecialFields == null)
|
||||
@@ -1448,7 +1496,7 @@ namespace MPF.Core
|
||||
}
|
||||
|
||||
// Format the universal hash for finding within the comments
|
||||
universalHash = $"{universalHash[..^1]}/comments/only";
|
||||
universalHash = $"{universalHash.Substring(0, universalHash.Length - 1)}/comments/only";
|
||||
|
||||
// Get all matching IDs for the hash
|
||||
var newIds = await ListSearchResults(wc, universalHash, filterForwardSlashes: false);
|
||||
@@ -1480,10 +1528,18 @@ namespace MPF.Core
|
||||
/// <param name="id">Redump disc ID to retrieve</param>
|
||||
/// <param name="localCount">Local count of tracks for the current disc</param>
|
||||
/// <returns>True if the track count matches, false otherwise</returns>
|
||||
#if NETFRAMEWORK
|
||||
private async static Task<bool> ValidateTrackCount(RedumpWebClient wc, int id, int localCount)
|
||||
#else
|
||||
private async static Task<bool> ValidateTrackCount(RedumpHttpClient wc, int id, int localCount)
|
||||
#endif
|
||||
{
|
||||
// If we can't pull the remote data, we can't match
|
||||
#if NETFRAMEWORK
|
||||
string? discData = await Task.Run(() => wc.DownloadSingleSiteID(id));
|
||||
#else
|
||||
string? discData = await wc.DownloadSingleSiteID(id);
|
||||
#endif
|
||||
if (string.IsNullOrEmpty(discData))
|
||||
return false;
|
||||
|
||||
@@ -1502,6 +1558,6 @@ namespace MPF.Core
|
||||
return localCount == remoteCount;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1677,10 +1677,10 @@ namespace MPF.Core.UI.ViewModels
|
||||
}
|
||||
|
||||
// Validate that the user explicitly wants an inactive drive to be considered for dumping
|
||||
if (_environment.Drive?.MarkedActive != true && _displayUserMessage != null)
|
||||
if (_environment?.Drive?.MarkedActive != true && _displayUserMessage != null)
|
||||
{
|
||||
string message = "The currently selected drive does not appear to contain a disc! "
|
||||
+ (!_environment.System.DetectedByWindows() ? $"This is normal for {_environment.System.LongName()} as the discs may not be readable on Windows. " : string.Empty)
|
||||
+ (!_environment!.System.DetectedByWindows() ? $"This is normal for {_environment.System.LongName()} as the discs may not be readable on Windows. " : string.Empty)
|
||||
+ "Do you want to continue?";
|
||||
|
||||
bool? mbresult = _displayUserMessage("No Disc Detected", message, 2, false);
|
||||
@@ -1692,7 +1692,7 @@ namespace MPF.Core.UI.ViewModels
|
||||
}
|
||||
|
||||
// Pre-split the output path
|
||||
var outputDirectory = Path.GetDirectoryName(_environment.OutputPath);
|
||||
var outputDirectory = Path.GetDirectoryName(_environment!.OutputPath);
|
||||
string outputFilename = Path.GetFileName(_environment.OutputPath);
|
||||
|
||||
// If a complete dump already exists
|
||||
|
||||
@@ -83,7 +83,11 @@ namespace MPF.Core.UI.ViewModels
|
||||
/// </summary>
|
||||
public static async Task<(bool?, string?)> TestRedumpLogin(string username, string password)
|
||||
{
|
||||
#if NETFRAMEWORK
|
||||
return await Task.Run(() => RedumpWebClient.ValidateCredentials(username, password));
|
||||
#else
|
||||
return await RedumpHttpClient.ValidateCredentials(username, password);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -127,7 +127,7 @@ namespace MPF.Core.Utilities
|
||||
|
||||
foreach (var val in Enum.GetValues(typeof(InternalProgram)))
|
||||
{
|
||||
if (((InternalProgram)val) == InternalProgram.NONE)
|
||||
if (((InternalProgram)val!) == InternalProgram.NONE)
|
||||
continue;
|
||||
|
||||
programs.Add($"{((InternalProgram?)val).LongName()}");
|
||||
|
||||
@@ -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 NET40
|
||||
public static async Task OutputToLog(TextReader reader, object baseClass, EventHandler<Modules.BaseParameters.StringEventArgs>? handler)
|
||||
#else
|
||||
public static async Task OutputToLog(TextReader reader, object baseClass, EventHandler<string>? handler)
|
||||
#endif
|
||||
{
|
||||
// Initialize the required variables
|
||||
char[] buffer = new char[256];
|
||||
@@ -37,15 +41,27 @@ namespace MPF.Core.Utilities
|
||||
string line = new(buffer, 0, read);
|
||||
|
||||
// If we have no newline characters, store in the string builder
|
||||
#if NETFRAMEWORK
|
||||
if (!line.Contains("\r") && !line.Contains("\n"))
|
||||
#else
|
||||
if (!line.Contains('\r') && !line.Contains('\n'))
|
||||
#endif
|
||||
sb.Append(line);
|
||||
|
||||
// If we have a newline, append and log
|
||||
#if NETFRAMEWORK
|
||||
else if (line.Contains("\n") || line.Contains("\r\n"))
|
||||
#else
|
||||
else if (line.Contains('\n') || line.Contains("\r\n"))
|
||||
#endif
|
||||
ProcessNewLines(sb, line, baseClass, handler);
|
||||
|
||||
// If we have a carriage return only, append and log first and last instances
|
||||
#if NETFRAMEWORK
|
||||
else if (line.Contains("\r"))
|
||||
#else
|
||||
else if (line.Contains('\r'))
|
||||
#endif
|
||||
ProcessCarriageReturns(sb, line, baseClass, handler);
|
||||
}
|
||||
}
|
||||
@@ -63,14 +79,22 @@ 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 NET40
|
||||
private static void ProcessNewLines(StringBuilder sb, string line, object baseClass, EventHandler<Modules.BaseParameters.StringEventArgs>? 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');
|
||||
for (int i = 0; i < split.Length; i++)
|
||||
{
|
||||
// If the chunk contains a carriage return, handle it like a separate line
|
||||
#if NETFRAMEWORK
|
||||
if (split[i].Contains("\r"))
|
||||
#else
|
||||
if (split[i].Contains('\r'))
|
||||
#endif
|
||||
{
|
||||
ProcessCarriageReturns(sb, split[i], baseClass, handler);
|
||||
continue;
|
||||
@@ -105,7 +129,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 NET40
|
||||
private static void ProcessCarriageReturns(StringBuilder sb, string line, object baseClass, EventHandler<Modules.BaseParameters.StringEventArgs>? handler)
|
||||
#else
|
||||
private static void ProcessCarriageReturns(StringBuilder sb, string line, object baseClass, EventHandler<string>? handler)
|
||||
#endif
|
||||
{
|
||||
var split = line.Split('\r');
|
||||
|
||||
@@ -115,7 +143,7 @@ namespace MPF.Core.Utilities
|
||||
|
||||
// Append the last
|
||||
sb.Clear();
|
||||
sb.Append($"\r{split[^1]}");
|
||||
sb.Append($"\r{split[split.Length - 1]}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,7 +236,8 @@ 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");
|
||||
var latestReleaseJsonString = hc.Send(message)?.Content?.ReadAsStringAsync().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
var latestReleaseJsonString = hc.SendAsync(message)?.ConfigureAwait(false).GetAwaiter().GetResult()
|
||||
.Content?.ReadAsStringAsync().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
if (latestReleaseJsonString == null)
|
||||
return (null, null);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user