mirror of
https://github.com/SabreTools/MPF.git
synced 2026-07-02 17:24:48 +00:00
Improve system detection (#792)
* Improve Sega system detection * Fix namespace * Ignore exception * Add Sega CD header * Improve system detection * Amiga CD check * Improve 3DO and Mac detection * Remove unused parameter * Try determine system even when drive inactive * Better logic for inactive drives * scope issues * GameWave and VIS * Fix Neo Geo CD system check * use var * put physicaltool behind try catch * better use var
This commit is contained in:
@@ -124,6 +124,7 @@
|
||||
- Check for partial dumps
|
||||
- Slightly reduce nesting of file pre-dump checks
|
||||
- Slightly increase nesting of file pre-dump checks
|
||||
- Improve system detection
|
||||
|
||||
### 3.2.4 (2024-11-24)
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SabreTools.IO;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
|
||||
namespace MPF.Frontend.Tools
|
||||
{
|
||||
@@ -12,7 +13,7 @@ namespace MPF.Frontend.Tools
|
||||
{
|
||||
#region Generic
|
||||
|
||||
/// <summary>s
|
||||
/// <summary>
|
||||
/// Get the last modified date for a file from a physical disc, if possible
|
||||
/// </summary>
|
||||
/// <param name="drive">Drive to extract information from</param>
|
||||
@@ -53,6 +54,45 @@ namespace MPF.Frontend.Tools
|
||||
return dt.ToString("yyyy-MM-dd");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the first numBytes bytes from a disc drive
|
||||
/// </summary>
|
||||
/// <param name="drive">Drive to get sector from</param>
|
||||
/// <param name="numBytes">Number of bytes to read from drive, maximum of one sector (2048 bytes)</param>
|
||||
/// <returns>Byte array of first sector of data, null on error</returns>
|
||||
public static byte[]? GetFirstBytes(Drive? drive, int numBytes)
|
||||
{
|
||||
if (drive == null || drive.Letter == null || drive.Letter == '\0')
|
||||
return null;
|
||||
|
||||
// Must read between 1 and 2048 bytes
|
||||
if (numBytes < 1)
|
||||
return null;
|
||||
else if (numBytes > 2048)
|
||||
numBytes = 2048;
|
||||
|
||||
string drivePath = $"\\\\.\\{drive.Letter}:";
|
||||
var firstSector = new byte[numBytes];
|
||||
try
|
||||
{
|
||||
// Open the drive as a raw device
|
||||
using (FileStream driveStream = new FileStream(drivePath, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
// Read the first sector
|
||||
int bytesRead = driveStream.Read(firstSector, 0, numBytes);
|
||||
if (bytesRead < numBytes)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error is
|
||||
return null;
|
||||
}
|
||||
|
||||
return firstSector;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region BD-Video
|
||||
@@ -699,5 +739,66 @@ namespace MPF.Frontend.Tools
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Sega
|
||||
|
||||
/// <summary>
|
||||
/// Detect the Sega system based on the CD ROM header
|
||||
/// </summary>
|
||||
/// <param name="drive">Drive to detect system from</param>
|
||||
/// <returns>Detected RedumpSystem if detected, null otherwise</returns>
|
||||
public static RedumpSystem? DetectSegaSystem(Drive? drive)
|
||||
{
|
||||
if (drive == null)
|
||||
return null;
|
||||
|
||||
byte[]? firstSector = GetFirstBytes(drive, 0x10);
|
||||
if (firstSector == null || firstSector.Length < 0x10)
|
||||
return null;
|
||||
|
||||
string systemType = Encoding.ASCII.GetString(firstSector, 0x00, 0x10);
|
||||
|
||||
if (systemType.Equals("SEGA SEGASATURN ", StringComparison.Ordinal))
|
||||
return RedumpSystem.SegaSaturn;
|
||||
else if (systemType.Equals("SEGA SEGAKATANA ", StringComparison.Ordinal))
|
||||
return RedumpSystem.SegaDreamcast;
|
||||
else if (systemType.Equals("SEGADISCSYSTEM ", StringComparison.Ordinal))
|
||||
return RedumpSystem.SegaMegaCDSegaCD;
|
||||
else if (systemType.Equals("SEGA MEGA DRIVE ", StringComparison.Ordinal))
|
||||
return RedumpSystem.SegaMegaCDSegaCD;
|
||||
else if (systemType.Equals("SEGA GENESIS ", StringComparison.Ordinal))
|
||||
return RedumpSystem.SegaMegaCDSegaCD;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Other
|
||||
|
||||
/// <summary>
|
||||
/// Detect a 3DO disc based on the CD ROM header
|
||||
/// </summary>
|
||||
/// <param name="drive">Drive to detect 3DO disc from</param>
|
||||
/// <returns>RedumpSystem.Panasonic3DOInteractiveMultiplayer if detected, null otherwise</returns>
|
||||
public static RedumpSystem? Detect3DOSystem(Drive? drive)
|
||||
{
|
||||
if (drive == null)
|
||||
return null;
|
||||
|
||||
byte[]? firstSector = GetFirstBytes(drive, 0xC0);
|
||||
if (firstSector == null || firstSector.Length < 0xC0)
|
||||
return null;
|
||||
|
||||
string systemType = Encoding.ASCII.GetString(firstSector, 0xB0, 0x10);
|
||||
|
||||
if (systemType.Equals("iamaduckiamaduck", StringComparison.Ordinal))
|
||||
return RedumpSystem.Panasonic3DOInteractiveMultiplayer;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -663,8 +663,7 @@ namespace MPF.Frontend.ViewModels
|
||||
CopyProtectScanButtonEnabled = true;
|
||||
|
||||
// Get the current system type
|
||||
if (index != -1)
|
||||
DetermineSystemType();
|
||||
DetermineSystemType();
|
||||
|
||||
// Only enable the start/stop if we don't have the default selected
|
||||
StartStopButtonEnabled = ShouldEnableDumpingButton();
|
||||
@@ -1256,16 +1255,27 @@ namespace MPF.Frontend.ViewModels
|
||||
{
|
||||
VerboseLogLn("Skipping system type detection because no valid drives found!");
|
||||
}
|
||||
else if (CurrentDrive?.MarkedActive != true)
|
||||
{
|
||||
VerboseLogLn("Skipping system type detection because drive not marked as active!");
|
||||
}
|
||||
else if (!Options.SkipSystemDetection)
|
||||
{
|
||||
VerboseLog($"Trying to detect system for drive {CurrentDrive.Name}.. ");
|
||||
var currentSystem = GetRedumpSystem(CurrentDrive);
|
||||
VerboseLogLn(currentSystem == null ? $"unable to detect, defaulting to {Options.DefaultSystem.LongName()}" : ($"detected {currentSystem.LongName()}."));
|
||||
currentSystem ??= Options.DefaultSystem;
|
||||
|
||||
// If undetected system on inactive drive, and PC is the default system, check for potential Mac disc
|
||||
if (currentSystem == null && CurrentDrive.MarkedActive == false && Options.DefaultSystem == RedumpSystem.IBMPCcompatible)
|
||||
{
|
||||
try
|
||||
{
|
||||
// If disc is readable on inactive drive, assume it is a Mac disc
|
||||
if (PhysicalTool.GetFirstBytes(CurrentDrive, 1) != null)
|
||||
currentSystem = RedumpSystem.AppleMacintosh;
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
|
||||
// Fallback to default system only if drive is active
|
||||
if (currentSystem == null && CurrentDrive.MarkedActive)
|
||||
currentSystem = Options.DefaultSystem;
|
||||
|
||||
if (currentSystem != null)
|
||||
{
|
||||
@@ -1466,12 +1476,33 @@ namespace MPF.Frontend.ViewModels
|
||||
private static RedumpSystem? GetRedumpSystem(Drive? drive)
|
||||
{
|
||||
// If the drive does not exist, we can't do anything
|
||||
if (drive == null)
|
||||
if (drive == null || string.IsNullOrEmpty(drive.Name))
|
||||
return null;
|
||||
|
||||
// If we can't read the media in that drive, we can't do anything
|
||||
if (string.IsNullOrEmpty(drive.Name) || !Directory.Exists(drive.Name))
|
||||
// If we can't read the files in the drive, we can only perform physical checks
|
||||
if (drive.MarkedActive == false || !Directory.Exists(drive.Name))
|
||||
{
|
||||
try
|
||||
{
|
||||
// Check for Panasonic 3DO - filesystem not readable on Windows
|
||||
RedumpSystem? detected3DOSystem = PhysicalTool.Detect3DOSystem(drive);
|
||||
if (detected3DOSystem != null)
|
||||
{
|
||||
return detected3DOSystem;
|
||||
}
|
||||
|
||||
// Sega Saturn / Sega Dreamcast / Sega Mega-CD / Sega-CD
|
||||
RedumpSystem? detectedSegaSystem = PhysicalTool.DetectSegaSystem(drive);
|
||||
if (detectedSegaSystem != null)
|
||||
{
|
||||
return detectedSegaSystem;
|
||||
}
|
||||
}
|
||||
catch {}
|
||||
|
||||
// Otherwise, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
// We're going to assume for floppies, HDDs, and removable drives
|
||||
if (drive.InternalDriveType != InternalDriveType.Optical)
|
||||
@@ -1550,6 +1581,12 @@ namespace MPF.Frontend.ViewModels
|
||||
return RedumpSystem.MattelFisherPriceiXL;
|
||||
}
|
||||
|
||||
// Memorex - Visual Information System
|
||||
if (File.Exists(Path.Combine(drive.Name, "CONTROL.TAT")))
|
||||
{
|
||||
return RedumpSystem.MemorexVisualInformationSystem;
|
||||
}
|
||||
|
||||
// Microsoft Xbox 360
|
||||
try
|
||||
{
|
||||
@@ -1603,6 +1640,17 @@ namespace MPF.Frontend.ViewModels
|
||||
}
|
||||
catch { }
|
||||
|
||||
try
|
||||
{
|
||||
// Sega Saturn / Sega Dreamcast / Sega Mega-CD / Sega-CD
|
||||
RedumpSystem? segaSystem = PhysicalTool.DetectSegaSystem(drive);
|
||||
if (segaSystem != null)
|
||||
{
|
||||
return segaSystem;
|
||||
}
|
||||
}
|
||||
catch {}
|
||||
|
||||
// Sega Dreamcast
|
||||
if (File.Exists(Path.Combine(drive.Name, "IP.BIN")))
|
||||
{
|
||||
@@ -1625,6 +1673,19 @@ namespace MPF.Frontend.ViewModels
|
||||
return RedumpSystem.SegaMegaCDSegaCD;
|
||||
}
|
||||
|
||||
// SNK Neo-Geo CD
|
||||
try
|
||||
{
|
||||
if (File.Exists(Path.Combine(drive.Name, "ABS.TXT"))
|
||||
|| File.Exists(Path.Combine(drive.Name, "BIB.TXT"))
|
||||
|| File.Exists(Path.Combine(drive.Name, "CPY.TXT"))
|
||||
|| File.Exists(Path.Combine(drive.Name, "IPL.TXT")))
|
||||
{
|
||||
return RedumpSystem.SNKNeoGeoCD;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Sony PlayStation and Sony PlayStation 2
|
||||
string psxExePath = Path.Combine(drive.Name, "PSX.EXE");
|
||||
string systemCnfPath = Path.Combine(drive.Name, "SYSTEM.CNF");
|
||||
@@ -1655,17 +1716,6 @@ namespace MPF.Frontend.ViewModels
|
||||
catch { }
|
||||
|
||||
// Sony PlayStation 4
|
||||
// There are more possible paths that could be checked.
|
||||
// There are some entries that can be found on most PS4 discs:
|
||||
// "/app/GAME_SERIAL/app.pkg"
|
||||
// "/bd/param.sfo"
|
||||
// "/license/rif"
|
||||
// There are also extra files that can be found on some discs:
|
||||
// "/patch/GAME_SERIAL/patch.pkg" can be found in Redump entry 66816.
|
||||
// Originally on disc as "/patch/CUSA11302/patch.pkg".
|
||||
// Is used as an on-disc update for the base game app without needing to get update from the internet.
|
||||
// "/addcont/GAME_SERIAL/CONTENT_ID/ac.pkg" can be found in Redump entry 97619.
|
||||
// Originally on disc as "/addcont/CUSA00288/FFXIVEXPS400001A/ac.pkg".
|
||||
#if NET20 || NET35
|
||||
if (File.Exists(Path.Combine(Path.Combine(Path.Combine(drive.Name, "PS4"), "UPDATE"), "PS4UPDATE.PUP")))
|
||||
#else
|
||||
@@ -1675,16 +1725,60 @@ namespace MPF.Frontend.ViewModels
|
||||
return RedumpSystem.SonyPlayStation4;
|
||||
}
|
||||
|
||||
// Sony PlayStation 5
|
||||
#if NET20 || NET35
|
||||
if (File.Exists(Path.Combine(Path.Combine(Path.Combine(drive.Name, "PS5"), "UPDATE"), "PS5UPDATE.PUP")))
|
||||
#else
|
||||
if (File.Exists(Path.Combine(drive.Name, "PS5", "UPDATE", "PS5UPDATE.PUP")))
|
||||
#endif
|
||||
{
|
||||
return RedumpSystem.SonyPlayStation5;
|
||||
}
|
||||
|
||||
// V.Tech V.Flash / V.Smile Pro
|
||||
if (File.Exists(Path.Combine(drive.Name, "0SYSTEM")))
|
||||
{
|
||||
return RedumpSystem.VTechVFlashVSmilePro;
|
||||
}
|
||||
|
||||
// VM Labs NUON
|
||||
#if NET20 || NET35
|
||||
if (File.Exists(Path.Combine(Path.Combine(drive.Name, "NUON"), "nuon.run")))
|
||||
#else
|
||||
if (File.Exists(Path.Combine(drive.Name, "NUON", "nuon.run")))
|
||||
#endif
|
||||
{
|
||||
return RedumpSystem.VMLabsNUON;
|
||||
}
|
||||
|
||||
// ZAPit Games - GameWave
|
||||
if (File.Exists(Path.Combine(drive.Name, "gamewave.diz")))
|
||||
{
|
||||
return RedumpSystem.ZAPiTGamesGameWaveFamilyEntertainmentSystem;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Computers
|
||||
|
||||
// Amiga CD (Do this check AFTER CD32/CDTV)
|
||||
if (File.Exists(Path.Combine(drive.Name, "Disk.info")))
|
||||
{
|
||||
return RedumpSystem.CommodoreAmigaCD;
|
||||
}
|
||||
|
||||
// Fujitsu FM Towns
|
||||
try
|
||||
{
|
||||
if (File.Exists(Path.Combine(drive.Name, "TMENU.EXP"))
|
||||
|| File.Exists(Path.Combine(drive.Name, "TBIOS.SYS"))
|
||||
|| File.Exists(Path.Combine(drive.Name, "TBIOS.BIN")))
|
||||
{
|
||||
return RedumpSystem.FujitsuFMTownsseries;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Sharp X68000
|
||||
if (File.Exists(Path.Combine(drive.Name, "COMMAND.X")))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user