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);