From ee96367a456ccecf22b0aa2a2ade3a1ab3b1a522 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Tue, 20 Aug 2024 12:30:46 -0400 Subject: [PATCH] Support GD-ROM info for Redumper (fixes #741) --- CHANGELIST.md | 1 + MPF.Processors/Redumper.cs | 190 +++++++++++++++++++++++++++++-------- 2 files changed, 153 insertions(+), 38 deletions(-) diff --git a/CHANGELIST.md b/CHANGELIST.md index 15cf0e19..7ee6e6ce 100644 --- a/CHANGELIST.md +++ b/CHANGELIST.md @@ -16,6 +16,7 @@ - Fix cleaning XGD3 SS - Prepare Redumper for XGD support - Hash DMI and PFI files for XGD in Redumper +- Support GD-ROM info for Redumper ### 3.2.1 (2024-08-05) diff --git a/MPF.Processors/Redumper.cs b/MPF.Processors/Redumper.cs index 9c2b72db..e1bd2f5e 100644 --- a/MPF.Processors/Redumper.cs +++ b/MPF.Processors/Redumper.cs @@ -381,7 +381,11 @@ namespace MPF.Processors break; case RedumpSystem.NamcoSegaNintendoTriforce: - // TODO: Support header information and GD-ROM info when generated + info.Extras!.Header = GetGDROMHeader($"{basePath}.log", out var triforceBuildDate, out var triforceSerial, out _) ?? string.Empty; + info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = triforceSerial ?? string.Empty; + info.CommonDiscInfo.EXEDateBuildDate = triforceBuildDate ?? string.Empty; + info.VersionAndEditions!.Version = GetGDROMVersion(info.Extras.Header) ?? string.Empty; + // TODO: Support region setting from parsed value break; case RedumpSystem.SegaMegaCDSegaCD: @@ -392,19 +396,35 @@ namespace MPF.Processors break; case RedumpSystem.SegaChihiro: - // TODO: Support header information and GD-ROM info when generated + info.Extras!.Header = GetGDROMHeader($"{basePath}.log", out var chihiroBuildDate, out var chihiroSerial, out _) ?? string.Empty; + info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = chihiroSerial ?? string.Empty; + info.CommonDiscInfo.EXEDateBuildDate = chihiroBuildDate ?? string.Empty; + info.VersionAndEditions!.Version = GetGDROMVersion(info.Extras.Header) ?? string.Empty; + // TODO: Support region setting from parsed value break; case RedumpSystem.SegaDreamcast: - // TODO: Support header information and GD-ROM info when generated + info.Extras!.Header = GetGDROMHeader($"{basePath}.log", out var dcBuildDate, out var dcSerial, out _) ?? string.Empty; + info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = dcSerial ?? string.Empty; + info.CommonDiscInfo.EXEDateBuildDate = dcBuildDate ?? string.Empty; + info.VersionAndEditions!.Version = GetGDROMVersion(info.Extras.Header) ?? string.Empty; + // TODO: Support region setting from parsed value break; case RedumpSystem.SegaNaomi: - // TODO: Support header information and GD-ROM info when generated + info.Extras!.Header = GetGDROMHeader($"{basePath}.log", out var naomiBuildDate, out var naomiSerial, out _) ?? string.Empty; + info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = naomiSerial ?? string.Empty; + info.CommonDiscInfo.EXEDateBuildDate = naomiBuildDate ?? string.Empty; + info.VersionAndEditions!.Version = GetGDROMVersion(info.Extras.Header) ?? string.Empty; + // TODO: Support region setting from parsed value break; case RedumpSystem.SegaNaomi2: - // TODO: Support header information and GD-ROM info when generated + info.Extras!.Header = GetGDROMHeader($"{basePath}.log", out var naomi2BuildDate, out var naomi2Serial, out _) ?? string.Empty; + info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = naomi2Serial ?? string.Empty; + info.CommonDiscInfo.EXEDateBuildDate = naomi2BuildDate ?? string.Empty; + info.VersionAndEditions!.Version = GetGDROMVersion(info.Extras.Header) ?? string.Empty; + // TODO: Support region setting from parsed value break; case RedumpSystem.SegaSaturn: @@ -832,7 +852,7 @@ namespace MPF.Processors /// /// Log file location /// True if error counts could be retrieved, false otherwise - public static bool GetErrorCount(string log, out long redumpErrors, out long c2Errors) + private static bool GetErrorCount(string log, out long redumpErrors, out long c2Errors) { // Set the default values for error counts redumpErrors = -1; c2Errors = -1; @@ -879,6 +899,100 @@ namespace MPF.Processors } } + /// + /// Get the header from a GD-ROM LD area, if possible + /// + /// Log file location + /// Header as a byte array if possible, null on error + private static string? GetGDROMHeader(string log, out string? buildDate, out string? serial, out string? region) + { + // Set the default values + buildDate = null; serial = null; region = null; + + // If the file doesn't exist, we can't get info from it + if (!File.Exists(log)) + return null; + + try + { + // Fast forward to the MCD line + using var sr = File.OpenText(log); + while (!sr.EndOfStream && sr.ReadLine()?.TrimStart()?.StartsWith("DC [") == false) ; + if (sr.EndOfStream) + return null; + + string? line, headerString = string.Empty; + while (!sr.EndOfStream) + { + line = sr.ReadLine()?.TrimStart(); + if (line == null) + break; + + if (line.StartsWith("build date:")) + { + buildDate = line.Substring("build date: ".Length).Trim(); + } + else if (line.StartsWith("serial:")) + { + serial = line.Substring("serial: ".Length).Trim(); + } + else if (line.StartsWith("region:")) + { + region = line.Substring("region: ".Length).Trim(); + } + else if (line.StartsWith("regions:")) + { + region = line.Substring("regions: ".Length).Trim(); + } + else if (line.StartsWith("header:")) + { + line = sr.ReadLine()?.TrimStart(); + while (line?.StartsWith("00") == true) + { + headerString += line + "\n"; + line = sr.ReadLine()?.Trim(); + } + } + else + { + break; + } + } + + return headerString.TrimEnd('\n'); + } + catch + { + // We don't care what the exception is right now + return null; + } + } + + /// + /// Get the build info from a GD-ROM LD area, if possible + /// + /// <String representing a formatter variant of the GD-ROM header + /// Version on successful extraction of info, null otherwise + private static string? GetGDROMVersion(string? segaHeader) + { + // If the input header is null, we can't do a thing + if (string.IsNullOrEmpty(segaHeader)) + return null; + + // Now read it in cutting it into lines for easier parsing + try + { + string[] header = segaHeader!.Split('\n'); + string versionLine = header[4].Substring(58); + return versionLine.Substring(10, 6).TrimStart('V', 'v'); + } + catch + { + // We don't care what the error is + return null; + } + } + /// /// Get hardware information from the input file, if possible /// @@ -1578,38 +1692,6 @@ namespace MPF.Processors } } - /// - /// Get the write offset from the input file, if possible - /// - /// Log file location - /// Sample write offset if possible, null on error - private static string? GetWriteOffset(string log) - { - // If the file doesn't exist, we can't get info from it - if (!File.Exists(log)) - return null; - - try - { - // If we find the disc write offset line, return the offset - using var sr = File.OpenText(log); - while (!sr.EndOfStream) - { - string? line = sr.ReadLine()?.TrimStart(); - if (line?.StartsWith("disc write offset") == true) - return line.Substring("disc write offset: ".Length).Trim(); - } - - // We couldn't detect it then - return null; - } - catch - { - // We don't care what the exception is right now - return null; - } - } - /// /// Get the version. if possible /// @@ -1708,6 +1790,38 @@ namespace MPF.Processors } } + /// + /// Get the write offset from the input file, if possible + /// + /// Log file location + /// Sample write offset if possible, null on error + private static string? GetWriteOffset(string log) + { + // If the file doesn't exist, we can't get info from it + if (!File.Exists(log)) + return null; + + try + { + // If we find the disc write offset line, return the offset + using var sr = File.OpenText(log); + while (!sr.EndOfStream) + { + string? line = sr.ReadLine()?.TrimStart(); + if (line?.StartsWith("disc write offset") == true) + return line.Substring("disc write offset: ".Length).Trim(); + } + + // We couldn't detect it then + return null; + } + catch + { + // We don't care what the exception is right now + return null; + } + } + #endregion } }