diff --git a/CHANGELIST.md b/CHANGELIST.md
index 161aeec7..c0fc15ce 100644
--- a/CHANGELIST.md
+++ b/CHANGELIST.md
@@ -65,6 +65,7 @@
- Update Redumper to build 660
- Use dated default output filenames
- Update packages
+- Scan disc image if not multi-track
### 3.5.0 (2025-10-10)
diff --git a/MPF.Frontend/Tools/ProtectionTool.cs b/MPF.Frontend/Tools/ProtectionTool.cs
index c978a655..5d769c29 100644
--- a/MPF.Frontend/Tools/ProtectionTool.cs
+++ b/MPF.Frontend/Tools/ProtectionTool.cs
@@ -101,6 +101,42 @@ namespace MPF.Frontend.Tools
return found;
}
+ ///
+ /// Run protection scan on a disc image
+ ///
+ /// Image path to scan for protection
+ /// Options object that determines what to scan
+ /// Optional progress callback
+ /// Set of all detected copy protections with an optional error string
+ public static async Task>> RunProtectionScanOnImage(string image,
+ Options options,
+ IProgress? progress = null)
+ {
+#if NET40
+ var found = await Task.Factory.StartNew(() =>
+#else
+ var found = await Task.Run(() =>
+#endif
+ {
+ var scanner = new Scanner(
+ false, // Disable extracting disc images for now
+ scanContents: false, // Disabled for image scanning
+ scanPaths: false, // Disabled for image scanning
+ scanSubdirectories: false, // Disabled for image scanning
+ options.IncludeDebugProtectionInformation,
+ progress);
+
+ return scanner.GetProtections(image);
+ });
+
+ // If nothing was returned, return
+ if (found == null || found.Count == 0)
+ return [];
+
+ // Return the filtered set of protections
+ return found;
+ }
+
///
/// Format found protections to a deduplicated, ordered string
///
@@ -124,7 +160,7 @@ namespace MPF.Frontend.Tools
{
if (value.Count == 0)
continue;
-
+
foreach (var prot in value)
{
if (!protectionValues.Contains(prot))
@@ -137,7 +173,7 @@ namespace MPF.Frontend.Tools
.Distinct()
.ToList();
#endif
-
+
// Sanitize and join protections for writing
string protectionString = SanitizeFoundProtections(protectionValues);
if (string.IsNullOrEmpty(protectionString))
@@ -427,7 +463,7 @@ namespace MPF.Frontend.Tools
.FindAll(p => p != "SafeDisc 2+");
}
- // Best case for SafeDisc 1.X: A full SafeDisc version is found that isn't part of a version range.
+ // Best case for SafeDisc 1.X: A full SafeDisc version is found that isn't part of a version range.
else if (foundProtections.Exists(p => Regex.IsMatch(p, @"SafeDisc 1\.[0-9]{2}\.[0-9]{3}$", RegexOptions.Compiled)
&& !Regex.IsMatch(p, @"SafeDisc 1\.[0-9]{2}\.[0-9]{3}-[0-9]\.[0-9]{2}\.[0-9]{3}", RegexOptions.Compiled)))
{
diff --git a/MPF.Frontend/Tools/SubmissionGenerator.cs b/MPF.Frontend/Tools/SubmissionGenerator.cs
index d0b76954..ed7c57e9 100644
--- a/MPF.Frontend/Tools/SubmissionGenerator.cs
+++ b/MPF.Frontend/Tools/SubmissionGenerator.cs
@@ -130,8 +130,37 @@ namespace MPF.Frontend.Tools
Dictionary>? protections = null;
try
{
- if (options.ScanForProtection && drive?.Name != null)
- protections = await ProtectionTool.RunProtectionScanOnPath(drive.Name, options, protectionProgress);
+ if (options.ScanForProtection)
+ {
+ // Scan the mounted drive path
+ if (drive?.Name != null)
+ protections = await ProtectionTool.RunProtectionScanOnPath(drive.Name, options, protectionProgress);
+
+ // Scan the disc image, if possible
+ Dictionary> imageProtections = [];
+ if (File.Exists($"{basePath}.iso"))
+ {
+ imageProtections = await ProtectionTool.RunProtectionScanOnImage($"{basePath}.iso", options, protectionProgress);
+ }
+ else if (File.Exists($"{basePath}.bin"))
+ {
+ imageProtections = await ProtectionTool.RunProtectionScanOnImage($"{basePath}.bin", options, protectionProgress);
+ }
+ // TODO: Add scanning for multi-track images based on cue parsing
+
+ // Add image protections, if any exist
+ if (imageProtections.Count > 0)
+ {
+ protections = [];
+ foreach (var kvp in imageProtections)
+ {
+ if (!protections.ContainsKey(kvp.Key))
+ protections[kvp.Key] = [];
+
+ protections[kvp.Key].AddRange(kvp.Value);
+ }
+ }
+ }
var protectionString = ProtectionTool.FormatProtections(protections);