mirror of
https://github.com/SabreTools/MPF.git
synced 2026-02-04 05:35:52 +00:00
Support reparsing of MPF-processed outputs (#896)
* Have a go at extracting files from existing log * no null output dir * Extract log from archive if it is zipped during mediatype detection * imports * fix variable names * fix null output dir * Final fixes * changelist * assign null * fix
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
- Move Zstd compression helper to base processor
|
||||
- Add file merge method in CleanRip
|
||||
- Implement file merging in CleanRip
|
||||
- Support reparsing of MPF-processed outputs
|
||||
|
||||
### 3.5.0 (2025-10-10)
|
||||
|
||||
|
||||
@@ -59,11 +59,15 @@ namespace MPF.Frontend.Tools
|
||||
List<string> missingFiles = processor.FoundAllFiles(mediaType, outputDirectory, outputFilename);
|
||||
if (missingFiles.Count > 0)
|
||||
{
|
||||
resultProgress?.Report(ResultEventArgs.Failure($"There were files missing from the output:\n{string.Join("\n", [.. missingFiles])}"));
|
||||
resultProgress?.Report(ResultEventArgs.Failure($"This may indicate an issue with the hardware or media, including unsupported devices.\nPlease see dumping program documentation for more details."));
|
||||
return null;
|
||||
resultProgress?.Report(ResultEventArgs.Failure($"There were files missing from the output:\n{string.Join("\n", [.. missingFiles])}\nThis may indicate an issue with the hardware or media, including unsupported devices.\nPlease see dumping program documentation for more details."));
|
||||
return null;
|
||||
}
|
||||
|
||||
// Extract files from existing log archive, if it exists
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
processor.ExtractFromLogs(mediaType, outputDirectory, outputFilename);
|
||||
#endif
|
||||
|
||||
// Assemble a base path
|
||||
string basePath = Path.GetFileNameWithoutExtension(outputFilename);
|
||||
if (!string.IsNullOrEmpty(outputDirectory))
|
||||
|
||||
@@ -161,7 +161,7 @@ namespace MPF.Processors.Test
|
||||
string outputFilename = string.Empty;
|
||||
var processor = new Redumper(RedumpSystem.IBMPCcompatible);
|
||||
var actual = processor.FoundAllFiles(MediaType.CDROM, outputDirectory, outputFilename);
|
||||
Assert.Equal(7, actual.Count);
|
||||
Assert.Equal(5, actual.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -10,6 +10,10 @@ using SabreTools.Data.Models.Logiqx;
|
||||
using SabreTools.RedumpLib;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
using Schemas;
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
using System.Linq;
|
||||
using SharpCompress.Archives.Zip;
|
||||
#endif
|
||||
|
||||
#pragma warning disable CS0618 // Ignore "Type or member is obsolete"
|
||||
#pragma warning disable IDE0059 // Unnecessary assignment of a value
|
||||
@@ -38,6 +42,31 @@ namespace MPF.Processors
|
||||
if (!string.IsNullOrEmpty(outputDirectory))
|
||||
basePath = Path.Combine(outputDirectory, basePath);
|
||||
|
||||
// Extract sidecar from archive, if it is zipped
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
if (File.Exists($"{basePath}_logs.zip"))
|
||||
{
|
||||
ZipArchive? logArchive = null;
|
||||
try
|
||||
{
|
||||
logArchive = ZipArchive.Open($"{basePath}_logs.zip");
|
||||
string sidecarFilename = $"{Path.GetFileNameWithoutExtension(outputFilename)}.cicm.xml";
|
||||
var sidecarFile = logArchive.Entries.FirstOrDefault(e => e.Key == sidecarFilename);
|
||||
if (sidecarFile != null && !sidecarFile.IsDirectory)
|
||||
{
|
||||
string sidecarPath = sidecarFilename;
|
||||
if (!string.IsNullOrEmpty(outputDirectory))
|
||||
sidecarPath = Path.Combine(outputDirectory, sidecarFilename);
|
||||
using var entryStream = sidecarFile.OpenEntryStream();
|
||||
using var fileStream = File.Create(sidecarPath);
|
||||
entryStream.CopyTo(fileStream);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
logArchive?.Dispose();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Deserialize the sidecar, if possible
|
||||
var sidecar = GenerateSidecar($"{basePath}.cicm.xml");
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace MPF.Processors
|
||||
/// <param name="redumpCompat">Determines if outputs are processed according to Redump specifications</param>
|
||||
public abstract void GenerateSubmissionInfo(SubmissionInfo submissionInfo, MediaType? mediaType, string basePath, bool redumpCompat);
|
||||
|
||||
// <summary>
|
||||
/// <summary>
|
||||
/// Generate a list of all output files generated
|
||||
/// </summary>
|
||||
/// <param name="mediaType">Media type for controlling expected file sets</param>
|
||||
@@ -291,6 +291,59 @@ namespace MPF.Processors
|
||||
return missingFiles;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts found files from a found archive if it exists
|
||||
/// </summary>
|
||||
/// <param name="mediaType">Media type for controlling expected file sets</param>
|
||||
/// <param name="outputDirectory">Output folder to use as the base path</param>
|
||||
/// <param name="outputFilename">Output filename to use as the base path</param>
|
||||
/// <remarks>Assumes filename has an extension</remarks>
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
public void ExtractFromLogs(MediaType? mediaType, string? outputDirectory, string outputFilename)
|
||||
{
|
||||
// Assemble a base path
|
||||
string basePath = Path.GetFileNameWithoutExtension(outputFilename);
|
||||
if (!string.IsNullOrEmpty(outputDirectory))
|
||||
basePath = Path.Combine(outputDirectory, basePath);
|
||||
|
||||
// Get the list of output files
|
||||
var outputFiles = GetOutputFiles(mediaType, outputDirectory, outputFilename);
|
||||
if (outputFiles.Count == 0)
|
||||
return;
|
||||
|
||||
// Check for the log file
|
||||
bool logArchiveExists = false;
|
||||
ZipArchive? logArchive = null;
|
||||
if (File.Exists($"{basePath}_logs.zip"))
|
||||
{
|
||||
logArchiveExists = true;
|
||||
try
|
||||
{
|
||||
// Try to open the archive
|
||||
logArchive = ZipArchive.Open($"{basePath}_logs.zip");
|
||||
}
|
||||
catch
|
||||
{
|
||||
logArchiveExists = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If no archive exists, do no work
|
||||
if (!logArchiveExists)
|
||||
return;
|
||||
|
||||
// Extract all found output files from the archive
|
||||
foreach (var outputFile in outputFiles)
|
||||
{
|
||||
outputFile.Extract(logArchive, outputDirectory ?? string.Empty);
|
||||
}
|
||||
|
||||
// Close the log archive, if it exists
|
||||
logArchive?.Dispose();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that no potential output files have been created
|
||||
/// </summary>
|
||||
|
||||
@@ -8,6 +8,9 @@ using System.Text.RegularExpressions;
|
||||
using SabreTools.Data.Models.Logiqx;
|
||||
using SabreTools.RedumpLib;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
using SharpCompress.Archives.Zip;
|
||||
#endif
|
||||
|
||||
/*
|
||||
If there are no external programs, such as error checking, etc., DIC outputs
|
||||
@@ -79,6 +82,31 @@ namespace MPF.Processors
|
||||
if (!string.IsNullOrEmpty(outputDirectory))
|
||||
basePath = Path.Combine(outputDirectory, basePath);
|
||||
|
||||
// Extract _disc.txt from archive, if it is zipped
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
if (File.Exists($"{basePath}_logs.zip"))
|
||||
{
|
||||
ZipArchive? logArchive = null;
|
||||
try
|
||||
{
|
||||
logArchive = ZipArchive.Open($"{basePath}_logs.zip");
|
||||
string disctxtFilename = $"{Path.GetFileNameWithoutExtension(outputFilename)}_disc.txt";
|
||||
var disctxtFile = logArchive.Entries.FirstOrDefault(e => e.Key == disctxtFilename);
|
||||
if (disctxtFile != null && !disctxtFile.IsDirectory)
|
||||
{
|
||||
string disctxtPath = disctxtFilename;
|
||||
if (!string.IsNullOrEmpty(outputDirectory))
|
||||
disctxtPath = Path.Combine(outputDirectory, disctxtFilename);
|
||||
using var entryStream = disctxtFile.OpenEntryStream();
|
||||
using var fileStream = File.Create(disctxtPath);
|
||||
entryStream.CopyTo(fileStream);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
logArchive?.Dispose();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get the comma-separated list of values
|
||||
if (GetDiscType($"{basePath}_disc.txt", out var discType) && discType != null)
|
||||
{
|
||||
|
||||
@@ -248,6 +248,45 @@ namespace MPF.Processors
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
/// <summary>
|
||||
/// Extracts an output file from a zip archive
|
||||
/// </summary>
|
||||
/// <param name="archive">Zip archive to check in</param>
|
||||
/// <param name="outputDirectory">Base directory to extract to</param>
|
||||
/// <returns>True if file extracted, False otherwise</returns>
|
||||
public virtual bool Extract(ZipArchive? archive, string outputDirectory)
|
||||
{
|
||||
// If the archive is invalid
|
||||
if (archive == null)
|
||||
return false;
|
||||
|
||||
foreach (string filename in Filenames)
|
||||
{
|
||||
// Check for invalid filenames
|
||||
if (string.IsNullOrEmpty(filename))
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
// Check all entries on filename alone
|
||||
var outputFile = archive.Entries.FirstOrDefault(e => e.Key == filename);
|
||||
if (outputFile == null || outputFile.IsDirectory)
|
||||
continue;
|
||||
|
||||
string outputPath = Path.Combine(outputDirectory, filename);
|
||||
|
||||
using var entryStream = outputFile.OpenEntryStream();
|
||||
using var fileStream = File.Create(outputPath);
|
||||
entryStream.CopyTo(fileStream);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Get all matching paths for the file
|
||||
/// </summary>
|
||||
|
||||
@@ -7,6 +7,7 @@ using SabreTools.Hashing;
|
||||
using SabreTools.RedumpLib;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
using System.Linq;
|
||||
using SharpCompress.Archives.Zip;
|
||||
#endif
|
||||
|
||||
@@ -34,6 +35,31 @@ namespace MPF.Processors
|
||||
if (!string.IsNullOrEmpty(outputDirectory))
|
||||
basePath = Path.Combine(outputDirectory, basePath);
|
||||
|
||||
// Extract log from archive, if it is zipped
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
if (File.Exists($"{basePath}_logs.zip"))
|
||||
{
|
||||
ZipArchive? logArchive = null;
|
||||
try
|
||||
{
|
||||
logArchive = ZipArchive.Open($"{basePath}_logs.zip");
|
||||
string logFilename = $"{Path.GetFileNameWithoutExtension(outputFilename)}.log";
|
||||
var logFile = logArchive.Entries.FirstOrDefault(e => e.Key == logFilename);
|
||||
if (logFile != null && !logFile.IsDirectory)
|
||||
{
|
||||
string logPath = logFilename;
|
||||
if (!string.IsNullOrEmpty(outputDirectory))
|
||||
logPath = Path.Combine(outputDirectory, logFilename);
|
||||
using var entryStream = logFile.OpenEntryStream();
|
||||
using var fileStream = File.Create(logPath);
|
||||
entryStream.CopyTo(fileStream);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
logArchive?.Dispose();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Use the log first, if it exists
|
||||
if (GetDiscType($"{basePath}.log", out MediaType? mediaType))
|
||||
return mediaType;
|
||||
@@ -462,8 +488,7 @@ namespace MPF.Processors
|
||||
"cdtext"),
|
||||
new($"{outputFilename}.cue", OutputFileFlags.Required),
|
||||
new($"{outputFilename}.flip", OutputFileFlags.None),
|
||||
new($"{outputFilename}.fulltoc", OutputFileFlags.Required
|
||||
| OutputFileFlags.Binary
|
||||
new($"{outputFilename}.fulltoc", OutputFileFlags.Binary
|
||||
| OutputFileFlags.Zippable,
|
||||
"fulltoc"),
|
||||
new($"{outputFilename}.log", OutputFileFlags.Required
|
||||
@@ -475,8 +500,7 @@ namespace MPF.Processors
|
||||
new($"{outputFilename}.pma", OutputFileFlags.Binary
|
||||
| OutputFileFlags.Zippable,
|
||||
"pma"),
|
||||
new([$"{outputFilename}.scram", $"{outputFilename}.scrap"], OutputFileFlags.Required
|
||||
| OutputFileFlags.Deleteable),
|
||||
new([$"{outputFilename}.scram", $"{outputFilename}.scrap"], OutputFileFlags.Deleteable),
|
||||
// TODO: Required if Zstandard version doesn't exist
|
||||
new($"{outputFilename}.state", OutputFileFlags.Binary
|
||||
| OutputFileFlags.Zippable,
|
||||
|
||||
Reference in New Issue
Block a user