diff --git a/CHANGELIST.md b/CHANGELIST.md
index e3bbc528..4959a82d 100644
--- a/CHANGELIST.md
+++ b/CHANGELIST.md
@@ -3,6 +3,7 @@
- Create currently-unused processors
- Move DataFile to Core.Data
- Seal XBC processor
+- Migrate processor functionality
### 3.1.9a (2024-05-21)
diff --git a/MPF.Core/DumpEnvironment.cs b/MPF.Core/DumpEnvironment.cs
index b17cf899..5f819200 100644
--- a/MPF.Core/DumpEnvironment.cs
+++ b/MPF.Core/DumpEnvironment.cs
@@ -6,6 +6,7 @@ using System.Linq;
using System.Threading.Tasks;
using MPF.Core.Data;
using MPF.Core.Modules;
+using MPF.Core.Processors;
using MPF.Core.Utilities;
using SabreTools.RedumpLib;
using SabreTools.RedumpLib.Data;
@@ -58,6 +59,11 @@ namespace MPF.Core
///
public BaseParameters? Parameters { get; private set; }
+ ///
+ /// Processor object representing post-dump processing
+ ///
+ public BaseProcessor? Processor { get; private set; }
+
#endregion
#region Event Handlers
@@ -128,6 +134,7 @@ namespace MPF.Core
// Dumping program
SetParameters(parameters);
+ SetProcessor();
}
#region Public Functionality
@@ -167,6 +174,28 @@ namespace MPF.Core
}
}
+ ///
+ /// Set the processor object based on the internal program
+ ///
+ public void SetProcessor()
+ {
+ Processor = InternalProgram switch
+ {
+ InternalProgram.Aaru => new Processors.Aaru(System, Type),
+ InternalProgram.CleanRip => new CleanRip(System, Type),
+ InternalProgram.DCDumper => null, // TODO: Create correct parameter type when supported
+ InternalProgram.DiscImageCreator => new DiscImageCreator(System, Type),
+ InternalProgram.PS3CFW => new PS3CFW(System, Type),
+ InternalProgram.Redumper => new Redumper(System, Type),
+ InternalProgram.UmdImageCreator => new UmdImageCreator(System, Type),
+ InternalProgram.XboxBackupCreator => new XboxBackupCreator(System, Type),
+
+ // If no dumping program found, set to null
+ InternalProgram.NONE => null,
+ _ => null,
+ };
+ }
+
///
/// Get the full parameter string for either DiscImageCreator or Aaru
///
@@ -299,7 +328,7 @@ namespace MPF.Core
var outputFilename = Path.GetFileName(OutputPath);
// Check to make sure that the output had all the correct files
- (bool foundFiles, List missingFiles) = Parameters.FoundAllFiles(outputDirectory, outputFilename, false);
+ (bool foundFiles, List missingFiles) = Processor.FoundAllFiles(outputDirectory, outputFilename, false);
if (!foundFiles)
{
resultProgress?.Report(Result.Failure($"There were files missing from the output:\n{string.Join("\n", [.. missingFiles])}"));
@@ -315,6 +344,7 @@ namespace MPF.Core
Type,
Options,
Parameters,
+ Processor,
resultProgress,
protectionProgress);
resultProgress?.Report(Result.Success("Extracting information complete!"));
@@ -408,7 +438,7 @@ namespace MPF.Core
if (Options.CompressLogFiles)
{
resultProgress?.Report(Result.Success("Compressing log files..."));
- (bool compressSuccess, string compressResult) = InfoTool.CompressLogFiles(outputDirectory, filenameSuffix, outputFilename, Parameters);
+ (bool compressSuccess, string compressResult) = InfoTool.CompressLogFiles(outputDirectory, filenameSuffix, outputFilename, Processor);
if (compressSuccess)
resultProgress?.Report(Result.Success(compressResult));
else
@@ -419,7 +449,7 @@ namespace MPF.Core
if (Options.DeleteUnnecessaryFiles)
{
resultProgress?.Report(Result.Success("Deleting unnecessary files..."));
- (bool deleteSuccess, string deleteResult) = InfoTool.DeleteUnnecessaryFiles(outputDirectory, outputFilename, Parameters);
+ (bool deleteSuccess, string deleteResult) = InfoTool.DeleteUnnecessaryFiles(outputDirectory, outputFilename, Processor);
if (deleteSuccess)
resultProgress?.Report(Result.Success(deleteResult));
else
diff --git a/MPF.Core/InfoTool.cs b/MPF.Core/InfoTool.cs
index 7c5b7a90..a085e9ba 100644
--- a/MPF.Core/InfoTool.cs
+++ b/MPF.Core/InfoTool.cs
@@ -11,6 +11,7 @@ using System.Xml.Schema;
using System.Xml.Serialization;
using MPF.Core.Data;
using MPF.Core.Modules;
+using MPF.Core.Processors;
using MPF.Core.Utilities;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -32,13 +33,13 @@ namespace MPF.Core
///
/// Output folder to write to
/// Output filename to use as the base path
- /// Parameters object representing what to send to the internal program
+ /// Processor object representing how to process the outputs
/// True if this is a check done before a dump, false if done after
/// Tuple of true if all required files exist, false otherwise and a list representing missing files
- internal static (bool, List) FoundAllFiles(this BaseParameters? parameters, string? outputDirectory, string outputFilename, bool preCheck)
+ internal static (bool, List) FoundAllFiles(this BaseProcessor? processor, string? outputDirectory, string outputFilename, bool preCheck)
{
// If there are no parameters set
- if (parameters == null)
+ if (processor == null)
return (false, new List());
// First, sanitized the output filename to strip off any potential extension
@@ -52,7 +53,7 @@ namespace MPF.Core
basePath = Path.Combine(outputDirectory, outputFilename);
// Finally, let the parameters say if all files exist
- return parameters.CheckAllOutputFilesExist(basePath, preCheck);
+ return processor.CheckAllOutputFilesExist(basePath, preCheck);
}
///
@@ -1153,15 +1154,15 @@ namespace MPF.Core
/// Output folder to write to
/// Output filename to use as the base path
/// Output filename to use as the base path
- /// Parameters object to use to derive log file paths
+ /// Processor object representing how to process the outputs
/// True if the process succeeded, false otherwise
- public static (bool, string) CompressLogFiles(string? outputDirectory, string? filenameSuffix, string outputFilename, BaseParameters? parameters)
+ public static (bool, string) CompressLogFiles(string? outputDirectory, string? filenameSuffix, string outputFilename, BaseProcessor? processor)
{
#if NET20 || NET35 || NET40
return (false, "Log compression is not available for this framework version");
#else
// If there are no parameters
- if (parameters == null)
+ if (processor == null)
return (false, "No parameters provided!");
// Prepare the necessary paths
@@ -1175,7 +1176,7 @@ namespace MPF.Core
string archiveName = combinedBase + "_logs.zip";
// Get the list of log files from the parameters object
- var files = parameters.GetLogFilePaths(combinedBase);
+ var files = processor.GetLogFilePaths(combinedBase);
// Add on generated log files if they exist
var mpfFiles = GetGeneratedFilePaths(outputDirectory, filenameSuffix);
@@ -1246,12 +1247,12 @@ namespace MPF.Core
///
/// Output folder to write to
/// Output filename to use as the base path
- /// Parameters object to use to derive log file paths
+ /// Processor object representing how to process the outputs
/// True if the process succeeded, false otherwise
- public static (bool, string) DeleteUnnecessaryFiles(string? outputDirectory, string outputFilename, BaseParameters? parameters)
+ public static (bool, string) DeleteUnnecessaryFiles(string? outputDirectory, string outputFilename, BaseProcessor? processor)
{
// If there are no parameters
- if (parameters == null)
+ if (processor == null)
return (false, "No parameters provided!");
// Prepare the necessary paths
@@ -1263,7 +1264,7 @@ namespace MPF.Core
combinedBase = Path.Combine(outputDirectory, outputFilename);
// Get the list of deleteable files from the parameters object
- var files = parameters.GetDeleteableFilePaths(combinedBase);
+ var files = processor.GetDeleteableFilePaths(combinedBase);
if (!files.Any())
return (true, "No files to delete!");
diff --git a/MPF.Core/Modules/Aaru/Parameters.cs b/MPF.Core/Modules/Aaru/Parameters.cs
index ccf12f56..d3fea41b 100644
--- a/MPF.Core/Modules/Aaru/Parameters.cs
+++ b/MPF.Core/Modules/Aaru/Parameters.cs
@@ -1,21 +1,9 @@
using System;
using System.Collections.Generic;
-using System.IO;
using System.Linq;
-using System.Text;
using System.Text.RegularExpressions;
-using System.Xml;
-using System.Xml.Schema;
-using System.Xml.Serialization;
-using MPF.Core.Converters;
using MPF.Core.Data;
-using SabreTools.Models.CueSheets;
-using SabreTools.RedumpLib;
using SabreTools.RedumpLib.Data;
-using Schemas;
-
-#pragma warning disable CS0618 // Ignore "Type or member is obsolete"
-#pragma warning disable IDE0059 // Unnecessary assignment of a value
namespace MPF.Core.Modules.Aaru
{
@@ -143,288 +131,6 @@ namespace MPF.Core.Modules.Aaru
#region BaseParameters Implementations
- ///
- public override (bool, List) CheckAllOutputFilesExist(string basePath, bool preCheck)
- {
- var missingFiles = new List();
- switch (this.Type)
- {
- case MediaType.CDROM:
- if (!File.Exists($"{basePath}_logs.zip") || !preCheck)
- {
- if (!File.Exists($"{basePath}.cicm.xml"))
- missingFiles.Add($"{basePath}.cicm.xml");
- if (!File.Exists($"{basePath}.ibg"))
- missingFiles.Add($"{basePath}.ibg");
- if (!File.Exists($"{basePath}.log"))
- missingFiles.Add($"{basePath}.log");
- if (!File.Exists($"{basePath}.mhddlog.bin"))
- missingFiles.Add($"{basePath}.mhddlog.bin");
- if (!File.Exists($"{basePath}.resume.xml"))
- missingFiles.Add($"{basePath}.resume.xml");
- if (!File.Exists($"{basePath}.sub.log"))
- missingFiles.Add($"{basePath}.sub.log");
- }
-
- break;
-
- case MediaType.DVD:
- case MediaType.HDDVD:
- case MediaType.BluRay:
- if (!File.Exists($"{basePath}_logs.zip") || !preCheck)
- {
- if (!File.Exists($"{basePath}.cicm.xml"))
- missingFiles.Add($"{basePath}.cicm.xml");
- if (!File.Exists($"{basePath}.ibg"))
- missingFiles.Add($"{basePath}.ibg");
- if (!File.Exists($"{basePath}.log"))
- missingFiles.Add($"{basePath}.log");
- if (!File.Exists($"{basePath}.mhddlog.bin"))
- missingFiles.Add($"{basePath}.mhddlog.bin");
- if (!File.Exists($"{basePath}.resume.xml"))
- missingFiles.Add($"{basePath}.resume.xml");
- }
-
- break;
-
- default:
- missingFiles.Add("Media and system combination not supported for Aaru");
- break;
- }
-
- return (!missingFiles.Any(), missingFiles);
- }
-
- ///
- public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive? drive, bool includeArtifacts)
- {
- // TODO: Fill in submission info specifics for Aaru
- var outputDirectory = Path.GetDirectoryName(basePath);
-
- // Ensure that required sections exist
- info = Builder.EnsureAllSections(info);
-
- // TODO: Determine if there's an Aaru version anywhere
- info.DumpingInfo!.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
- info.DumpingInfo.DumpingDate = InfoTool.GetFileModifiedDate(basePath + ".cicm.xml")?.ToString("yyyy-MM-dd HH:mm:ss");
-
- // Deserialize the sidecar, if possible
- var sidecar = GenerateSidecar(basePath + ".cicm.xml");
-
- // Fill in the hardware data
- if (GetHardwareInfo(sidecar, out var manufacturer, out var model, out var firmware))
- {
- info.DumpingInfo.Manufacturer = manufacturer;
- info.DumpingInfo.Model = model;
- info.DumpingInfo.Firmware = firmware;
- }
-
- // Fill in the disc type data
- if (GetDiscType(sidecar, out var discType, out var discSubType))
- {
- string fullDiscType = string.Empty;
- if (!string.IsNullOrEmpty(discType) && !string.IsNullOrEmpty(discSubType))
- fullDiscType = $"{discType} ({discSubType})";
- else if (!string.IsNullOrEmpty(discType) && string.IsNullOrEmpty(discSubType))
- fullDiscType = discType!;
- else if (string.IsNullOrEmpty(discType) && !string.IsNullOrEmpty(discSubType))
- fullDiscType = discSubType!;
-
- info.DumpingInfo.ReportedDiscType = fullDiscType;
- }
-
- // Get the Datafile information
- var datafile = GenerateDatafile(sidecar, basePath);
-
- // Fill in the hash data
- info.TracksAndWriteOffsets!.ClrMameProData = InfoTool.GenerateDatfile(datafile);
-
- switch (this.Type)
- {
- // TODO: Can this do GD-ROM?
- case MediaType.CDROM:
- // TODO: Re-enable once PVD generation / finding is fixed
- // Generate / obtain the PVD
- //info.Extras.PVD = GeneratePVD(sidecar) ?? "Disc has no PVD";
-
- long errorCount = -1;
- if (File.Exists(basePath + ".resume.xml"))
- errorCount = GetErrorCount(basePath + ".resume.xml");
-
- info.CommonDiscInfo!.ErrorsCount = (errorCount == -1 ? "Error retrieving error count" : errorCount.ToString());
-
- info.TracksAndWriteOffsets.Cuesheet = GenerateCuesheet(sidecar, basePath) ?? string.Empty;
-
- string cdWriteOffset = GetWriteOffset(sidecar) ?? string.Empty;
- info.CommonDiscInfo.RingWriteOffset = cdWriteOffset;
- info.TracksAndWriteOffsets.OtherWriteOffsets = cdWriteOffset;
- break;
-
- case MediaType.DVD:
- case MediaType.HDDVD:
- case MediaType.BluRay:
-
- // Get the individual hash data, as per internal
- if (InfoTool.GetISOHashValues(datafile, out long size, out var crc32, out var md5, out var sha1))
- {
- info.SizeAndChecksums!.CRC32 = crc32;
- info.SizeAndChecksums.CRC32 = crc32;
- info.SizeAndChecksums.MD5 = md5;
- info.SizeAndChecksums.SHA1 = sha1;
- }
-
- // TODO: Re-enable once PVD generation / finding is fixed
- // Generate / obtain the PVD
- //info.Extras.PVD = GeneratePVD(sidecar) ?? "Disc has no PVD";
-
- // Deal with the layerbreak
- string? layerbreak = null;
- if (this.Type == MediaType.DVD)
- layerbreak = GetLayerbreak(sidecar) ?? string.Empty;
- else if (this.Type == MediaType.BluRay)
- layerbreak = info.SizeAndChecksums!.Size > 25_025_314_816 ? "25025314816" : null;
-
- // If we have a single-layer disc
- if (string.IsNullOrEmpty(layerbreak))
- {
- // Currently no-op
- }
- // If we have a dual-layer disc
- else
- {
- info.SizeAndChecksums!.Layerbreak = Int64.Parse(layerbreak);
- }
-
- // TODO: Investigate XGD disc outputs
- // TODO: Investigate BD specifics like PIC
-
- break;
- }
-
- switch (this.System)
- {
- // TODO: Can we get SecuROM data?
- // TODO: Can we get SS version/ranges?
- // TODO: Can we get DMI info?
- // TODO: Can we get Sega Header info?
- // TODO: Can we get PS1 EDC status?
- // TODO: Can we get PS1 LibCrypt status?
-
- case RedumpSystem.DVDAudio:
- case RedumpSystem.DVDVideo:
- info.CopyProtection!.Protection = GetDVDProtection(sidecar) ?? string.Empty;
- break;
-
- case RedumpSystem.KonamiPython2:
- if (InfoTool.GetPlayStationExecutableInfo(drive?.Name, out var pythonTwoSerial, out Region? pythonTwoRegion, out var pythonTwoDate))
- {
- // Ensure internal serial is pulled from local data
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = pythonTwoSerial ?? string.Empty;
- info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? pythonTwoRegion;
- info.CommonDiscInfo.EXEDateBuildDate = pythonTwoDate;
- }
-
- info.VersionAndEditions!.Version = InfoTool.GetPlayStation2Version(drive?.Name) ?? string.Empty;
- break;
-
- case RedumpSystem.MicrosoftXbox:
- if (GetXgdAuxInfo(sidecar, out var xgd1DMIHash, out var xgd1PFIHash, out var xgd1SSHash, out var ss, out var xgd1SSVer))
- {
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.DMIHash] = xgd1DMIHash ?? string.Empty;
- info.CommonDiscInfo.CommentsSpecialFields[SiteCode.PFIHash] = xgd1PFIHash ?? string.Empty;
- info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSHash] = xgd1SSHash ?? string.Empty;
- info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSVersion] = xgd1SSVer ?? string.Empty;
- info.Extras!.SecuritySectorRanges = ss ?? string.Empty;
- }
-
- if (GetXboxDMIInfo(sidecar, out var serial, out var version, out Region? region))
- {
- info.CommonDiscInfo!.Serial = serial ?? string.Empty;
- info.VersionAndEditions!.Version = version ?? string.Empty;
- info.CommonDiscInfo.Region = region;
- }
-
- break;
-
- case RedumpSystem.MicrosoftXbox360:
- if (GetXgdAuxInfo(sidecar, out var xgd23DMIHash, out var xgd23PFIHash, out var xgd23SSHash, out var ss360, out var xgd23SSVer))
- {
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.DMIHash] = xgd23DMIHash ?? string.Empty;
- info.CommonDiscInfo.CommentsSpecialFields[SiteCode.PFIHash] = xgd23PFIHash ?? string.Empty;
- info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSHash] = xgd23SSHash ?? string.Empty;
- info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSVersion] = xgd23SSVer ?? string.Empty;
- info.Extras!.SecuritySectorRanges = ss360 ?? string.Empty;
- }
-
- if (GetXbox360DMIInfo(sidecar, out var serial360, out var version360, out Region? region360))
- {
- info.CommonDiscInfo!.Serial = serial360 ?? string.Empty;
- info.VersionAndEditions!.Version = version360 ?? string.Empty;
- info.CommonDiscInfo.Region = region360;
- }
- break;
-
- case RedumpSystem.SonyPlayStation:
- if (InfoTool.GetPlayStationExecutableInfo(drive?.Name, out var playstationSerial, out Region? playstationRegion, out var playstationDate))
- {
- // Ensure internal serial is pulled from local data
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = playstationSerial ?? string.Empty;
- info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationRegion;
- info.CommonDiscInfo.EXEDateBuildDate = playstationDate;
- }
-
- break;
-
- case RedumpSystem.SonyPlayStation2:
- if (InfoTool.GetPlayStationExecutableInfo(drive?.Name, out var playstationTwoSerial, out Region? playstationTwoRegion, out var playstationTwoDate))
- {
- // Ensure internal serial is pulled from local data
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = playstationTwoSerial ?? string.Empty;
- info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationTwoRegion;
- info.CommonDiscInfo.EXEDateBuildDate = playstationTwoDate;
- }
-
- info.VersionAndEditions!.Version = InfoTool.GetPlayStation2Version(drive?.Name) ?? string.Empty;
- break;
-
- case RedumpSystem.SonyPlayStation3:
- info.VersionAndEditions!.Version = InfoTool.GetPlayStation3Version(drive?.Name) ?? string.Empty;
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = InfoTool.GetPlayStation3Serial(drive?.Name) ?? string.Empty;
- string? firmwareVersion = InfoTool.GetPlayStation3FirmwareVersion(drive?.Name);
- if (firmwareVersion != null)
- info.CommonDiscInfo!.ContentsSpecialFields![SiteCode.Patches] = $"PS3 Firmware {firmwareVersion}";
- break;
-
- case RedumpSystem.SonyPlayStation4:
- info.VersionAndEditions!.Version = InfoTool.GetPlayStation4Version(drive?.Name) ?? string.Empty;
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = InfoTool.GetPlayStation4Serial(drive?.Name) ?? string.Empty;
- break;
-
- case RedumpSystem.SonyPlayStation5:
- info.VersionAndEditions!.Version = InfoTool.GetPlayStation5Version(drive?.Name) ?? string.Empty;
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = InfoTool.GetPlayStation5Serial(drive?.Name) ?? string.Empty;
- break;
- }
-
- // Fill in any artifacts that exist, Base64-encoded, if we need to
- if (includeArtifacts)
- {
- info.Artifacts ??= [];
- if (File.Exists(basePath + ".cicm.xml"))
- info.Artifacts["cicm"] = GetBase64(GetFullFile(basePath + ".cicm.xml")) ?? string.Empty;
- if (File.Exists(basePath + ".ibg"))
- info.Artifacts["ibg"] = Convert.ToBase64String(File.ReadAllBytes(basePath + ".ibg"));
- if (File.Exists(basePath + ".log"))
- info.Artifacts["log"] = GetBase64(GetFullFile(basePath + ".log")) ?? string.Empty;
- if (File.Exists(basePath + ".mhddlog.bin"))
- info.Artifacts["mhddlog_bin"] = Convert.ToBase64String(File.ReadAllBytes(basePath + ".mhddlog.bin"));
- if (File.Exists(basePath + ".resume.xml"))
- info.Artifacts["resume"] = GetBase64(GetFullFile(basePath + ".resume.xml")) ?? string.Empty;
- if (File.Exists(basePath + ".sub.log"))
- info.Artifacts["sub_log"] = GetBase64(GetFullFile(basePath + ".sub.log")) ?? string.Empty;
- }
- }
-
///
public override string? GenerateParameters()
{
@@ -1431,52 +1137,6 @@ namespace MPF.Core.Modules.Aaru
///
public override string GetDefaultExtension(MediaType? mediaType) => Converters.Extension(mediaType);
- ///
- public override List GetLogFilePaths(string basePath)
- {
- var logFiles = new List();
- switch (this.Type)
- {
- case MediaType.CDROM:
- if (File.Exists($"{basePath}.cicm.xml"))
- logFiles.Add($"{basePath}.cicm.xml");
- if (File.Exists($"{basePath}.error.log"))
- logFiles.Add($"{basePath}.error.log");
- if (File.Exists($"{basePath}.ibg"))
- logFiles.Add($"{basePath}.ibg");
- if (File.Exists($"{basePath}.log"))
- logFiles.Add($"{basePath}.log");
- if (File.Exists($"{basePath}.mhddlog.bin"))
- logFiles.Add($"{basePath}.mhddlog.bin");
- if (File.Exists($"{basePath}.resume.xml"))
- logFiles.Add($"{basePath}.resume.xml");
- if (File.Exists($"{basePath}.sub.log"))
- logFiles.Add($"{basePath}.sub.log");
-
- break;
-
- case MediaType.DVD:
- case MediaType.HDDVD:
- case MediaType.BluRay:
- if (File.Exists($"{basePath}.cicm.xml"))
- logFiles.Add($"{basePath}.cicm.xml");
- if (File.Exists($"{basePath}.error.log"))
- logFiles.Add($"{basePath}.error.log");
- if (File.Exists($"{basePath}.ibg"))
- logFiles.Add($"{basePath}.ibg");
- if (File.Exists($"{basePath}.log"))
- logFiles.Add($"{basePath}.log");
- if (File.Exists($"{basePath}.mhddlog.bin"))
- logFiles.Add($"{basePath}.mhddlog.bin");
- if (File.Exists($"{basePath}.resume.xml"))
- logFiles.Add($"{basePath}.resume.xml");
-
- break;
- }
-
- return logFiles;
- }
-
///
public override bool IsDumpingCommand()
{
@@ -2299,1116 +1959,5 @@ namespace MPF.Core.Modules.Aaru
}
#endregion
-
- #region Information Extraction Methods
-
- ///
- /// Convert the TrackTypeTrackType value to a CueTrackDataType
- ///
- /// TrackTypeTrackType to convert
- /// Sector size to help with specific subtypes
- /// CueTrackDataType representing the input data
- private static CueTrackDataType ConvertToDataType(TrackTypeTrackType trackType, uint bytesPerSector)
- {
- switch (trackType)
- {
- case TrackTypeTrackType.audio:
- return CueTrackDataType.AUDIO;
-
- case TrackTypeTrackType.mode1:
- if (bytesPerSector == 2048)
- return CueTrackDataType.MODE1_2048;
- else
- return CueTrackDataType.MODE1_2352;
-
- case TrackTypeTrackType.mode2:
- case TrackTypeTrackType.m2f1:
- case TrackTypeTrackType.m2f2:
- if (bytesPerSector == 2336)
- return CueTrackDataType.MODE2_2336;
- else
- return CueTrackDataType.MODE2_2352;
-
- default:
- return CueTrackDataType.MODE1_2352;
- }
- }
-
- ///
- /// Convert the TrackFlagsType value to a CueTrackFlag
- ///
- /// TrackFlagsType containing flag data
- /// CueTrackFlag representing the flags
- private static CueTrackFlag ConvertToTrackFlag(TrackFlagsType trackFlagsType)
- {
- if (trackFlagsType == null)
- return 0;
-
- CueTrackFlag flag = 0;
-
- if (trackFlagsType.CopyPermitted)
- flag |= CueTrackFlag.DCP;
-
- if (trackFlagsType.Quadraphonic)
- flag |= CueTrackFlag.FourCH;
-
- if (trackFlagsType.PreEmphasis)
- flag |= CueTrackFlag.PRE;
-
- return flag;
- }
-
- ///
- /// Generate a cuesheet string based on CICM sidecar data
- ///
- /// CICM Sidecar data generated by Aaru
- /// Base path for determining file names
- /// String containing the cuesheet, null on error
- private static string? GenerateCuesheet(CICMMetadataType? cicmSidecar, string basePath)
- {
- // If the object is null, we can't get information from it
- if (cicmSidecar == null)
- return null;
-
- // Required variables
- uint totalTracks = 0;
- var cueFiles = new List();
- var cueSheet = new CueSheet
- {
- Performer = string.Join(", ", cicmSidecar.Performer ?? []),
- };
-
- // Only care about OpticalDisc types
- if (cicmSidecar.OpticalDisc == null || cicmSidecar.OpticalDisc.Length == 0)
- return null;
-
- // Loop through each OpticalDisc in the metadata
- foreach (OpticalDiscType opticalDisc in cicmSidecar.OpticalDisc)
- {
- // Only capture the first total track count
- if (opticalDisc.Tracks != null && opticalDisc.Tracks.Length > 0)
- totalTracks = opticalDisc.Tracks[0];
-
- // If there are no tracks, we can't get a cuesheet
- if (opticalDisc.Track == null || opticalDisc.Track.Length == 0)
- continue;
-
- // Get cuesheet-level information
- cueSheet.Catalog = opticalDisc.MediaCatalogueNumber;
-
- // Loop through each track
- foreach (TrackType track in opticalDisc.Track)
- {
- // Create cue track entry
- var cueTrack = new CueTrack
- {
- Number = (int)(track.Sequence?.TrackNumber ?? 0),
- DataType = ConvertToDataType(track.TrackType1, track.BytesPerSector),
- Flags = ConvertToTrackFlag(track.Flags),
- ISRC = track.ISRC,
- };
-
- // Create cue file entry
- var cueFile = new CueFile
- {
- FileName = GenerateTrackName(basePath, (int)totalTracks, cueTrack.Number, opticalDisc.DiscType),
- FileType = CueFileType.BINARY,
- };
-
- // Add index data
- var cueTracks = new List();
- if (track.Indexes != null && track.Indexes.Length > 0)
- {
- var cueIndicies = new List();
-
- // Loop through each index
- foreach (TrackIndexType trackIndex in track.Indexes)
- {
- // Get timestamp from frame count
- int absoluteLength = Math.Abs(trackIndex.Value);
- int frames = absoluteLength % 75;
- int seconds = (absoluteLength / 75) % 60;
- int minutes = (absoluteLength / 75 / 60);
- string timeString = $"{minutes:D2}:{seconds:D2}:{frames:D2}";
-
- // Pregap information
- if (trackIndex.Value < 0)
- {
- string[] timeStringSplit = timeString.Split(':');
- cueTrack.PreGap = new PreGap
- {
- Minutes = int.Parse(timeStringSplit[0]),
- Seconds = int.Parse(timeStringSplit[1]),
- Frames = int.Parse(timeStringSplit[2]),
- };
- }
-
- // Individual indexes
- else
- {
- string[] timeStringSplit = timeString.Split(':');
- cueIndicies.Add(new CueIndex
- {
- Index = trackIndex.index,
- Minutes = int.Parse(timeStringSplit[0]),
- Seconds = int.Parse(timeStringSplit[1]),
- Frames = int.Parse(timeStringSplit[2]),
- });
- }
- }
-
- cueTrack.Indices = [.. cueIndicies];
- }
- else
- {
- // Default if index data missing from sidecar
- cueTrack.Indices = new CueIndex[]
- {
- new()
- {
- Index = 1,
- Minutes = 0,
- Seconds = 0,
- Frames = 0,
- },
- };
- }
-
- // Add the track to the file
- cueTracks.Add(cueTrack);
-
- // Add the file to the cuesheet
- cueFiles.Add(cueFile);
- }
- }
-
- // If we have a cuesheet to write out, do so
- cueSheet.Files = [.. cueFiles];
- if (cueSheet != null && cueSheet != default)
- {
- var ms = SabreTools.Serialization.Serializers.CueSheet.SerializeStream(cueSheet);
- if (ms == null)
- return null;
-
- using var sr = new StreamReader(ms);
- return sr.ReadToEnd();
- }
-
- return null;
- }
-
- ///
- /// Generate a CMP XML datfile string based on CICM sidecar data
- ///
- /// CICM Sidecar data generated by Aaru
- /// Base path for determining file names
- /// String containing the datfile, null on error
- private static string? GenerateDatfile(CICMMetadataType? cicmSidecar, string basePath)
- {
- // If the object is null, we can't get information from it
- if (cicmSidecar == null)
- return null;
-
- // Required variables
- string datfile = string.Empty;
-
- // Process OpticalDisc, if possible
- if (cicmSidecar.OpticalDisc != null && cicmSidecar.OpticalDisc.Length > 0)
- {
- // Loop through each OpticalDisc in the metadata
- foreach (OpticalDiscType opticalDisc in cicmSidecar.OpticalDisc)
- {
- // Only capture the first total track count
- uint totalTracks = 0;
- if (opticalDisc.Tracks != null && opticalDisc.Tracks.Length > 0)
- totalTracks = opticalDisc.Tracks[0];
-
- // If there are no tracks, we can't get a datfile
- if (opticalDisc.Track == null || opticalDisc.Track.Length == 0)
- continue;
-
- // Loop through each track
- foreach (TrackType track in opticalDisc.Track)
- {
- uint trackNumber = track.Sequence?.TrackNumber ?? 0;
- ulong size = track.Size;
- string crc32 = string.Empty;
- string md5 = string.Empty;
- string sha1 = string.Empty;
-
- // If we don't have any checksums, we can't get a DAT for this track
- if (track.Checksums == null || track.Checksums.Length == 0)
- continue;
-
- // Extract only relevant checksums
- foreach (ChecksumType checksum in track.Checksums)
- {
- switch (checksum.type)
- {
- case ChecksumTypeType.crc32:
- crc32 = checksum.Value;
- break;
- case ChecksumTypeType.md5:
- md5 = checksum.Value;
- break;
- case ChecksumTypeType.sha1:
- sha1 = checksum.Value;
- break;
- }
- }
-
- // Build the track datfile data and append
- string trackName = GenerateTrackName(basePath, (int)totalTracks, (int)trackNumber, opticalDisc.DiscType);
- datfile += $"\n";
- }
- }
- }
-
- // Process BlockMedia, if possible
- if (cicmSidecar.BlockMedia != null && cicmSidecar.BlockMedia.Length > 0)
- {
- // Loop through each BlockMedia in the metadata
- foreach (BlockMediaType blockMedia in cicmSidecar.BlockMedia)
- {
- ulong size = blockMedia.Size;
- string crc32 = string.Empty;
- string md5 = string.Empty;
- string sha1 = string.Empty;
-
- // If we don't have any checksums, we can't get a DAT for this track
- if (blockMedia.Checksums == null || blockMedia.Checksums.Length == 0)
- continue;
-
- // Extract only relevant checksums
- foreach (ChecksumType checksum in blockMedia.Checksums)
- {
- switch (checksum.type)
- {
- case ChecksumTypeType.crc32:
- crc32 = checksum.Value;
- break;
- case ChecksumTypeType.md5:
- md5 = checksum.Value;
- break;
- case ChecksumTypeType.sha1:
- sha1 = checksum.Value;
- break;
- }
- }
-
- // Build the track datfile data and append
- string trackName = $"{basePath}.bin";
- datfile += $"\n";
- }
- }
-
- return datfile;
- }
-
- ///
- /// Generate a CMP XML datfile string based on CICM sidecar data
- ///
- /// CICM Sidecar data generated by Aaru
- /// Base path for determining file names
- /// Datafile containing the hash information, null on error
- private static Datafile? GenerateDatafile(CICMMetadataType? cicmSidecar, string basePath)
- {
- // If the object is null, we can't get information from it
- if (cicmSidecar == null)
- return null;
-
- // Required variables
- var datafile = new Datafile();
- var roms = new List();
-
- // Process OpticalDisc, if possible
- if (cicmSidecar.OpticalDisc != null && cicmSidecar.OpticalDisc.Length > 0)
- {
- // Loop through each OpticalDisc in the metadata
- foreach (OpticalDiscType opticalDisc in cicmSidecar.OpticalDisc)
- {
- // Only capture the first total track count
- uint totalTracks = 0;
- if (opticalDisc.Tracks != null && opticalDisc.Tracks.Length > 0)
- totalTracks = opticalDisc.Tracks[0];
-
- // If there are no tracks, we can't get a datfile
- if (opticalDisc.Track == null || opticalDisc.Track.Length == 0)
- continue;
-
- // Loop through each track
- foreach (TrackType track in opticalDisc.Track)
- {
- uint trackNumber = track.Sequence?.TrackNumber ?? 0;
- ulong size = track.Size;
- string crc32 = string.Empty;
- string md5 = string.Empty;
- string sha1 = string.Empty;
-
- // If we don't have any checksums, we can't get a DAT for this track
- if (track.Checksums == null || track.Checksums.Length == 0)
- continue;
-
- // Extract only relevant checksums
- foreach (ChecksumType checksum in track.Checksums)
- {
- switch (checksum.type)
- {
- case ChecksumTypeType.crc32:
- crc32 = checksum.Value;
- break;
- case ChecksumTypeType.md5:
- md5 = checksum.Value;
- break;
- case ChecksumTypeType.sha1:
- sha1 = checksum.Value;
- break;
- }
- }
-
- // Build the track datfile data and append
- string trackName = GenerateTrackName(basePath, (int)totalTracks, (int)trackNumber, opticalDisc.DiscType);
- roms.Add(new Rom { Name = trackName, Size = size.ToString(), Crc = crc32, Md5 = md5, Sha1 = sha1 });
- }
- }
- }
-
- // Process BlockMedia, if possible
- if (cicmSidecar.BlockMedia != null && cicmSidecar.BlockMedia.Length > 0)
- {
- // Loop through each BlockMedia in the metadata
- foreach (BlockMediaType blockMedia in cicmSidecar.BlockMedia)
- {
- ulong size = blockMedia.Size;
- string crc32 = string.Empty;
- string md5 = string.Empty;
- string sha1 = string.Empty;
-
- // If we don't have any checksums, we can't get a DAT for this track
- if (blockMedia.Checksums == null || blockMedia.Checksums.Length == 0)
- continue;
-
- // Extract only relevant checksums
- foreach (ChecksumType checksum in blockMedia.Checksums)
- {
- switch (checksum.type)
- {
- case ChecksumTypeType.crc32:
- crc32 = checksum.Value;
- break;
- case ChecksumTypeType.md5:
- md5 = checksum.Value;
- break;
- case ChecksumTypeType.sha1:
- sha1 = checksum.Value;
- break;
- }
- }
-
- // Build the track datfile data and append
- string trackName = $"{basePath}.bin";
- roms.Add(new Rom { Name = trackName, Size = size.ToString(), Crc = crc32, Md5 = md5, Sha1 = sha1 });
- }
- }
-
- // Assign the roms to a new game
- datafile.Games = new Game[1];
- datafile.Games[0] = new Game { Roms = [.. roms] };
-
- return datafile;
- }
-
- ///
- /// Generate a track name based on current path and tracks
- ///
- /// Base path for determining file names
- /// Total number of tracks in the media
- /// Current track index
- /// Current disc type, used for determining extension
- /// Formatted string representing the track name according to Redump standards
- private static string GenerateTrackName(string basePath, int totalTracks, int trackNumber, string discType)
- {
- string extension = "bin";
- if (discType.Contains("BD") || discType.Contains("DVD"))
- extension = "iso";
-
- string trackName = Path.GetFileNameWithoutExtension(basePath);
- if (totalTracks == 1)
- trackName = $"{trackName}.{extension}";
- else if (totalTracks > 1 && totalTracks < 10)
- trackName = $"{trackName} (Track {trackNumber}).{extension}";
- else
- trackName = $"{trackName} (Track {trackNumber:D2}).{extension}";
-
- return trackName;
- }
-
- ///
- /// Generate a Redump-compatible PVD block based on CICM sidecar file
- ///
- /// CICM Sidecar data generated by Aaru
- /// String containing the PVD, null on error
- private static string? GeneratePVD(CICMMetadataType? cicmSidecar)
- {
- // If the object is null, we can't get information from it
- if (cicmSidecar == null)
- return null;
-
- // Process OpticalDisc, if possible
- if (cicmSidecar.OpticalDisc != null && cicmSidecar.OpticalDisc.Length > 0)
- {
- // Loop through each OpticalDisc in the metadata
- foreach (OpticalDiscType opticalDisc in cicmSidecar.OpticalDisc)
- {
- var pvdData = GeneratePVDData(opticalDisc);
-
- // If we got a null value, we skip this disc
- if (pvdData == null)
- continue;
-
- // Build each row in consecutive order
- string pvd = string.Empty;
-#if NET20 || NET35 || NET40
- byte[] pvdLine = new byte[16];
- Array.Copy(pvdData, 0, pvdLine, 0, 16);
- pvd += GenerateSectorOutputLine("0320", pvdLine);
- Array.Copy(pvdData, 16, pvdLine, 0, 16);
- pvd += GenerateSectorOutputLine("0330", pvdLine);
- Array.Copy(pvdData, 32, pvdLine, 0, 16);
- pvd += GenerateSectorOutputLine("0340", pvdLine);
- Array.Copy(pvdData, 48, pvdLine, 0, 16);
- pvd += GenerateSectorOutputLine("0350", pvdLine);
- Array.Copy(pvdData, 64, pvdLine, 0, 16);
- pvd += GenerateSectorOutputLine("0360", pvdLine);
- Array.Copy(pvdData, 80, pvdLine, 0, 16);
- pvd += GenerateSectorOutputLine("0370", pvdLine);
-#else
- pvd += GenerateSectorOutputLine("0320", new ReadOnlySpan(pvdData, 0, 16).ToArray());
- pvd += GenerateSectorOutputLine("0330", new ReadOnlySpan(pvdData, 16, 16).ToArray());
- pvd += GenerateSectorOutputLine("0340", new ReadOnlySpan(pvdData, 32, 16).ToArray());
- pvd += GenerateSectorOutputLine("0350", new ReadOnlySpan(pvdData, 48, 16).ToArray());
- pvd += GenerateSectorOutputLine("0360", new ReadOnlySpan(pvdData, 64, 16).ToArray());
- pvd += GenerateSectorOutputLine("0370", new ReadOnlySpan(pvdData, 80, 16).ToArray());
-#endif
-
- return pvd;
- }
- }
-
- return null;
- }
-
- ///
- /// Generate the byte array representing the current PVD information
- ///
- /// OpticalDisc type from CICM Sidecar data
- /// Byte array representing the PVD, null on error
- private static byte[]? GeneratePVDData(OpticalDiscType? opticalDisc)
- {
- // Required variables
- DateTime creation = DateTime.MinValue;
- DateTime modification = DateTime.MinValue;
- DateTime expiration = DateTime.MinValue;
- DateTime effective = DateTime.MinValue;
-
- // If there are no tracks, we can't get a PVD
- if (opticalDisc?.Track == null || opticalDisc.Track.Length == 0)
- return null;
-
- // Take the first track only
- TrackType track = opticalDisc.Track[0];
-
- // If there are no partitions, we can't get a PVD
- if (track.FileSystemInformation == null || track.FileSystemInformation.Length == 0)
- return null;
-
- // Loop through each Partition
- foreach (PartitionType partition in track.FileSystemInformation)
- {
- // If the partition has no file systems, we can't get a PVD
- if (partition.FileSystems == null || partition.FileSystems.Length == 0)
- continue;
-
- // Loop through each FileSystem until we find a PVD
- foreach (FileSystemType fileSystem in partition.FileSystems)
- {
- // If we don't have a PVD-able filesystem, we can't get a PVD
- if (!fileSystem.CreationDateSpecified
- && !fileSystem.ModificationDateSpecified
- && !fileSystem.ExpirationDateSpecified
- && !fileSystem.EffectiveDateSpecified)
- {
- continue;
- }
-
- // Creation Date
- if (fileSystem.CreationDateSpecified)
- creation = fileSystem.CreationDate;
-
- // Modification Date
- if (fileSystem.ModificationDateSpecified)
- modification = fileSystem.ModificationDate;
-
- // Expiration Date
- if (fileSystem.ExpirationDateSpecified)
- expiration = fileSystem.ExpirationDate;
-
- // Effective Date
- if (fileSystem.EffectiveDateSpecified)
- effective = fileSystem.EffectiveDate;
-
- break;
- }
-
- // If we found a Partition with PVD data, we break
- if (creation != DateTime.MinValue
- || modification != DateTime.MinValue
- || expiration != DateTime.MinValue
- || effective != DateTime.MinValue)
- {
- break;
- }
- }
-
- // If we found no partitions, we return null
- if (creation == DateTime.MinValue
- && modification == DateTime.MinValue
- && expiration == DateTime.MinValue
- && effective == DateTime.MinValue)
- {
- return null;
- }
-
- // Now generate the byte array data
- var pvdData = new List();
- pvdData.AddRange(new string(' ', 13).ToCharArray().Select(c => (byte)c));
- pvdData.AddRange(GeneratePVDDateTimeBytes(creation));
- pvdData.AddRange(GeneratePVDDateTimeBytes(modification));
- pvdData.AddRange(GeneratePVDDateTimeBytes(expiration));
- pvdData.AddRange(GeneratePVDDateTimeBytes(effective));
- pvdData.Add(0x01);
- pvdData.AddRange(new string((char)0, 14).ToCharArray().Select(c => (byte)c));
-
- // Return the filled array
- return [.. pvdData];
- }
-
- ///
- /// Generate the required bytes from a DateTime object
- ///
- /// DateTime to get representation of
- /// Byte array representing the DateTime
- private static byte[] GeneratePVDDateTimeBytes(DateTime dateTime)
- {
- string emptyTime = "0000000000000000";
- string dateTimeString = emptyTime;
- byte timeZoneNumber = 0;
-
- // If we don't have default values, set the proper string
- if (dateTime != DateTime.MinValue)
- {
- dateTimeString = dateTime.ToString("yyyyMMddHHmmssff");
-
- // Get timezone offset (0 == GMT, up and down in 15-minute increments)
- string timeZoneString;
- try
- {
- timeZoneString = dateTime.ToString("zzz");
- }
- catch
- {
- timeZoneString = "00:00";
- }
-
- // Format is hh:mm
- string[] splitTimeZoneString = timeZoneString.Split(':');
- if (int.TryParse(splitTimeZoneString[0], out int hours))
- timeZoneNumber += (byte)(hours * 4);
- if (int.TryParse(splitTimeZoneString[1], out int minutes))
- timeZoneNumber += (byte)(minutes / 15);
- }
-
- // Get and return the byte array
- List dateTimeList = dateTimeString.ToCharArray().Select(c => (byte)c).ToList();
- dateTimeList.Add(timeZoneNumber);
- return [.. dateTimeList];
- }
-
- ///
- /// Generate a single 16-byte sector line from a byte array
- ///
- /// Row ID for outputting
- /// Bytes representing the data to write
- /// Formatted string representing the sector line
- private static string? GenerateSectorOutputLine(string row, byte[] bytes)
- {
- // If the data isn't correct, return null
- if (bytes == null || bytes.Length != 16)
- return null;
-
- string pvdLine = $"{row} : ";
- pvdLine += BitConverter.ToString(bytes.Take(8).ToArray()).Replace("-", " ");
- pvdLine += " ";
- pvdLine += BitConverter.ToString(bytes.Skip(8).Take(8).ToArray()).Replace("-", " ");
- pvdLine += " ";
- pvdLine += Encoding.ASCII.GetString([.. bytes]).Replace((char)0, '.').Replace('?', '.');
- pvdLine += "\n";
-
- return pvdLine;
- }
-
- ///
- /// Read the CICM Sidecar as an object
- ///
- /// CICM Sidecar data generated by Aaru
- /// Object containing the data, null on error
- private static CICMMetadataType? GenerateSidecar(string cicmSidecar)
- {
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(cicmSidecar))
- return null;
-
- // Open and read in the XML file
- XmlReader xtr = XmlReader.Create(cicmSidecar, new XmlReaderSettings
- {
- CheckCharacters = false,
-#if NET40_OR_GREATER || NETCOREAPP
- DtdProcessing = DtdProcessing.Ignore,
-#endif
- IgnoreComments = true,
- IgnoreWhitespace = true,
- ValidationFlags = XmlSchemaValidationFlags.None,
- ValidationType = ValidationType.None,
- });
-
- // If the reader is null for some reason, we can't do anything
- if (xtr == null)
- return null;
-
- var serializer = new XmlSerializer(typeof(CICMMetadataType));
- return serializer.Deserialize(xtr) as CICMMetadataType;
- }
-
- ///
- /// Get reported disc type information, if possible
- ///
- /// CICM Sidecar data generated by Aaru
- /// True if disc type info was set, false otherwise
- private static bool GetDiscType(CICMMetadataType? cicmSidecar, out string? discType, out string? discSubType)
- {
- // Set the default values
- discType = null; discSubType = null;
-
- // If the object is null, we can't get information from it
- if (cicmSidecar == null)
- return false;
-
- // Only care about OpticalDisc types
- if (cicmSidecar.OpticalDisc == null || cicmSidecar.OpticalDisc.Length == 0)
- return false;
-
- // Find and return the hardware info, if possible
- foreach (OpticalDiscType opticalDisc in cicmSidecar.OpticalDisc)
- {
- // Store the first instance of each value
- if (string.IsNullOrEmpty(discType) && !string.IsNullOrEmpty(opticalDisc.DiscType))
- discType = opticalDisc.DiscType;
- if (string.IsNullOrEmpty(discSubType) && !string.IsNullOrEmpty(opticalDisc.DiscSubType))
- discSubType = opticalDisc.DiscSubType;
- }
-
- return !string.IsNullOrEmpty(discType) || !string.IsNullOrEmpty(discSubType);
- }
-
- ///
- /// Get the DVD protection information, if possible
- ///
- /// CICM Sidecar data generated by Aaru
- /// Formatted string representing the DVD protection, null on error
- private static string? GetDVDProtection(CICMMetadataType? cicmSidecar)
- {
- // If the object is null, we can't get information from it
- if (cicmSidecar == null)
- return null;
-
- // Only care about OpticalDisc types
- if (cicmSidecar.OpticalDisc == null || cicmSidecar.OpticalDisc.Length == 0)
- return null;
-
- // Get an output for the copyright protection
- string copyrightProtectionSystemType = string.Empty;
-
- // Loop through each OpticalDisc in the metadata
- foreach (OpticalDiscType opticalDisc in cicmSidecar.OpticalDisc)
- {
- if (!string.IsNullOrEmpty(opticalDisc.CopyProtection))
- copyrightProtectionSystemType += $", {opticalDisc.CopyProtection}";
- }
-
- // Trim the values
- copyrightProtectionSystemType = copyrightProtectionSystemType.TrimStart(',').Trim();
-
- // TODO: Note- Most of the below values are not currently captured by Aaru.
- // At the time of writing, there are open issues to capture more of this
- // information and store it in the output. For now, only the copyright
- // protection system can be retrieved.
-
- // Now we format everything we can
- string protection = string.Empty;
- //if (!string.IsNullOrEmpty(region))
- // protection += $"Region: {region}\n";
- //if (!string.IsNullOrEmpty(rceProtection))
- // protection += $"RCE Protection: {rceProtection}\n";
- if (!string.IsNullOrEmpty(copyrightProtectionSystemType))
- protection += $"Copyright Protection System Type: {copyrightProtectionSystemType}\n";
- //if (!string.IsNullOrEmpty(vobKeys))
- // protection += vobKeys;
- //if (!string.IsNullOrEmpty(decryptedDiscKey))
- // protection += $"Decrypted Disc Key: {decryptedDiscKey}\n";
-
- return protection;
- }
-
- ///
- /// Get the detected error count from the input files, if possible
- ///
- /// .resume.xml file location
- /// Error count if possible, -1 on error
- private static long GetErrorCount(string resume)
- {
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(resume))
- return -1;
-
- // Get a total error count for after
- long? totalErrors = null;
-
- // Parse the resume XML file
- try
- {
- // Read in the error count whenever we find it
- using var sr = File.OpenText(resume);
- while (!sr.EndOfStream)
- {
- var line = sr.ReadLine()?.Trim();
-
- // Initialize on seeing the open tag
- if (string.IsNullOrEmpty(line))
- continue;
- else if (line!.StartsWith(""))
- totalErrors = 0;
- else if (line.StartsWith(""))
- return totalErrors ?? -1;
- else if (line.StartsWith("") && totalErrors != null)
- totalErrors++;
- }
-
- // If we haven't found anything, return -1
- return totalErrors ?? -1;
- }
- catch
- {
- // We don't care what the exception is right now
- return Int64.MaxValue;
- }
- }
-
- ///
- /// Get hardware information, if possible
- ///
- /// CICM Sidecar data generated by Aaru
- /// True if hardware info was set, false otherwise
- private static bool GetHardwareInfo(CICMMetadataType? cicmSidecar, out string? manufacturer, out string? model, out string? firmware)
- {
- // Set the default values
- manufacturer = null; model = null; firmware = null;
-
- // If the object is null, we can't get information from it
- if (cicmSidecar == null)
- return false;
-
- // Only care about OpticalDisc types
- if (cicmSidecar.OpticalDisc == null || cicmSidecar.OpticalDisc.Length == 0)
- return false;
-
- // Find and return the hardware info, if possible
- foreach (OpticalDiscType opticalDisc in cicmSidecar.OpticalDisc)
- {
- // If there's no hardware information, skip
- if (opticalDisc.DumpHardwareArray == null || !opticalDisc.DumpHardwareArray.Any())
- continue;
-
- foreach (DumpHardwareType hardware in opticalDisc.DumpHardwareArray)
- {
- // If the hardware information is invalid, skip
- if (hardware == null)
- continue;
-
- // Store the first instance of each value
- if (string.IsNullOrEmpty(manufacturer) && !string.IsNullOrEmpty(hardware.Manufacturer))
- manufacturer = hardware.Manufacturer;
- if (string.IsNullOrEmpty(model) && !string.IsNullOrEmpty(hardware.Model))
- model = hardware.Model;
- if (string.IsNullOrEmpty(firmware) && !string.IsNullOrEmpty(hardware.Firmware))
- firmware = hardware.Firmware;
- }
- }
-
- return !string.IsNullOrEmpty(manufacturer) || !string.IsNullOrEmpty(model) || !string.IsNullOrEmpty(firmware);
- }
-
- ///
- /// Get the layerbreak from the input file, if possible
- ///
- /// CICM Sidecar data generated by Aaru
- /// Layerbreak if possible, null on error
- private static string? GetLayerbreak(CICMMetadataType? cicmSidecar)
- {
- // If the object is null, we can't get information from it
- if (cicmSidecar == null)
- return null;
-
- // Only care about OpticalDisc types
- if (cicmSidecar.OpticalDisc == null || cicmSidecar.OpticalDisc.Length == 0)
- return null;
-
- // Setup the layerbreak
- string? layerbreak = null;
-
- // Find and return the layerbreak, if possible
- foreach (OpticalDiscType opticalDisc in cicmSidecar.OpticalDisc)
- {
- // If there's no layer information, skip
- if (opticalDisc.Layers == null)
- continue;
-
- // TODO: Determine how to find the layerbreak from the CICM or other outputs
- }
-
- return layerbreak;
- }
-
- ///
- /// Get the write offset from the CICM Sidecar file, if possible
- ///
- /// CICM Sidecar data generated by Aaru
- /// Sample write offset if possible, null on error
- private static string? GetWriteOffset(CICMMetadataType? cicmSidecar)
- {
- // If the object is null, we can't get information from it
- if (cicmSidecar == null)
- return null;
-
- // Only care about OpticalDisc types
- if (cicmSidecar.OpticalDisc == null || cicmSidecar.OpticalDisc.Length == 0)
- return null;
-
- // Loop through each OpticalDisc in the metadata
- foreach (OpticalDiscType opticalDisc in cicmSidecar.OpticalDisc)
- {
- // If the disc doesn't have an offset specified, we skip it;
- if (!opticalDisc.OffsetSpecified)
- continue;
-
- return opticalDisc.Offset.ToString();
- }
-
- return null;
- }
-
- ///
- /// Get the XGD auxiliary info from the CICM Sidecar file, if possible
- ///
- /// CICM Sidecar data generated by Aaru
- /// True on successful extraction of info, false otherwise
- private static bool GetXgdAuxInfo(CICMMetadataType? cicmSidecar, out string? dmihash, out string? pfihash, out string? sshash, out string? ss, out string? ssver)
- {
- dmihash = null; pfihash = null; sshash = null; ss = null; ssver = null;
-
- // If the object is null, we can't get information from it
- if (cicmSidecar == null)
- return false;
-
- // Only care about OpticalDisc types
- if (cicmSidecar.OpticalDisc == null || cicmSidecar.OpticalDisc.Length == 0)
- return false;
-
- // Loop through each OpticalDisc in the metadata
- foreach (OpticalDiscType opticalDisc in cicmSidecar.OpticalDisc)
- {
- // If the Xbox type isn't set, we can't extract information
- if (opticalDisc.Xbox == null)
- continue;
-
- // Get the Xbox information
- XboxType xbox = opticalDisc.Xbox;
-
- // DMI
- if (xbox.DMI != null)
- {
- DumpType dmi = xbox.DMI;
- if (dmi.Checksums != null && dmi.Checksums.Length != 0)
- {
- foreach (ChecksumType checksum in dmi.Checksums)
- {
- // We only care about the CRC32
- if (checksum.type == ChecksumTypeType.crc32)
- {
- dmihash = checksum.Value;
- break;
- }
- }
- }
- }
-
- // PFI
- if (xbox.PFI != null)
- {
- DumpType pfi = xbox.PFI;
- if (pfi.Checksums != null && pfi.Checksums.Length != 0)
- {
- foreach (ChecksumType checksum in pfi.Checksums)
- {
- // We only care about the CRC32
- if (checksum.type == ChecksumTypeType.crc32)
- {
- pfihash = checksum.Value;
- break;
- }
- }
- }
- }
-
- // SS
- if (xbox.SecuritySectors != null && xbox.SecuritySectors.Length > 0)
- {
- foreach (XboxSecuritySectorsType securitySector in xbox.SecuritySectors)
- {
- DumpType security = securitySector.SecuritySectors;
- if (security.Checksums != null && security.Checksums.Length != 0)
- {
- foreach (ChecksumType checksum in security.Checksums)
- {
- // We only care about the CRC32
- if (checksum.type == ChecksumTypeType.crc32)
- {
- // TODO: Validate correctness for all 3 fields
- ss = security.Image;
- ssver = securitySector.RequestVersion.ToString();
- sshash = checksum.Value;
- break;
- }
- }
- }
-
- // If we got a hash, we can break
- if (sshash != null)
- break;
- }
- }
- }
-
- return false;
- }
-
- ///
- /// Get the Xbox serial info from the CICM Sidecar file, if possible
- ///
- /// CICM Sidecar data generated by Aaru
- /// True on successful extraction of info, false otherwise
- private static bool GetXboxDMIInfo(CICMMetadataType? cicmSidecar, out string? serial, out string? version, out Region? region)
- {
- serial = null; version = null; region = Region.World;
-
- // If the object is null, we can't get information from it
- if (cicmSidecar == null)
- return false;
-
- // Only care about OpticalDisc types
- if (cicmSidecar.OpticalDisc == null || cicmSidecar.OpticalDisc.Length == 0)
- return false;
-
- // Loop through each OpticalDisc in the metadata
- foreach (OpticalDiscType opticalDisc in cicmSidecar.OpticalDisc)
- {
- // If the Xbox type isn't set, we can't extract information
- if (opticalDisc.Xbox == null)
- continue;
-
- // Get the Xbox information
- XboxType xbox = opticalDisc.Xbox;
-
- // DMI
- if (xbox.DMI != null)
- {
- DumpType dmi = xbox.DMI;
- string image = dmi.Image;
-
- // TODO: Figure out if `image` is the right thing here
- // TODO: Figure out how to extract info from `image`
- //br.BaseStream.Seek(8, SeekOrigin.Begin);
- //char[] str = br.ReadChars(8);
-
- //serial = $"{str[0]}{str[1]}-{str[2]}{str[3]}{str[4]}";
- //version = $"1.{str[5]}{str[6]}";
- //region = GetXgdRegion(str[7]);
- //return true;
- }
- }
-
- return false;
- }
-
- ///
- /// Get the Xbox 360 serial info from the CICM Sidecar file, if possible
- ///
- /// CICM Sidecar data generated by Aaru
- /// True on successful extraction of info, false otherwise
- private static bool GetXbox360DMIInfo(CICMMetadataType? cicmSidecar, out string? serial, out string? version, out Region? region)
- {
- serial = null; version = null; region = Region.World;
-
- // If the object is null, we can't get information from it
- if (cicmSidecar == null)
- return false;
-
- // Only care about OpticalDisc types
- if (cicmSidecar.OpticalDisc == null || cicmSidecar.OpticalDisc.Length == 0)
- return false;
-
- // Loop through each OpticalDisc in the metadata
- foreach (OpticalDiscType opticalDisc in cicmSidecar.OpticalDisc)
- {
- // If the Xbox type isn't set, we can't extract information
- if (opticalDisc.Xbox == null)
- continue;
-
- // Get the Xbox information
- XboxType xbox = opticalDisc.Xbox;
-
- // DMI
- if (xbox.DMI != null)
- {
- DumpType dmi = xbox.DMI;
- string image = dmi.Image;
-
- // TODO: Figure out if `image` is the right thing here
- // TODO: Figure out how to extract info from `image`
- //br.BaseStream.Seek(64, SeekOrigin.Begin);
- //char[] str = br.ReadChars(14);
-
- //serial = $"{str[0]}{str[1]}-{str[2]}{str[3]}{str[4]}{str[5]}";
- //version = $"1.{str[6]}{str[7]}";
- //region = GetXgdRegion(str[8]);
- // str[9], str[10], str[11] - unknown purpose
- // str[12], str[13] - disc <12> of <13>
- //return true;
- }
- }
-
- return false;
- }
-
-#endregion
}
}
diff --git a/MPF.Core/Modules/BaseParameters.cs b/MPF.Core/Modules/BaseParameters.cs
index 9ec1d0f7..40136f5b 100644
--- a/MPF.Core/Modules/BaseParameters.cs
+++ b/MPF.Core/Modules/BaseParameters.cs
@@ -75,11 +75,6 @@ namespace MPF.Core.Modules
///
private Process? process;
- ///
- /// All found volume labels and their corresponding file systems
- ///
- public Dictionary>? VolumeLabels;
-
#endregion
#region Virtual Dumping Information
@@ -158,28 +153,6 @@ namespace MPF.Core.Modules
SetDefaultParameters(drivePath, filename, driveSpeed, options);
}
- #region Abstract Methods
-
- ///
- /// Validate if all required output files exist
- ///
- /// Base filename and path to use for checking
- /// True if this is a check done before a dump, false if done after
- /// Tuple of true if all required files exist, false otherwise and a list representing missing files
- public abstract (bool, List) CheckAllOutputFilesExist(string basePath, bool preCheck);
-
- ///
- /// Generate a SubmissionInfo for the output files
- ///
- /// Base submission info to fill in specifics for
- /// Options object representing user-defined options
- /// Base filename and path to use for checking
- /// Drive representing the disc to get information from
- /// True to include output files as encoded artifacts, false otherwise
- public abstract void GenerateSubmissionInfo(SubmissionInfo submissionInfo, Options options, string basePath, Drive? drive, bool includeArtifacts);
-
- #endregion
-
#region Virtual Methods
///
@@ -201,20 +174,6 @@ namespace MPF.Core.Modules
/// String representing the media type, null on error
public virtual string? GetDefaultExtension(MediaType? mediaType) => null;
- ///
- /// Generate a list of all deleteable files generated
- ///
- /// Base filename and path to use for checking
- /// List of all deleteable file paths, empty otherwise
- public virtual List GetDeleteableFilePaths(string basePath) => new();
-
- ///
- /// Generate a list of all log files generated
- ///
- /// Base filename and path to use for checking
- /// List of all log file paths, empty otherwise
- public virtual List GetLogFilePaths(string basePath) => new();
-
///
/// Get the MediaType from the current set of parameters
///
@@ -329,7 +288,7 @@ namespace MPF.Core.Modules
{ }
}
-#endregion
+ #endregion
#region Parameter Parsing
@@ -1173,96 +1132,5 @@ namespace MPF.Core.Modules
}
#endregion
-
- #region Methods to Move
-
- ///
- /// Get the hex contents of the PIC file
- ///
- /// Path to the PIC.bin file associated with the dump
- /// Number of characters to trim the PIC to, if -1, ignored
- /// PIC data as a hex string if possible, null on error
- /// https://stackoverflow.com/questions/9932096/add-separator-to-string-at-every-n-characters
- protected static string? GetPIC(string picPath, int trimLength = -1)
- {
- // If the file doesn't exist, we can't get the info
- if (!File.Exists(picPath))
- return null;
-
- try
- {
- var hex = GetFullFile(picPath, true);
- if (hex == null)
- return null;
-
- if (trimLength > -1)
- hex = hex.Substring(0, trimLength);
-
- // TODO: Check for non-zero values in discarded PIC
-
- return Regex.Replace(hex, ".{32}", "$0\n", RegexOptions.Compiled);
- }
- catch
- {
- // We don't care what the error was right now
- return null;
- }
- }
-
- ///
- /// Get a isobuster-formatted PVD from a 2048 byte-per-sector image, if possible
- ///
- /// Path to ISO file
- /// Formatted PVD string, otherwise null
- /// True if PVD was successfully parsed, otherwise false
- protected static bool GetPVD(string isoPath, out string? pvd)
- {
- pvd = null;
- try
- {
- // Get PVD bytes from ISO file
- var buf = new byte[96];
- using (FileStream iso = File.OpenRead(isoPath))
- {
- // TODO: Don't hardcode 0x8320
- iso.Seek(0x8320, SeekOrigin.Begin);
-
- int offset = 0;
- while (offset < 96)
- {
- int read = iso.Read(buf, offset, buf.Length - offset);
- if (read == 0)
- throw new EndOfStreamException();
- offset += read;
- }
- }
-
- // Format PVD to isobuster standard
- char[] pvdCharArray = new char[96];
- for (int i = 0; i < 96; i++)
- {
- if (buf[i] >= 0x20 && buf[i] <= 0x7E)
- pvdCharArray[i] = (char)buf[i];
- else
- pvdCharArray[i] = '.';
- }
- string pvdASCII = new string(pvdCharArray, 0, 96);
- pvd = string.Empty;
- for (int i = 0; i < 96; i += 16)
- {
- pvd += $"{(0x0320 + i):X4} : {buf[i]:X2} {buf[i + 1]:X2} {buf[i + 2]:X2} {buf[i + 3]:X2} {buf[i + 4]:X2} {buf[i + 5]:X2} {buf[i + 6]:X2} {buf[i + 7]:X2} " +
- $"{buf[i + 8]:X2} {buf[i + 9]:X2} {buf[i + 10]:X2} {buf[i + 11]:X2} {buf[i + 12]:X2} {buf[i + 13]:X2} {buf[i + 14]:X2} {buf[i + 15]:X2} {pvdASCII.Substring(i, 16)}\n";
- }
-
- return true;
- }
- catch
- {
- // We don't care what the error is
- return false;
- }
- }
-
- #endregion
}
}
diff --git a/MPF.Core/Modules/CleanRip/Parameters.cs b/MPF.Core/Modules/CleanRip/Parameters.cs
index dc8eba9b..217b587f 100644
--- a/MPF.Core/Modules/CleanRip/Parameters.cs
+++ b/MPF.Core/Modules/CleanRip/Parameters.cs
@@ -1,11 +1,4 @@
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text.RegularExpressions;
-using MPF.Core.Converters;
-using MPF.Core.Data;
-using SabreTools.Hashing;
-using SabreTools.RedumpLib;
+using MPF.Core.Data;
using SabreTools.RedumpLib.Data;
namespace MPF.Core.Modules.CleanRip
@@ -30,376 +23,5 @@ namespace MPF.Core.Modules.CleanRip
: base(system, type, drivePath, filename, driveSpeed, options)
{
}
-
- #region BaseParameters Implementations
-
- ///
- public override (bool, List) CheckAllOutputFilesExist(string basePath, bool preCheck)
- {
- var missingFiles = new List();
- switch (this.Type)
- {
- case MediaType.DVD: // Only added here to help users; not strictly correct
- case MediaType.NintendoGameCubeGameDisc:
- case MediaType.NintendoWiiOpticalDisc:
- if (!File.Exists($"{basePath}_logs.zip") || !preCheck)
- {
- if (!File.Exists($"{basePath}-dumpinfo.txt"))
- missingFiles.Add($"{basePath}-dumpinfo.txt");
- if (!File.Exists($"{basePath}.bca"))
- missingFiles.Add($"{basePath}.bca");
- }
-
- break;
-
- default:
- missingFiles.Add("Media and system combination not supported for CleanRip");
- break;
- }
-
- return (!missingFiles.Any(), missingFiles);
- }
-
- ///
- public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive? drive, bool includeArtifacts)
- {
- // Ensure that required sections exist
- info = Builder.EnsureAllSections(info);
-
- // TODO: Determine if there's a CleanRip version anywhere
- info.DumpingInfo!.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
- info.DumpingInfo.DumpingDate = InfoTool.GetFileModifiedDate(basePath + "-dumpinfo.txt")?.ToString("yyyy-MM-dd HH:mm:ss");
-
- // Get the Datafile information
- var datafile = GenerateCleanripDatafile(basePath + ".iso", basePath + "-dumpinfo.txt");
- info.TracksAndWriteOffsets!.ClrMameProData = InfoTool.GenerateDatfile(datafile);
-
- // Get the individual hash data, as per internal
- if (InfoTool.GetISOHashValues(datafile, out long size, out var crc32, out var md5, out var sha1))
- {
- info.SizeAndChecksums!.Size = size;
- info.SizeAndChecksums.CRC32 = crc32;
- info.SizeAndChecksums.MD5 = md5;
- info.SizeAndChecksums.SHA1 = sha1;
-
- // Dual-layer discs have the same size and layerbreak
- if (size == 8511160320)
- info.SizeAndChecksums.Layerbreak = 2084960;
- }
-
- // Extract info based generically on MediaType
- switch (this.Type)
- {
- case MediaType.DVD: // Only added here to help users; not strictly correct
- case MediaType.NintendoGameCubeGameDisc:
- case MediaType.NintendoWiiOpticalDisc:
- if (File.Exists(basePath + ".bca"))
- info.Extras!.BCA = GetBCA(basePath + ".bca");
-
- if (GetGameCubeWiiInformation(basePath + "-dumpinfo.txt", out Region? gcRegion, out var gcVersion, out var gcName, out var gcSerial))
- {
- info.CommonDiscInfo!.Region = gcRegion ?? info.CommonDiscInfo.Region;
- info.VersionAndEditions!.Version = gcVersion ?? info.VersionAndEditions.Version;
- info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalName] = gcName ?? string.Empty;
- info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = gcSerial ?? string.Empty;
- }
-
- break;
- }
-
- // Fill in any artifacts that exist, Base64-encoded, if we need to
- if (includeArtifacts)
- {
- info.Artifacts ??= [];
-
- if (File.Exists(basePath + ".bca"))
- info.Artifacts["bca"] = GetBase64(GetFullFile(basePath + ".bca", binary: true)) ?? string.Empty;
- if (File.Exists(basePath + "-dumpinfo.txt"))
- info.Artifacts["dumpinfo"] = GetBase64(GetFullFile(basePath + "-dumpinfo.txt")) ?? string.Empty;
- }
- }
-
- ///
- public override List GetLogFilePaths(string basePath)
- {
- var logFiles = new List();
- switch (this.Type)
- {
- case MediaType.DVD: // Only added here to help users; not strictly correct
- case MediaType.NintendoGameCubeGameDisc:
- case MediaType.NintendoWiiOpticalDisc:
- if (File.Exists($"{basePath}-dumpinfo.txt"))
- logFiles.Add($"{basePath}-dumpinfo.txt");
- if (File.Exists($"{basePath}.bca"))
- logFiles.Add($"{basePath}.bca");
-
- break;
- }
-
- return logFiles;
- }
-
- #endregion
-
- #region Information Extraction Methods
-
- ///
- /// Get a formatted datfile from the cleanrip output, if possible
- ///
- /// Path to ISO file
- /// Path to discinfo file
- ///
- private static Datafile? GenerateCleanripDatafile(string iso, string dumpinfo)
- {
- // If the files don't exist, we can't get info from it
- if (!File.Exists(iso) || !File.Exists(dumpinfo))
- return null;
-
- long size = new FileInfo(iso).Length;
- string crc = string.Empty;
- string md5 = string.Empty;
- string sha1 = string.Empty;
-
- try
- {
- // Make sure this file is a dumpinfo
- using var sr = File.OpenText(dumpinfo);
- if (sr.ReadLine()?.Contains("--File Generated by CleanRip") != true)
- return null;
-
- // Read all lines and gather dat information
- while (!sr.EndOfStream)
- {
- var line = sr.ReadLine()?.Trim();
- if (string.IsNullOrEmpty(line))
- continue;
- else if (line!.StartsWith("CRC32"))
- crc = line.Substring(7).ToLowerInvariant();
- else if (line.StartsWith("MD5"))
- md5 = line.Substring(5);
- else if (line.StartsWith("SHA-1"))
- sha1 = line.Substring(7);
- }
-
- // Ensure all checksums were found in log
- if (crc == string.Empty || md5 == string.Empty || sha1 == string.Empty)
- {
- if (HashTool.GetStandardHashes(iso, out long isoSize, out string? isoCRC, out string? isoMD5, out string? isoSHA1))
- {
- crc = isoCRC ?? crc;
- md5 = isoMD5 ?? md5;
- sha1 = isoSHA1 ?? sha1;
- }
- }
-
- return new Datafile
- {
- Games =
- [
- new()
- {
- Roms =
- [
- new Rom { Name = Path.GetFileName(iso), Size = size.ToString(), Crc = crc, Md5 = md5, Sha1 = sha1 },
- ]
- }
- ]
- };
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Get the hex contents of the BCA file
- ///
- /// Path to the BCA file associated with the dump
- /// BCA data as a hex string if possible, null on error
- /// https://stackoverflow.com/questions/9932096/add-separator-to-string-at-every-n-characters
- private static string? GetBCA(string bcaPath)
- {
- // If the file doesn't exist, we can't get the info
- if (!File.Exists(bcaPath))
- return null;
-
- try
- {
- var hex = GetFullFile(bcaPath, true);
- if (hex == null)
- return null;
-
- return Regex.Replace(hex, ".{32}", "$0\n");
- }
- catch
- {
- // We don't care what the error was right now
- return null;
- }
- }
-
- ///
- /// Get a formatted datfile from the cleanrip output, if possible
- ///
- /// Path to ISO file
- /// Path to discinfo file
- ///
- private static string? GetCleanripDatfile(string iso, string dumpinfo)
- {
- // If the files don't exist, we can't get info from it
- if (!File.Exists(iso) || !File.Exists(dumpinfo))
- return null;
-
- long size = new FileInfo(iso).Length;
- string crc = string.Empty;
- string md5 = string.Empty;
- string sha1 = string.Empty;
-
- try
- {
- // Make sure this file is a dumpinfo
- using var sr = File.OpenText(dumpinfo);
- if (sr.ReadLine()?.Contains("--File Generated by CleanRip") != true)
- return null;
-
- // Read all lines and gather dat information
- while (!sr.EndOfStream)
- {
- var line = sr.ReadLine()?.Trim();
- if (string.IsNullOrEmpty(line))
- continue;
- else if (line!.StartsWith("CRC32"))
- crc = line.Substring(7).ToLowerInvariant();
- else if (line.StartsWith("MD5"))
- md5 = line.Substring(5);
- else if (line.StartsWith("SHA-1"))
- sha1 = line.Substring(7);
- }
-
- return $"";
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Get the extracted GC and Wii version
- ///
- /// Path to discinfo file
- /// Output region, if possible
- /// Output internal version of the game
- /// Output internal name of the game
- /// Output internal serial of the game
- ///
- private static bool GetGameCubeWiiInformation(string dumpinfo, out Region? region, out string? version, out string? name, out string? serial)
- {
- region = null; version = null; name = null; serial = null;
-
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(dumpinfo))
- return false;
-
- try
- {
- // Make sure this file is a dumpinfo
- using var sr = File.OpenText(dumpinfo);
- if (sr.ReadLine()?.Contains("--File Generated by CleanRip") != true)
- return false;
-
- // Read all lines and gather dat information
- while (!sr.EndOfStream)
- {
- var line = sr.ReadLine()?.Trim();
- if (string.IsNullOrEmpty(line))
- {
- continue;
- }
- else if (line!.StartsWith("Version"))
- {
- version = line.Substring("Version: ".Length);
- }
- else if (line.StartsWith("Internal Name"))
- {
- name = line.Substring("Internal Name: ".Length);
- }
- else if (line.StartsWith("Filename"))
- {
- serial = line.Substring("Filename: ".Length);
- if (serial.EndsWith("-disc2"))
- serial = serial.Replace("-disc2", string.Empty);
-
- // char gameType = serial[0];
- // string gameid = serial[1] + serial[2];
- // string version = serial[4] + serial[5]
-
- switch (serial[3])
- {
- case 'A':
- region = Region.World;
- break;
- case 'D':
- region = Region.Germany;
- break;
- case 'E':
- region = Region.UnitedStatesOfAmerica;
- break;
- case 'F':
- region = Region.France;
- break;
- case 'I':
- region = Region.Italy;
- break;
- case 'J':
- region = Region.Japan;
- break;
- case 'K':
- region = Region.SouthKorea;
- break;
- case 'L':
- region = Region.Europe; // Japanese import to Europe
- break;
- case 'M':
- region = Region.Europe; // American import to Europe
- break;
- case 'N':
- region = Region.UnitedStatesOfAmerica; // Japanese import to USA
- break;
- case 'P':
- region = Region.Europe;
- break;
- case 'R':
- region = Region.RussianFederation;
- break;
- case 'S':
- region = Region.Spain;
- break;
- case 'Q':
- region = Region.SouthKorea; // Korea with Japanese language
- break;
- case 'T':
- region = Region.SouthKorea; // Korea with English language
- break;
- case 'X':
- region = null; // Not a real region code
- break;
- }
- }
- }
-
- return true;
- }
- catch
- {
- // We don't care what the exception is right now
- return false;
- }
- }
-
- #endregion
}
}
diff --git a/MPF.Core/Modules/DiscImageCreator/Parameters.cs b/MPF.Core/Modules/DiscImageCreator/Parameters.cs
index cedd230f..60c16b3d 100644
--- a/MPF.Core/Modules/DiscImageCreator/Parameters.cs
+++ b/MPF.Core/Modules/DiscImageCreator/Parameters.cs
@@ -3,10 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
-using MPF.Core.Converters;
using MPF.Core.Data;
-using MPF.Core.Utilities;
-using SabreTools.RedumpLib;
using SabreTools.RedumpLib.Data;
namespace MPF.Core.Modules.DiscImageCreator
@@ -173,734 +170,6 @@ namespace MPF.Core.Modules.DiscImageCreator
#region BaseParameters Implementations
- ///
- public override (bool, List) CheckAllOutputFilesExist(string basePath, bool preCheck)
- {
- /*
- If there are no external programs, such as error checking, etc., DIC outputs
- a slightly different set of files. This reduced set needs to be documented in
- order for special use cases, such as self-built versions of DIC or removed
- helper programs, can be detected to the best of our ability. Below is the list
- of files that are generated in that case:
-
- .bin
- .c2
- .ccd
- .cue
- .img/.imgtmp
- .scm/.scmtmp
- .sub/.subtmp
- _cmd.txt (formerly)
- _img.cue
-
- This list needs to be translated into the minimum viable set of information
- such that things like error checking can be passed back as a flag, or some
- similar method.
-
- Here are some notes about the various output files and what they represent:
- - bin - Final split output disc image (CD/GD only)
- - c2 - Represents each byte per sector as one bit; 0 means no error, 1 means error
- - c2Error - Human-readable version of `c2`; only errors are printed
- - ccd - CloneCD control file referencing the `img` file
- - cmd - Represents the commandline that was run
- - cue - CDRWIN cuesheet referencing the `bin` file(s)
- - dat - Logiqx datfile referencing the `bin` file(s)
- - disc - Disc metadata and information
- - drive - Drive metadata and information
- - img - CloneCD output disc image (CD/GD only)
- - img.cue - CDRWIN cuesheet referencing the `img` file
- - img_EdcEcc - ECC check output as run on the `img` file
- - iso - Final output disc image (DVD/BD only)
- - mainError - Read, drive, or system errors
- - mainInfo - ISOBuster-formatted sector information
- - scm - Scrambled disc image
- - sub - Binary subchannel data as read from the disc
- - subError - Subchannel read errors
- - subInfo - Subchannel informational messages
- - subIntention - Subchannel intentional error information
- - subReadable - Human-readable version of `sub`
- - toc - Binary representation of the table of contents
- - volDesc - Volume descriptor information
- */
-
- var missingFiles = new List();
- switch (this.Type)
- {
- case MediaType.CDROM:
- case MediaType.GDROM:
- if (!File.Exists($"{basePath}.cue"))
- missingFiles.Add($"{basePath}.cue");
- if (!File.Exists($"{basePath}.img") && !File.Exists($"{basePath}.imgtmp"))
- missingFiles.Add($"{basePath}.img");
-
- // Audio-only discs don't output these files
- if (!this.System.IsAudio())
- {
- if (!File.Exists($"{basePath}.scm") && !File.Exists($"{basePath}.scmtmp"))
- missingFiles.Add($"{basePath}.scm");
- }
-
- if (!File.Exists($"{basePath}_logs.zip") || !preCheck)
- {
- // GD-ROM and GD-R don't output this for the HD area
- if (this.Type != MediaType.GDROM)
- {
- if (!File.Exists($"{basePath}.ccd"))
- missingFiles.Add($"{basePath}.ccd");
- }
-
- if (!File.Exists($"{basePath}.dat"))
- missingFiles.Add($"{basePath}.dat");
- if (!File.Exists($"{basePath}.sub") && !File.Exists($"{basePath}.subtmp"))
- missingFiles.Add($"{basePath}.sub");
- if (!File.Exists($"{basePath}_disc.txt"))
- missingFiles.Add($"{basePath}_disc.txt");
- if (!File.Exists($"{basePath}_drive.txt"))
- missingFiles.Add($"{basePath}_drive.txt");
- if (!File.Exists($"{basePath}_img.cue"))
- missingFiles.Add($"{basePath}_img.cue");
- if (!File.Exists($"{basePath}_mainError.txt"))
- missingFiles.Add($"{basePath}_mainError.txt");
- if (!File.Exists($"{basePath}_mainInfo.txt"))
- missingFiles.Add($"{basePath}_mainInfo.txt");
- if (!File.Exists($"{basePath}_subError.txt"))
- missingFiles.Add($"{basePath}_subError.txt");
- if (!File.Exists($"{basePath}_subInfo.txt"))
- missingFiles.Add($"{basePath}_subInfo.txt");
- if (!File.Exists($"{basePath}_subReadable.txt") && !File.Exists($"{basePath}_sub.txt"))
- missingFiles.Add($"{basePath}_subReadable.txt");
- if (!File.Exists($"{basePath}_volDesc.txt"))
- missingFiles.Add($"{basePath}_volDesc.txt");
-
- // Audio-only discs don't output these files
- if (!this.System.IsAudio())
- {
- if (!File.Exists($"{basePath}.img_EdcEcc.txt") && !File.Exists($"{basePath}.img_EccEdc.txt"))
- missingFiles.Add($"{basePath}.img_EdcEcc.txt");
- }
- }
-
- // Removed or inconsistent files
- //{
- // // Doesn't output on Linux
- // if (!File.Exists($"{basePath}.c2"))
- // missingFiles.Add($"{basePath}.c2");
-
- // // Doesn't output on Linux
- // if (!File.Exists($"{basePath}_c2Error.txt"))
- // missingFiles.Add($"{basePath}_c2Error.txt");
-
- // // Replaced by timestamp-named file
- // if (!File.Exists($"{basePath}_cmd.txt"))
- // missingFiles.Add($"{basePath}_cmd.txt");
-
- // // Not guaranteed output
- // if (!File.Exists($"{basePath}_subIntention.txt"))
- // missingFiles.Add($"{basePath}_subIntention.txt");
-
- // // Not guaranteed output
- // if (File.Exists($"{basePath}_suppl.dat"))
- // missingFiles.Add($"{basePath}_suppl.dat");
-
- // // Not guaranteed output (at least PCE)
- // if (!File.Exists($"{basePath}.toc"))
- // missingFiles.Add($"{basePath}.toc");
- //}
-
- break;
-
- case MediaType.DVD:
- case MediaType.HDDVD:
- case MediaType.BluRay:
- case MediaType.NintendoGameCubeGameDisc:
- case MediaType.NintendoWiiOpticalDisc:
- if (!File.Exists($"{basePath}_logs.zip") || !preCheck)
- {
- if (!File.Exists($"{basePath}.dat"))
- missingFiles.Add($"{basePath}.dat");
- if (!File.Exists($"{basePath}_disc.txt"))
- missingFiles.Add($"{basePath}_disc.txt");
- if (!File.Exists($"{basePath}_drive.txt"))
- missingFiles.Add($"{basePath}_drive.txt");
- if (!File.Exists($"{basePath}_mainError.txt"))
- missingFiles.Add($"{basePath}_mainError.txt");
- if (!File.Exists($"{basePath}_mainInfo.txt"))
- missingFiles.Add($"{basePath}_mainInfo.txt");
- if (!File.Exists($"{basePath}_volDesc.txt"))
- missingFiles.Add($"{basePath}_volDesc.txt");
- }
-
- // Removed or inconsistent files
- //{
- // // Replaced by timestamp-named file
- // if (!File.Exists($"{basePath}_cmd.txt"))
- // missingFiles.Add($"{basePath}_cmd.txt");
-
- // // Not guaranteed output
- // if (File.Exists($"{basePath}_CSSKey.txt"))
- // missingFiles.Add($"{basePath}_CSSKey.txt");
-
- // // Only output for some parameters
- // if (File.Exists($"{basePath}.raw"))
- // missingFiles.Add($"{basePath}.raw");
-
- // // Not guaranteed output
- // if (File.Exists($"{basePath}_suppl.dat"))
- // missingFiles.Add($"{basePath}_suppl.dat");
- //}
-
- break;
-
- case MediaType.FloppyDisk:
- case MediaType.HardDisk:
- // TODO: Determine what outputs come out from a HDD, SD, etc.
- if (!File.Exists($"{basePath}_logs.zip") || !preCheck)
- {
- if (!File.Exists($"{basePath}.dat"))
- missingFiles.Add($"{basePath}.dat");
- if (!File.Exists($"{basePath}_disc.txt"))
- missingFiles.Add($"{basePath}_disc.txt");
- }
-
- // Removed or inconsistent files
- //{
- // // Replaced by timestamp-named file
- // if (!File.Exists($"{basePath}_cmd.txt"))
- // missingFiles.Add($"{basePath}_cmd.txt");
- //}
-
- break;
-
- default:
- missingFiles.Add("Media and system combination not supported for DiscImageCreator");
- break;
- }
-
- return (!missingFiles.Any(), missingFiles);
- }
-
- ///
- public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive? drive, bool includeArtifacts)
- {
- var outputDirectory = Path.GetDirectoryName(basePath);
-
- // Ensure that required sections exist
- info = Builder.EnsureAllSections(info);
-
- // Get the dumping program and version
- var (dicCmd, dicVersion) = GetCommandFilePathAndVersion(basePath);
- info.DumpingInfo!.DumpingProgram = $"{EnumConverter.LongName(this.InternalProgram)} {dicVersion ?? "Unknown Version"}";
- info.DumpingInfo.DumpingDate = InfoTool.GetFileModifiedDate(dicCmd)?.ToString("yyyy-MM-dd HH:mm:ss");
-
- // Fill in the hardware data
- if (GetHardwareInfo($"{basePath}_drive.txt", out var manufacturer, out var model, out var firmware))
- {
- info.DumpingInfo.Manufacturer = manufacturer;
- info.DumpingInfo.Model = model;
- info.DumpingInfo.Firmware = firmware;
- }
-
- // Fill in the disc type data
- if (GetDiscType($"{basePath}_disc.txt", out var discTypeOrBookType))
- info.DumpingInfo.ReportedDiscType = discTypeOrBookType;
-
- // Get the Datafile information
- var datafile = InfoTool.GetDatafile($"{basePath}.dat");
-
- // Fill in the hash data
- info.TracksAndWriteOffsets!.ClrMameProData = InfoTool.GenerateDatfile(datafile);
-
- // Fill in the volume labels
- if (GetVolumeLabels($"{basePath}_volDesc.txt", out var volLabels))
- VolumeLabels = volLabels;
-
- // Extract info based generically on MediaType
- switch (this.Type)
- {
- case MediaType.CDROM:
- case MediaType.GDROM: // TODO: Verify GD-ROM outputs this
- info.Extras!.PVD = GetPVD($"{basePath}_mainInfo.txt") ?? "Disc has no PVD";
-
- // Audio-only discs will fail if there are any C2 errors, so they would never get here
- if (this.System.IsAudio())
- {
- info.CommonDiscInfo!.ErrorsCount = "0";
- }
- else
- {
- long errorCount = -1;
- if (File.Exists($"{basePath}.img_EdcEcc.txt"))
- errorCount = GetErrorCount($"{basePath}.img_EdcEcc.txt");
- else if (File.Exists($"{basePath}.img_EccEdc.txt"))
- errorCount = GetErrorCount($"{basePath}.img_EccEdc.txt");
-
- info.CommonDiscInfo!.ErrorsCount = (errorCount == -1 ? "Error retrieving error count" : errorCount.ToString());
- }
-
- info.TracksAndWriteOffsets.Cuesheet = GetFullFile($"{basePath}.cue") ?? string.Empty;
- //var cueSheet = new CueSheet($"{basePath}.cue"); // TODO: Do something with this
-
- // Attempt to get the write offset
- string cdWriteOffset = GetWriteOffset($"{basePath}_disc.txt") ?? string.Empty;
- info.CommonDiscInfo.RingWriteOffset = cdWriteOffset;
- info.TracksAndWriteOffsets.OtherWriteOffsets = cdWriteOffset;
-
- // Attempt to get multisession data
- string cdMultiSessionInfo = GetMultisessionInformation($"{basePath}_disc.txt") ?? string.Empty;
- if (!string.IsNullOrEmpty(cdMultiSessionInfo))
- info.CommonDiscInfo.CommentsSpecialFields![SiteCode.Multisession] = cdMultiSessionInfo;
-
- break;
-
- case MediaType.DVD:
- case MediaType.HDDVD:
- case MediaType.BluRay:
-
- // Get the individual hash data, as per internal
- if (InfoTool.GetISOHashValues(datafile, out long size, out var crc32, out var md5, out var sha1))
- {
- info.SizeAndChecksums!.Size = size;
- info.SizeAndChecksums.CRC32 = crc32;
- info.SizeAndChecksums.MD5 = md5;
- info.SizeAndChecksums.SHA1 = sha1;
- }
-
- // Deal with the layerbreaks
- if (this.Type == MediaType.DVD)
- {
- string layerbreak = GetLayerbreak($"{basePath}_disc.txt", System.IsXGD()) ?? string.Empty;
- info.SizeAndChecksums!.Layerbreak = !string.IsNullOrEmpty(layerbreak) ? Int64.Parse(layerbreak) : default;
- }
- else if (this.Type == MediaType.BluRay)
- {
- var di = InfoTool.GetDiscInformation($"{basePath}_PIC.bin");
- info.SizeAndChecksums!.PICIdentifier = InfoTool.GetPICIdentifier(di);
- if (InfoTool.GetLayerbreaks(di, out long? layerbreak1, out long? layerbreak2, out long? layerbreak3))
- {
- if (layerbreak1 != null && layerbreak1 * 2048 < info.SizeAndChecksums.Size)
- info.SizeAndChecksums.Layerbreak = layerbreak1.Value;
-
- if (layerbreak2 != null && layerbreak2 * 2048 < info.SizeAndChecksums.Size)
- info.SizeAndChecksums.Layerbreak2 = layerbreak2.Value;
-
- if (layerbreak3 != null && layerbreak3 * 2048 < info.SizeAndChecksums.Size)
- info.SizeAndChecksums.Layerbreak3 = layerbreak3.Value;
- }
- }
-
- // Read the PVD
- if (!options.EnableRedumpCompatibility || System != RedumpSystem.MicrosoftXbox)
- info.Extras!.PVD = GetPVD($"{basePath}_mainInfo.txt") ?? string.Empty;
-
- // Bluray-specific options
- if (this.Type == MediaType.BluRay)
- {
- int trimLength = -1;
- switch (this.System)
- {
- case RedumpSystem.MicrosoftXboxOne:
- case RedumpSystem.MicrosoftXboxSeriesXS:
- case RedumpSystem.SonyPlayStation3:
- case RedumpSystem.SonyPlayStation4:
- case RedumpSystem.SonyPlayStation5:
- if (info.SizeAndChecksums!.Layerbreak3 != default)
- trimLength = 520;
- else if (info.SizeAndChecksums!.Layerbreak2 != default)
- trimLength = 392;
- else
- trimLength = 264;
- break;
- }
-
- info.Extras!.PIC = GetPIC($"{basePath}_PIC.bin", trimLength) ?? string.Empty;
- }
-
- break;
- }
-
- // Extract info based specifically on RedumpSystem
- switch (this.System)
- {
- case RedumpSystem.AppleMacintosh:
- case RedumpSystem.EnhancedCD:
- case RedumpSystem.IBMPCcompatible:
- case RedumpSystem.RainbowDisc:
- case RedumpSystem.SonyElectronicBook:
- if (File.Exists($"{basePath}_subIntention.txt"))
- {
- var fi = new FileInfo($"{basePath}_subIntention.txt");
- if (fi.Length > 0)
- info.CopyProtection!.SecuROMData = GetFullFile($"{basePath}_subIntention.txt") ?? string.Empty;
- }
-
- // Needed for some odd copy protections
- info.CopyProtection!.Protection = GetDVDProtection($"{basePath}_CSSKey.txt", $"{basePath}_disc.txt", false) ?? string.Empty;
-
- break;
-
- case RedumpSystem.DVDAudio:
- case RedumpSystem.DVDVideo:
- info.CopyProtection!.Protection = GetDVDProtection($"{basePath}_CSSKey.txt", $"{basePath}_disc.txt", true) ?? string.Empty;
- break;
-
- case RedumpSystem.KonamiPython2:
- info.CommonDiscInfo!.EXEDateBuildDate = GetPlayStationEXEDate($"{basePath}_volDesc.txt", InfoTool.GetPlayStationExecutableName(drive?.Name));
-
- if (InfoTool.GetPlayStationExecutableInfo(drive?.Name, out var pythonTwoSerial, out Region? pythonTwoRegion, out var pythonTwoDate))
- {
- // Ensure internal serial is pulled from local data
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = pythonTwoSerial ?? string.Empty;
- info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? pythonTwoRegion;
- info.CommonDiscInfo.EXEDateBuildDate ??= pythonTwoDate;
- }
-
- info.VersionAndEditions!.Version = InfoTool.GetPlayStation2Version(drive?.Name) ?? string.Empty;
- break;
-
- case RedumpSystem.MicrosoftXbox:
-
- string xmidString;
- if (string.IsNullOrEmpty(outputDirectory))
- xmidString = Tools.GetXGD1XMID($"{basePath}_DMI.bin");
- else
- xmidString = Tools.GetXGD1XMID(Path.Combine(outputDirectory, $"{basePath}_DMI.bin"));
-
- var xmid = SabreTools.Serialization.Wrappers.XMID.Create(xmidString);
- if (xmid != null)
- {
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.XMID] = xmidString?.TrimEnd('\0') ?? string.Empty;
- info.CommonDiscInfo.Serial = xmid.Serial ?? string.Empty;
- if (!options.EnableRedumpCompatibility)
- info.VersionAndEditions!.Version = xmid.Version ?? string.Empty;
-
- info.CommonDiscInfo.Region = InfoTool.GetXGDRegion(xmid.Model.RegionIdentifier);
- }
-
- // If we have the new, external DAT
- if (File.Exists($"{basePath}_suppl.dat"))
- {
- var suppl = InfoTool.GetDatafile($"{basePath}_suppl.dat");
- if (GetXGDAuxHashInfo(suppl, out var xgd1DMIHash, out var xgd1PFIHash, out var xgd1SSHash))
- {
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.DMIHash] = xgd1DMIHash ?? string.Empty;
- info.CommonDiscInfo.CommentsSpecialFields[SiteCode.PFIHash] = xgd1PFIHash ?? string.Empty;
- info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSHash] = xgd1SSHash ?? string.Empty;
- }
-
- if (GetXGDAuxSSInfo($"{basePath}_disc.txt", out var xgd1SS, out var xgd1SSVer))
- {
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.SSVersion] = xgd1SSVer ?? string.Empty;
- info.Extras!.SecuritySectorRanges = xgd1SS ?? string.Empty;
- }
- }
- else
- {
- if (GetXGDAuxInfo($"{basePath}_disc.txt", out var xgd1DMIHash, out var xgd1PFIHash, out var xgd1SSHash, out var xgd1SS, out var xgd1SSVer))
- {
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.DMIHash] = xgd1DMIHash ?? string.Empty;
- info.CommonDiscInfo.CommentsSpecialFields[SiteCode.PFIHash] = xgd1PFIHash ?? string.Empty;
- info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSHash] = xgd1SSHash ?? string.Empty;
- info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSVersion] = xgd1SSVer ?? string.Empty;
- info.Extras!.SecuritySectorRanges = xgd1SS ?? string.Empty;
- }
- }
-
- break;
-
- case RedumpSystem.MicrosoftXbox360:
- string xemidString;
- if (string.IsNullOrEmpty(outputDirectory))
- xemidString = Tools.GetXGD23XeMID($"{basePath}_DMI.bin");
- else
- xemidString = Tools.GetXGD23XeMID(Path.Combine(outputDirectory, $"{basePath}_DMI.bin"));
-
- var xemid = SabreTools.Serialization.Wrappers.XeMID.Create(xemidString);
- if (xemid != null)
- {
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.XeMID] = xemidString?.TrimEnd('\0') ?? string.Empty;
- info.CommonDiscInfo.Serial = xemid.Serial ?? string.Empty;
- if (!options.EnableRedumpCompatibility)
- info.VersionAndEditions!.Version = xemid.Version ?? string.Empty;
-
- info.CommonDiscInfo.Region = InfoTool.GetXGDRegion(xemid.Model.RegionIdentifier);
- }
-
- // If we have the new, external DAT
- if (File.Exists($"{basePath}_suppl.dat"))
- {
- var suppl = InfoTool.GetDatafile($"{basePath}_suppl.dat");
- if (GetXGDAuxHashInfo(suppl, out var xgd23DMIHash, out var xgd23PFIHash, out var xgd23SSHash))
- {
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.DMIHash] = xgd23DMIHash ?? string.Empty;
- info.CommonDiscInfo.CommentsSpecialFields[SiteCode.PFIHash] = xgd23PFIHash ?? string.Empty;
- info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSHash] = xgd23SSHash ?? string.Empty;
- }
-
- if (GetXGDAuxSSInfo($"{basePath}_disc.txt", out var xgd23SS, out var xgd23SSVer))
- {
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.SSVersion] = xgd23SSVer ?? string.Empty;
- info.Extras!.SecuritySectorRanges = xgd23SS ?? string.Empty;
- }
- }
- else
- {
- if (GetXGDAuxInfo($"{basePath}_disc.txt", out var xgd23DMIHash, out var xgd23PFIHash, out var xgd23SSHash, out var xgd23SS, out var xgd23SSVer))
- {
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.DMIHash] = xgd23DMIHash ?? string.Empty;
- info.CommonDiscInfo.CommentsSpecialFields[SiteCode.PFIHash] = xgd23PFIHash ?? string.Empty;
- info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSHash] = xgd23SSHash ?? string.Empty;
- info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SSVersion] = xgd23SSVer ?? string.Empty;
- info.Extras!.SecuritySectorRanges = xgd23SS ?? string.Empty;
- }
- }
-
- break;
-
- case RedumpSystem.NamcoSegaNintendoTriforce:
- if (this.Type == MediaType.CDROM)
- {
- info.Extras!.Header = GetSegaHeader($"{basePath}_mainInfo.txt") ?? string.Empty;
-
- // Take only the first 16 lines for GD-ROM
- if (!string.IsNullOrEmpty(info.Extras.Header))
- info.Extras.Header = string.Join("\n", info.Extras.Header.Split('\n').Take(16).ToArray());
-
- if (GetGDROMBuildInfo(info.Extras.Header, out var gdSerial, out var gdVersion, out var gdDate))
- {
- // Ensure internal serial is pulled from local data
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = gdSerial ?? string.Empty;
- info.VersionAndEditions!.Version = gdVersion ?? string.Empty;
- info.CommonDiscInfo.EXEDateBuildDate = gdDate ?? string.Empty;
- }
- }
-
- break;
-
- case RedumpSystem.SegaMegaCDSegaCD:
- info.Extras!.Header = GetSegaHeader($"{basePath}_mainInfo.txt") ?? string.Empty;
-
- // Take only the last 16 lines for Sega CD
- if (!string.IsNullOrEmpty(info.Extras.Header))
- info.Extras.Header = string.Join("\n", info.Extras.Header.Split('\n').Skip(16).ToArray());
-
- if (GetSegaCDBuildInfo(info.Extras.Header, out var scdSerial, out var fixedDate))
- {
- // Ensure internal serial is pulled from local data
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = scdSerial ?? string.Empty;
- info.CommonDiscInfo.EXEDateBuildDate = fixedDate ?? string.Empty;
- }
-
- break;
-
- case RedumpSystem.SegaChihiro:
- if (this.Type == MediaType.CDROM)
- {
- info.Extras!.Header = GetSegaHeader($"{basePath}_mainInfo.txt") ?? string.Empty;
-
- // Take only the first 16 lines for GD-ROM
- if (!string.IsNullOrEmpty(info.Extras.Header))
- info.Extras.Header = string.Join("\n", info.Extras.Header.Split('\n').Take(16).ToArray());
-
- if (GetGDROMBuildInfo(info.Extras.Header, out var gdSerial, out var gdVersion, out var gdDate))
- {
- // Ensure internal serial is pulled from local data
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = gdSerial ?? string.Empty;
- info.VersionAndEditions!.Version = gdVersion ?? string.Empty;
- info.CommonDiscInfo.EXEDateBuildDate = gdDate ?? string.Empty;
- }
- }
-
- break;
-
- case RedumpSystem.SegaDreamcast:
- if (this.Type == MediaType.CDROM)
- {
- info.Extras!.Header = GetSegaHeader($"{basePath}_mainInfo.txt") ?? string.Empty;
-
- // Take only the first 16 lines for GD-ROM
- if (!string.IsNullOrEmpty(info.Extras.Header))
- info.Extras.Header = string.Join("\n", info.Extras.Header.Split('\n').Take(16).ToArray());
-
- if (GetGDROMBuildInfo(info.Extras.Header, out var gdSerial, out var gdVersion, out var gdDate))
- {
- // Ensure internal serial is pulled from local data
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = gdSerial ?? string.Empty;
- info.VersionAndEditions!.Version = gdVersion ?? string.Empty;
- info.CommonDiscInfo.EXEDateBuildDate = gdDate ?? string.Empty;
- }
- }
-
- break;
-
- case RedumpSystem.SegaNaomi:
- if (this.Type == MediaType.CDROM)
- {
- info.Extras!.Header = GetSegaHeader($"{basePath}_mainInfo.txt") ?? string.Empty;
-
- // Take only the first 16 lines for GD-ROM
- if (!string.IsNullOrEmpty(info.Extras.Header))
- info.Extras.Header = string.Join("\n", info.Extras.Header.Split('\n').Take(16).ToArray());
-
- if (GetGDROMBuildInfo(info.Extras.Header, out var gdSerial, out var gdVersion, out var gdDate))
- {
- // Ensure internal serial is pulled from local data
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = gdSerial ?? string.Empty;
- info.VersionAndEditions!.Version = gdVersion ?? string.Empty;
- info.CommonDiscInfo.EXEDateBuildDate = gdDate ?? string.Empty;
- }
- }
-
- break;
-
- case RedumpSystem.SegaNaomi2:
- if (this.Type == MediaType.CDROM)
- {
- info.Extras!.Header = GetSegaHeader($"{basePath}_mainInfo.txt") ?? string.Empty;
-
- // Take only the first 16 lines for GD-ROM
- if (!string.IsNullOrEmpty(info.Extras.Header))
- info.Extras.Header = string.Join("\n", info.Extras.Header.Split('\n').Take(16).ToArray());
-
- if (GetGDROMBuildInfo(info.Extras.Header, out var gdSerial, out var gdVersion, out var gdDate))
- {
- // Ensure internal serial is pulled from local data
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = gdSerial ?? string.Empty;
- info.VersionAndEditions!.Version = gdVersion ?? string.Empty;
- info.CommonDiscInfo.EXEDateBuildDate = gdDate ?? string.Empty;
- }
- }
-
- break;
-
- case RedumpSystem.SegaSaturn:
- info.Extras!.Header = GetSegaHeader($"{basePath}_mainInfo.txt") ?? string.Empty;
-
- // Take only the first 16 lines for Saturn
- if (!string.IsNullOrEmpty(info.Extras.Header))
- info.Extras.Header = string.Join("\n", info.Extras.Header.Split('\n').Take(16).ToArray());
-
- if (GetSaturnBuildInfo(info.Extras.Header, out var saturnSerial, out var saturnVersion, out var buildDate))
- {
- // Ensure internal serial is pulled from local data
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = saturnSerial ?? string.Empty;
- info.VersionAndEditions!.Version = saturnVersion ?? string.Empty;
- info.CommonDiscInfo.EXEDateBuildDate = buildDate ?? string.Empty;
- }
-
- break;
-
- case RedumpSystem.SonyPlayStation:
- info.CommonDiscInfo!.EXEDateBuildDate = GetPlayStationEXEDate($"{basePath}_volDesc.txt", InfoTool.GetPlayStationExecutableName(drive?.Name), true);
-
- if (InfoTool.GetPlayStationExecutableInfo(drive?.Name, out var playstationSerial, out Region? playstationRegion, out var playstationDate))
- {
- // Ensure internal serial is pulled from local data
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = playstationSerial ?? string.Empty;
- info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationRegion;
- info.CommonDiscInfo.EXEDateBuildDate ??= playstationDate;
- }
-
- bool? psEdcStatus = null;
- if (File.Exists($"{basePath}.img_EdcEcc.txt"))
- psEdcStatus = GetPlayStationEDCStatus($"{basePath}.img_EdcEcc.txt");
- else if (File.Exists($"{basePath}.img_EccEdc.txt"))
- psEdcStatus = GetPlayStationEDCStatus($"{basePath}.img_EccEdc.txt");
-
- info.EDC!.EDC = psEdcStatus.ToYesNo();
- info.CopyProtection!.AntiModchip = GetPlayStationAntiModchipDetected($"{basePath}_disc.txt").ToYesNo();
- break;
-
- case RedumpSystem.SonyPlayStation2:
- info.CommonDiscInfo!.EXEDateBuildDate = GetPlayStationEXEDate($"{basePath}_volDesc.txt", InfoTool.GetPlayStationExecutableName(drive?.Name));
-
- if (InfoTool.GetPlayStationExecutableInfo(drive?.Name, out var playstationTwoSerial, out Region? playstationTwoRegion, out var playstationTwoDate))
- {
- // Ensure internal serial is pulled from local data
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = playstationTwoSerial ?? string.Empty;
- info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationTwoRegion;
- info.CommonDiscInfo.EXEDateBuildDate ??= playstationTwoDate;
- }
-
- info.VersionAndEditions!.Version = InfoTool.GetPlayStation2Version(drive?.Name) ?? string.Empty;
- break;
-
- case RedumpSystem.SonyPlayStation3:
- info.VersionAndEditions!.Version = InfoTool.GetPlayStation3Version(drive?.Name) ?? string.Empty;
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = InfoTool.GetPlayStation3Serial(drive?.Name) ?? string.Empty;
- string? firmwareVersion = InfoTool.GetPlayStation3FirmwareVersion(drive?.Name);
- if (firmwareVersion != null)
- info.CommonDiscInfo!.ContentsSpecialFields![SiteCode.Patches] = $"PS3 Firmware {firmwareVersion}";
- break;
-
- case RedumpSystem.SonyPlayStation4:
- info.VersionAndEditions!.Version = InfoTool.GetPlayStation4Version(drive?.Name) ?? string.Empty;
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = InfoTool.GetPlayStation4Serial(drive?.Name) ?? string.Empty;
- break;
-
- case RedumpSystem.SonyPlayStation5:
- info.VersionAndEditions!.Version = InfoTool.GetPlayStation5Version(drive?.Name) ?? string.Empty;
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = InfoTool.GetPlayStation5Serial(drive?.Name) ?? string.Empty;
- break;
- }
-
- // Fill in any artifacts that exist, Base64-encoded, if we need to
- if (includeArtifacts)
- {
- info.Artifacts ??= [];
-
- //if (File.Exists($"{basePath}.c2"))
- // info.Artifacts["c2"] = Convert.ToBase64String(File.ReadAllBytes($"{basePath}.c2")) ?? string.Empty;
- if (File.Exists($"{basePath}_c2Error.txt"))
- info.Artifacts["c2Error"] = GetBase64(GetFullFile($"{basePath}_c2Error.txt")) ?? string.Empty;
- if (File.Exists($"{basePath}.ccd"))
- info.Artifacts["ccd"] = GetBase64(GetFullFile($"{basePath}.ccd")) ?? string.Empty;
- if (File.Exists($"{basePath}_cmd.txt")) // TODO: Figure out how to read in the timestamp-named file
- info.Artifacts["cmd"] = GetBase64(GetFullFile($"{basePath}_cmd.txt")) ?? string.Empty;
- if (File.Exists($"{basePath}_CSSKey.txt"))
- info.Artifacts["csskey"] = GetBase64(GetFullFile($"{basePath}_CSSKey.txt")) ?? string.Empty;
- if (File.Exists($"{basePath}.cue"))
- info.Artifacts["cue"] = GetBase64(GetFullFile($"{basePath}.cue")) ?? string.Empty;
- if (File.Exists($"{basePath}.dat"))
- info.Artifacts["dat"] = GetBase64(GetFullFile($"{basePath}.dat")) ?? string.Empty;
- if (File.Exists($"{basePath}_disc.txt"))
- info.Artifacts["disc"] = GetBase64(GetFullFile($"{basePath}_disc.txt")) ?? string.Empty;
- //if (File.Exists(Path.Combine(outputDirectory, $"{basePath}_DMI.bin")))
- // info.Artifacts["dmi"] = Convert.ToBase64String(File.ReadAllBytes(Path.Combine(outputDirectory, $"{basePath}_DMI.bin"))) ?? string.Empty;
- if (File.Exists($"{basePath}_drive.txt"))
- info.Artifacts["drive"] = GetBase64(GetFullFile($"{basePath}_drive.txt")) ?? string.Empty;
- if (File.Exists($"{basePath}_img.cue"))
- info.Artifacts["img_cue"] = GetBase64(GetFullFile($"{basePath}_img.cue")) ?? string.Empty;
- if (File.Exists($"{basePath}.img_EdcEcc.txt"))
- info.Artifacts["img_EdcEcc"] = GetBase64(GetFullFile($"{basePath}.img_EdcEcc.txt")) ?? string.Empty;
- if (File.Exists($"{basePath}.img_EccEdc.txt"))
- info.Artifacts["img_EdcEcc"] = GetBase64(GetFullFile($"{basePath}.img_EccEdc.txt")) ?? string.Empty;
- if (File.Exists($"{basePath}_mainError.txt"))
- info.Artifacts["mainError"] = GetBase64(GetFullFile($"{basePath}_mainError.txt")) ?? string.Empty;
- if (File.Exists($"{basePath}_mainInfo.txt"))
- info.Artifacts["mainInfo"] = GetBase64(GetFullFile($"{basePath}_mainInfo.txt")) ?? string.Empty;
- //if (File.Exists($"{basePath}_PFI.bin"))
- // info.Artifacts["pfi"] = Convert.ToBase64String(File.ReadAllBytes($"{basePath}_PFI.bin")) ?? string.Empty;
- //if (File.Exists($"{basePath}_PIC.bin"))
- // info.Artifacts["pic"] = Convert.ToBase64String(File.ReadAllBytes($"{basePath}_PIC.bin")) ?? string.Empty;
- //if (File.Exists($"{basePath}_SS.bin"))
- // info.Artifacts["ss"] = Convert.ToBase64String(File.ReadAllBytes($"{basePath}_SS.bin")) ?? string.Empty;
- if (File.Exists($"{basePath}.sub"))
- info.Artifacts["sub"] = Convert.ToBase64String(File.ReadAllBytes($"{basePath}.sub")) ?? string.Empty;
- if (File.Exists($"{basePath}_subError.txt"))
- info.Artifacts["subError"] = GetBase64(GetFullFile($"{basePath}_subError.txt")) ?? string.Empty;
- if (File.Exists($"{basePath}_subInfo.txt"))
- info.Artifacts["subInfo"] = GetBase64(GetFullFile($"{basePath}_subInfo.txt")) ?? string.Empty;
- if (File.Exists($"{basePath}_subIntention.txt"))
- info.Artifacts["subIntention"] = GetBase64(GetFullFile($"{basePath}_subIntention.txt")) ?? string.Empty;
- //if (File.Exists($"{basePath}_sub.txt"))
- // info.Artifacts["subReadable"] = GetBase64(GetFullFile($"{basePath}_sub.txt")) ?? string.Empty;
- //if (File.Exists($"{basePath}_subReadable.txt"))
- // info.Artifacts["subReadable"] = GetBase64(GetFullFile($"{basePath}_subReadable.txt")) ?? string.Empty;
- if (File.Exists($"{basePath}_volDesc.txt"))
- info.Artifacts["volDesc"] = GetBase64(GetFullFile($"{basePath}_volDesc.txt")) ?? string.Empty;
- }
- }
-
///
public override string? GenerateParameters()
{
@@ -1596,182 +865,6 @@ namespace MPF.Core.Modules.DiscImageCreator
///
public override string? GetDefaultExtension(MediaType? mediaType) => Converters.Extension(mediaType);
- ///
- public override List GetDeleteableFilePaths(string basePath)
- {
- var deleteableFiles = new List();
- switch (this.Type)
- {
- case MediaType.CDROM:
- case MediaType.GDROM:
- if (File.Exists($"{basePath}.img"))
- deleteableFiles.Add($"{basePath}.img");
- if (File.Exists($"{basePath} (Track 0).img"))
- deleteableFiles.Add($"{basePath} (Track 0).img");
- if (File.Exists($"{basePath} (Track 00).img"))
- deleteableFiles.Add($"{basePath} (Track 00).img");
- if (File.Exists($"{basePath} (Track 1)(-LBA).img"))
- deleteableFiles.Add($"{basePath} (Track 1)(-LBA).img");
- if (File.Exists($"{basePath} (Track 01)(-LBA).img"))
- deleteableFiles.Add($"{basePath} (Track 01)(-LBA).img");
- if (File.Exists($"{basePath} (Track AA).img"))
- deleteableFiles.Add($"{basePath} (Track AA).img");
-
- if (File.Exists($"{basePath}.scm"))
- deleteableFiles.Add($"{basePath}.scm");
- if (File.Exists($"{basePath} (Track 0).scm"))
- deleteableFiles.Add($"{basePath} (Track 0).scm");
- if (File.Exists($"{basePath} (Track 00).scm"))
- deleteableFiles.Add($"{basePath} (Track 00).scm");
- if (File.Exists($"{basePath} (Track 1)(-LBA).scm"))
- deleteableFiles.Add($"{basePath} (Track 1)(-LBA).scm");
- if (File.Exists($"{basePath} (Track 01)(-LBA).scm"))
- deleteableFiles.Add($"{basePath} (Track 01)(-LBA).scm");
- if (File.Exists($"{basePath} (Track AA).scm"))
- deleteableFiles.Add($"{basePath} (Track AA).scm");
-
- break;
-
- case MediaType.DVD:
- case MediaType.HDDVD:
- case MediaType.BluRay:
- case MediaType.NintendoGameCubeGameDisc:
- case MediaType.NintendoWiiOpticalDisc:
- if (File.Exists($"{basePath}.raw"))
- deleteableFiles.Add($"{basePath}.raw");
-
- break;
- }
-
- return deleteableFiles;
- }
-
- ///
- public override List GetLogFilePaths(string basePath)
- {
- (var cmdPath, _) = GetCommandFilePathAndVersion(basePath);
-
- var logFiles = new List();
- switch (this.Type)
- {
- case MediaType.CDROM:
- case MediaType.GDROM:
- if (File.Exists($"{basePath}.c2"))
- logFiles.Add($"{basePath}.c2");
- if (File.Exists($"{basePath}_c2Error.txt"))
- logFiles.Add($"{basePath}_c2Error.txt");
- if (File.Exists($"{basePath}.ccd"))
- logFiles.Add($"{basePath}.ccd");
- if (cmdPath != null && File.Exists(cmdPath))
- logFiles.Add(cmdPath);
- if (File.Exists($"{basePath}_cmd.txt"))
- logFiles.Add($"{basePath}_cmd.txt");
- if (File.Exists($"{basePath}.dat"))
- logFiles.Add($"{basePath}.dat");
- if (File.Exists($"{basePath}.sub"))
- logFiles.Add($"{basePath}.sub");
- if (File.Exists($"{basePath} (Track 0).sub"))
- logFiles.Add($"{basePath} (Track 0).sub");
- if (File.Exists($"{basePath} (Track 00).sub"))
- logFiles.Add($"{basePath} (Track 00).sub");
- if (File.Exists($"{basePath} (Track 1)(-LBA).sub"))
- logFiles.Add($"{basePath} (Track 1)(-LBA).sub");
- if (File.Exists($"{basePath} (Track 01)(-LBA).sub"))
- logFiles.Add($"{basePath} (Track 01)(-LBA).sub");
- if (File.Exists($"{basePath} (Track AA).sub"))
- logFiles.Add($"{basePath} (Track AA).sub");
- if (File.Exists($"{basePath}.subtmp"))
- logFiles.Add($"{basePath}.subtmp");
- if (File.Exists($"{basePath}.toc"))
- logFiles.Add($"{basePath}.toc");
- if (File.Exists($"{basePath}_disc.txt"))
- logFiles.Add($"{basePath}_disc.txt");
- if (File.Exists($"{basePath}_drive.txt"))
- logFiles.Add($"{basePath}_drive.txt");
- if (File.Exists($"{basePath}_img.cue"))
- logFiles.Add($"{basePath}_img.cue");
- if (File.Exists($"{basePath}.img_EdcEcc.txt"))
- logFiles.Add($"{basePath}.img_EdcEcc.txt");
- if (File.Exists($"{basePath}.img_EccEdc.txt"))
- logFiles.Add($"{basePath}.img_EccEdc.txt");
- if (File.Exists($"{basePath}_mainError.txt"))
- logFiles.Add($"{basePath}_mainError.txt");
- if (File.Exists($"{basePath}_mainInfo.txt"))
- logFiles.Add($"{basePath}_mainInfo.txt");
- if (File.Exists($"{basePath}_sub.txt"))
- logFiles.Add($"{basePath}_sub.txt");
- if (File.Exists($"{basePath}_subError.txt"))
- logFiles.Add($"{basePath}_subError.txt");
- if (File.Exists($"{basePath}_subInfo.txt"))
- logFiles.Add($"{basePath}_subInfo.txt");
- if (File.Exists($"{basePath}_subIntention.txt"))
- logFiles.Add($"{basePath}_subIntention.txt");
- if (File.Exists($"{basePath}_subReadable.txt"))
- logFiles.Add($"{basePath}_subReadable.txt");
- if (File.Exists($"{basePath}_suppl.dat"))
- logFiles.Add($"{basePath}_suppl.dat");
- if (File.Exists($"{basePath}_volDesc.txt"))
- logFiles.Add($"{basePath}_volDesc.txt");
-
- break;
-
- case MediaType.DVD:
- case MediaType.HDDVD:
- case MediaType.BluRay:
- case MediaType.NintendoGameCubeGameDisc:
- case MediaType.NintendoWiiOpticalDisc:
- if (cmdPath != null && File.Exists(cmdPath))
- logFiles.Add(cmdPath);
- if (File.Exists($"{basePath}_cmd.txt"))
- logFiles.Add($"{basePath}_cmd.txt");
- if (File.Exists($"{basePath}_CSSKey.txt"))
- logFiles.Add($"{basePath}_CSSKey.txt");
- if (File.Exists($"{basePath}.dat"))
- logFiles.Add($"{basePath}.dat");
- if (File.Exists($"{basePath}.toc"))
- logFiles.Add($"{basePath}.toc");
- if (File.Exists($"{basePath}_disc.txt"))
- logFiles.Add($"{basePath}_disc.txt");
- if (File.Exists($"{basePath}_drive.txt"))
- logFiles.Add($"{basePath}_drive.txt");
- if (File.Exists($"{basePath}_mainError.txt"))
- logFiles.Add($"{basePath}_mainError.txt");
- if (File.Exists($"{basePath}_mainInfo.txt"))
- logFiles.Add($"{basePath}_mainInfo.txt");
- if (File.Exists($"{basePath}_suppl.dat"))
- logFiles.Add($"{basePath}_suppl.dat");
- if (File.Exists($"{basePath}_volDesc.txt"))
- logFiles.Add($"{basePath}_volDesc.txt");
-
- if (File.Exists($"{basePath}_DMI.bin"))
- logFiles.Add($"{basePath}_DMI.bin");
- if (File.Exists($"{basePath}_PFI.bin"))
- logFiles.Add($"{basePath}_PFI.bin");
- if (File.Exists($"{basePath}_PIC.bin"))
- logFiles.Add($"{basePath}_PIC.bin");
- if (File.Exists($"{basePath}_SS.bin"))
- logFiles.Add($"{basePath}_SS.bin");
-
- break;
-
- case MediaType.FloppyDisk:
- case MediaType.HardDisk:
- // TODO: Determine what outputs come out from a HDD, SD, etc.
- if (cmdPath != null && File.Exists(cmdPath))
- logFiles.Add(cmdPath);
- if (File.Exists($"{basePath}_cmd.txt"))
- logFiles.Add($"{basePath}_cmd.txt");
- if (File.Exists($"{basePath}.dat"))
- logFiles.Add($"{basePath}.dat");
- if (File.Exists($"{basePath}_disc.txt"))
- logFiles.Add($"{basePath}_disc.txt");
-
- break;
- }
-
- return logFiles;
- }
-
///
public override MediaType? GetMediaType() => Converters.ToMediaType(BaseCommand);
@@ -2569,37 +1662,6 @@ namespace MPF.Core.Modules.DiscImageCreator
#region Private Extra Methods
- ///
- /// Get the command file path and extract the version from it
- ///
- /// Base filename and path to use for checking
- /// Tuple of file path and version as strings, both null on error
- private static (string?, string?) GetCommandFilePathAndVersion(string basePath)
- {
- // If we have an invalid base path, we can do nothing
- if (string.IsNullOrEmpty(basePath))
- return (null, null);
-
- // Generate the matching regex based on the base path
- string basePathFileName = Path.GetFileName(basePath);
- var cmdFilenameRegex = new Regex(Regex.Escape(basePathFileName) + @"_(\d{8})T\d{6}\.txt");
-
- // Find the first match for the command file
- var parentDirectory = Path.GetDirectoryName(basePath);
- if (string.IsNullOrEmpty(parentDirectory))
- return (null, null);
-
- var currentFiles = Directory.GetFiles(parentDirectory);
- var commandPath = currentFiles.FirstOrDefault(f => cmdFilenameRegex.IsMatch(f));
- if (string.IsNullOrEmpty(commandPath))
- return (null, null);
-
- // Extract the version string
- var match = cmdFilenameRegex.Match(commandPath);
- string version = match.Groups[1].Value;
- return (commandPath, version);
- }
-
///
/// Set the DIC command to be used for a given system and media type
///
@@ -2663,1230 +1725,5 @@ namespace MPF.Core.Modules.DiscImageCreator
}
#endregion
-
- #region Information Extraction Methods
-
- ///
- /// Get reported disc type information, if possible
- ///
- /// _disc.txt file location
- /// True if disc type info was set, false otherwise
- private static bool GetDiscType(string drive, out string? discTypeOrBookType)
- {
- // Set the default values
- discTypeOrBookType = null;
-
- // If the file doesn't exist, we can't get the info
- if (!File.Exists(drive))
- return false;
-
- try
- {
- // Create a hashset to contain all of the found values
- var discTypeOrBookTypeSet = new HashSet();
-
- using var sr = File.OpenText(drive);
- var line = sr.ReadLine();
- while (line != null)
- {
- // Trim the line for later use
- line = line.Trim();
-
- // Concatenate all found values for each possible line type
- if (line.StartsWith("DiscType:"))
- {
- // DiscType:
- string identifier = line.Substring("DiscType: ".Length);
- discTypeOrBookTypeSet.Add(identifier);
- }
- else if (line.StartsWith("DiscTypeIdentifier:"))
- {
- // DiscTypeIdentifier:
- string identifier = line.Substring("DiscTypeIdentifier: ".Length);
- discTypeOrBookTypeSet.Add(identifier);
- }
- else if (line.StartsWith("DiscTypeSpecific:"))
- {
- // DiscTypeSpecific:
- string identifier = line.Substring("DiscTypeSpecific: ".Length);
- discTypeOrBookTypeSet.Add(identifier);
- }
- else if (line.StartsWith("BookType:"))
- {
- // BookType:
- string identifier = line.Substring("BookType: ".Length);
- discTypeOrBookTypeSet.Add(identifier);
- }
-
- line = sr.ReadLine();
- }
-
- // Create the output string
- if (discTypeOrBookTypeSet.Any())
- discTypeOrBookType = string.Join(", ", [.. discTypeOrBookTypeSet.OrderBy(s => s)]);
-
- return true;
- }
- catch
- {
- // We don't care what the exception is right now
- discTypeOrBookType = null;
- return false;
- }
- }
-
- ///
- /// Get all Volume Identifiers
- ///
- /// _volDesc.txt file location
- /// Volume labels (by type), or null if none present
- private static bool GetVolumeLabels(string volDesc, out Dictionary> volLabels)
- {
- // If the file doesn't exist, can't get the volume labels
- volLabels = [];
- if (!File.Exists(volDesc))
- return false;
-
- try
- {
- using var sr = File.OpenText(volDesc);
- var line = sr.ReadLine();
-
- string volType = "UNKNOWN";
- string label;
- while (line != null)
- {
- // Trim the line for later use
- line = line.Trim();
-
- // ISO9660 and extensions section
- if (line.StartsWith("Volume Descriptor Type: "))
- {
- Int32.TryParse(line.Substring("Volume Descriptor Type: ".Length), out int volTypeInt);
- volType = volTypeInt switch
- {
- // 0 => "Boot Record" // Should not not contain a Volume Identifier
- 1 => "ISO", // ISO9660
- 2 => "Joliet",
- // 3 => "Volume Partition Descriptor" // Should not not contain a Volume Identifier
- // 255 => "???" // Should not not contain a Volume Identifier
- _ => "UNKNOWN" // Should not contain a Volume Identifier
- };
- }
- // UDF section
- else if (line.StartsWith("Primary Volume Descriptor Number:"))
- {
- volType = "UDF";
- }
- // Identifier
- else if (line.StartsWith("Volume Identifier: "))
- {
- label = line.Substring("Volume Identifier: ".Length);
-
- // Remove leading non-printable character (unsure why DIC outputs this)
- if (Convert.ToUInt32(label[0]) == 0x7F || Convert.ToUInt32(label[0]) < 0x20)
- label = label.Substring(1);
-
- // Skip if label is blank
- if (label == null || label.Length <= 0)
- {
- volType = "UNKNOWN";
- line = sr.ReadLine();
- continue;
- }
-
- if (volLabels.ContainsKey(label))
- volLabels[label].Add(volType);
- else
- volLabels.Add(label, [volType]);
-
- // Reset volume type
- volType = "UNKNOWN";
- }
-
- line = sr.ReadLine();
- }
-
- // Return true if a volume label was found
- return volLabels.Count > 0;
- }
- catch
- {
- // We don't care what the exception is right now
- volLabels = [];
- return false;
- }
- }
-
- ///
- /// Get the DVD protection information, if possible
- ///
- /// _CSSKey.txt file location
- /// _disc.txt file location
- /// Indicates whether region and protection type are always included
- /// Formatted string representing the DVD protection, null on error
- private static string? GetDVDProtection(string cssKey, string disc, bool includeAlways)
- {
- // If one of the files doesn't exist, we can't get info from them
- if (!File.Exists(disc))
- return null;
-
- // Setup all of the individual pieces
- string? region = null, rceProtection = null, copyrightProtectionSystemType = null, vobKeys = null, decryptedDiscKey = null;
-
- // Get everything from _disc.txt first
- using (var sr = File.OpenText(disc))
- {
- try
- {
- // Fast forward to the copyright information
- while (sr.ReadLine()?.Trim()?.StartsWith("========== CopyrightInformation ==========") == false) ;
-
- // Now read until we hit the manufacturing information
- var line = sr.ReadLine()?.Trim();
- while (line?.StartsWith("========== ManufacturingInformation ==========") == false)
- {
- if (line == null)
- break;
-
- if (line.StartsWith("CopyrightProtectionType"))
- copyrightProtectionSystemType = line.Substring("CopyrightProtectionType: ".Length);
- else if (line.StartsWith("RegionManagementInformation"))
- region = line.Substring("RegionManagementInformation: ".Length);
-
- line = sr.ReadLine()?.Trim();
- }
- }
- catch { }
- }
-
- // Get everything from _CSSKey.txt next, if it exists
- if (File.Exists(cssKey))
- {
- try
- {
- // Read until the end
- using var sr = File.OpenText(cssKey);
- while (!sr.EndOfStream)
- {
- var line = sr.ReadLine()?.Trim();
- if (line == null)
- break;
-
- if (line.StartsWith("DecryptedDiscKey"))
- {
- decryptedDiscKey = line.Substring("DecryptedDiscKey[020]: ".Length);
- }
- else if (line.StartsWith("LBA:"))
- {
- // Set the key string if necessary
- vobKeys ??= string.Empty;
-
- // No keys
- if (line.Contains("No TitleKey"))
- {
- var match = Regex.Match(line, @"^LBA:\s*[0-9]+, Filename: (.*?), No TitleKey$", RegexOptions.Compiled);
- string matchedFilename = match.Groups[1].Value;
- if (matchedFilename.EndsWith(";1"))
- matchedFilename = matchedFilename.Substring(0, matchedFilename.Length - 2);
-
- vobKeys += $"{matchedFilename} Title Key: No Title Key\n";
- }
- else
- {
- var match = Regex.Match(line, @"^LBA:\s*[0-9]+, Filename: (.*?), EncryptedTitleKey: .*?, DecryptedTitleKey: (.*?)$", RegexOptions.Compiled);
- string matchedFilename = match.Groups[1].Value;
- if (matchedFilename.EndsWith(";1"))
- matchedFilename = matchedFilename.Substring(0, matchedFilename.Length - 2);
-
- vobKeys += $"{matchedFilename} Title Key: {match.Groups[2].Value}\n";
- }
- }
- }
- }
- catch { }
- }
-
- // Filter out if we're not always including information
- if (!includeAlways)
- {
- if (region == "1 2 3 4 5 6 7 8")
- region = null;
- if (copyrightProtectionSystemType == "No")
- copyrightProtectionSystemType = null;
- }
-
- // Now we format everything we can
- string protection = string.Empty;
- if (!string.IsNullOrEmpty(region))
- protection += $"Region: {region}\n";
- if (!string.IsNullOrEmpty(rceProtection))
- protection += $"RCE Protection: {rceProtection}\n";
- if (!string.IsNullOrEmpty(copyrightProtectionSystemType))
- protection += $"Copyright Protection System Type: {copyrightProtectionSystemType}\n";
- if (!string.IsNullOrEmpty(vobKeys))
- protection += vobKeys;
- if (!string.IsNullOrEmpty(decryptedDiscKey))
- protection += $"Decrypted Disc Key: {decryptedDiscKey}\n";
-
- return protection;
- }
-
- ///
- /// Get the detected error count from the input files, if possible
- ///
- /// .img_EdcEcc.txt/.img_EccEdc.txt file location
- /// Error count if possible, -1 on error
- private static long GetErrorCount(string edcecc)
- {
- // TODO: Better usage of _mainInfo and _c2Error for uncorrectable errors
-
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(edcecc))
- return -1;
-
- // Get a total error count for after
- long? totalErrors = null;
-
- // First line of defense is the EdcEcc error file
- try
- {
- // Read in the error count whenever we find it
- using var sr = File.OpenText(edcecc);
- while (!sr.EndOfStream)
- {
- var line = sr.ReadLine()?.Trim();
- if (line == null)
- break;
-
- if (line.StartsWith("[NO ERROR]"))
- {
- totalErrors = 0;
- break;
- }
- else if (line.StartsWith("Total errors"))
- {
- totalErrors ??= 0;
-
- if (Int64.TryParse(line.Substring("Total errors: ".Length).Trim(), out long te))
- totalErrors += te;
- }
- else if (line.StartsWith("Total warnings"))
- {
- totalErrors ??= 0;
-
- if (Int64.TryParse(line.Substring("Total warnings: ".Length).Trim(), out long tw))
- totalErrors += tw;
- }
- }
-
- // If we haven't found anything, return -1
- return totalErrors ?? -1;
- }
- catch
- {
- // We don't care what the exception is right now
- return Int64.MaxValue;
- }
- }
-
- ///
- /// Get the PSX/PS2/KP2 EXE Date from the log, if possible
- ///
- /// Log file location
- /// Internal serial
- /// True if PSX disc, false otherwise
- /// EXE date if possible, null otherwise
- public static string? GetPlayStationEXEDate(string log, string? exeName, bool psx = false)
- {
- // If the file doesn't exist, we can't get the info
- if (!File.Exists(log))
- return null;
-
- // If the EXE name is not valid, we can't get the info
- if (string.IsNullOrEmpty(exeName))
- return null;
-
- try
- {
- string? exeDate = null;
- using var sr = File.OpenText(log);
- var line = sr.ReadLine();
- while (line != null)
- {
- // Trim the line for later use
- line = line.Trim();
-
- // The exe date is listed in a single line, File Identifier: ABCD_123.45;1
- if (line.Length >= "File Identifier: ".Length + 11 &&
- line.StartsWith("File Identifier:") &&
- line.Substring("File Identifier: ".Length) == exeName)
- {
- // Account for Y2K date problem
- if (exeDate != null && exeDate!.Substring(0, 2) == "19")
- {
- string decade = exeDate!.Substring(2, 1);
- // Does only PSX need to account for 1920s-60s?
- if (decade == "0" || decade == "1" ||
- psx && (decade == "2" || decade == "3" || decade == "4" || decade == "5" || decade == "6"))
- exeDate = $"20{exeDate!.Substring(2)}";
- }
-
- // Currently stored date is the EXE date, return it
- return exeDate;
- }
-
- // The exe datetime is listed in a single line
- if (line.Length >= "Recording Date and Time: ".Length + 10 &&
- line.StartsWith("Recording Date and Time:"))
- {
- // exe date: ISO datetime (yyyy-MM-ddT.....)
- exeDate = line.Substring("Recording Date and Time: ".Length, 10);
- }
-
- line = sr.ReadLine();
- }
-
- return null;
- }
- 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
- /// True on successful extraction of info, false otherwise
- private static bool GetGDROMBuildInfo(string? segaHeader, out string? serial, out string? version, out string? date)
- {
- serial = null; version = null; date = null;
-
- // If the input header is null, we can't do a thing
- if (string.IsNullOrEmpty(segaHeader))
- return false;
-
- // Now read it in cutting it into lines for easier parsing
- try
- {
- string[] header = segaHeader!.Split('\n');
- string versionLine = header[4].Substring(58);
- string dateLine = header[5].Substring(58);
- serial = versionLine.Substring(0, 10).TrimEnd();
- version = versionLine.Substring(10, 6).TrimStart('V', 'v');
- date = dateLine.Substring(0, 8);
- return true;
- }
- catch
- {
- // We don't care what the error is
- return false;
- }
- }
-
- ///
- /// Get hardware information from the input file, if possible
- ///
- /// _drive.txt file location
- /// True if hardware info was set, false otherwise
- private static bool GetHardwareInfo(string drive, out string? manufacturer, out string? model, out string? firmware)
- {
- // Set the default values
- manufacturer = null; model = null; firmware = null;
-
- // If the file doesn't exist, we can't get the info
- if (!File.Exists(drive))
- return false;
-
- try
- {
- using var sr = File.OpenText(drive);
- var line = sr.ReadLine();
- while (line != null)
- {
- // Trim the line for later use
- line = line.Trim();
-
- // Only take the first instance of each value
- if (string.IsNullOrEmpty(manufacturer) && line.StartsWith("VendorId"))
- {
- // VendorId:
- manufacturer = line.Substring("VendorId: ".Length);
- }
- else if (string.IsNullOrEmpty(model) && line.StartsWith("ProductId"))
- {
- // ProductId:
- model = line.Substring("ProductId: ".Length);
- }
- else if (string.IsNullOrEmpty(firmware) && line.StartsWith("ProductRevisionLevel"))
- {
- // ProductRevisionLevel:
- firmware = line.Substring("ProductRevisionLevel: ".Length);
- }
-
- line = sr.ReadLine();
- }
-
- return true;
- }
- catch
- {
- // We don't care what the exception is right now
- return false;
- }
- }
-
- ///
- /// Get the layerbreak from the input file, if possible
- ///
- /// _disc.txt file location
- /// True if XGD layerbreak info should be used, false otherwise
- /// Layerbreak if possible, null on error
- private static string? GetLayerbreak(string disc, bool xgd)
- {
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(disc))
- return null;
-
- try
- {
- using var sr = File.OpenText(disc);
- var line = sr.ReadLine();
- while (line != null)
- {
- // Trim the line for later use
- line = line.Trim();
-
- // Single-layer discs have no layerbreak
- if (line.Contains("NumberOfLayers: Single Layer"))
- {
- return null;
- }
-
- // Xbox discs have a special layerbreaks
- else if (xgd && line.StartsWith("LayerBreak"))
- {
- // LayerBreak: (L0 Video: , L0 Middle: , L0 Game: )
- string[] split = line.Split(' ').Where(s => !string.IsNullOrEmpty(s)).ToArray();
- return split[1];
- }
-
- // Dual-layer discs have a regular layerbreak
- else if (!xgd && line.StartsWith("LayerZeroSector"))
- {
- // LayerZeroSector: ()
- string[] split = line.Split(' ').Where(s => !string.IsNullOrEmpty(s)).ToArray();
- return split[1];
- }
-
- line = sr.ReadLine();
- }
-
- // If we get to the end, there's an issue
- return null;
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Get multisession information from the input file, if possible
- ///
- /// _disc.txt file location
- /// Formatted multisession information, null on error
- private static string? GetMultisessionInformation(string disc)
- {
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(disc))
- return null;
-
- try
- {
- // Seek to the TOC data
- using var sr = File.OpenText(disc);
- var line = sr.ReadLine();
- if (line == null)
- return null;
-
- if (!line.StartsWith("========== TOC"))
- while ((line = sr.ReadLine())?.StartsWith("========== TOC") == false) ;
- if (line == null)
- return null;
-
- // Create the required regex
- var trackLengthRegex = new Regex(@"^\s*.*?Track\s*([0-9]{1,2}), LBA\s*[0-9]{1,8} - \s*[0-9]{1,8}, Length\s*([0-9]{1,8})$", RegexOptions.Compiled);
-
- // Read in the track length data
- var trackLengthMapping = new Dictionary();
- while ((line = sr.ReadLine())?.Contains("Track") == true)
- {
- var match = trackLengthRegex.Match(line);
- trackLengthMapping[match.Groups[1].Value] = match.Groups[2].Value;
- }
-
- if (line == null)
- return null;
-
- // Seek to the FULL TOC data
- line = sr.ReadLine();
- if (line == null)
- return null;
-
- if (!line.StartsWith("========== FULL TOC"))
- while ((line = sr.ReadLine())?.StartsWith("========== FULL TOC") == false) ;
- if (line == null)
- return null;
-
- // Create the required regex
- var trackSessionRegex = new Regex(@"^\s*Session\s*([0-9]{1,2}),.*?,\s*Track\s*([0-9]{1,2}).*?$", RegexOptions.Compiled);
-
- // Read in the track session data
- var trackSessionMapping = new Dictionary();
- while ((line = sr.ReadLine())?.StartsWith("========== OpCode") == false)
- {
- if (line == null)
- return null;
-
- var match = trackSessionRegex.Match(line);
- if (!match.Success)
- continue;
-
- trackSessionMapping[match.Groups[2].Value] = match.Groups[1].Value;
- }
-
- // If we have all Session 1, we can just skip out
- if (trackSessionMapping.All(kvp => kvp.Value == "1"))
- return null;
-
- // Seek to the multisession data
- line = sr.ReadLine()?.Trim();
- if (line == null)
- return null;
-
- if (!line.StartsWith("Lead-out length"))
- while ((line = sr.ReadLine()?.Trim())?.StartsWith("Lead-out length") == false) ;
-
- // TODO: Are there any examples of 3+ session discs?
-
- // Read the first session lead-out
- var firstSessionLeadOutLengthString = line?.Substring("Lead-out length of 1st session: ".Length);
- line = sr.ReadLine()?.Trim();
- if (line == null)
- return null;
-
- // Read the second session lead-in, if it exists
- string? secondSessionLeadInLengthString = null;
- while (line?.StartsWith("Lead-in length") == false)
- {
- secondSessionLeadInLengthString = line?.Substring("Lead-in length of 2nd session: ".Length);
- line = sr.ReadLine()?.Trim();
- }
-
- // Read the second session pregap
- var secondSessionPregapLengthString = line?.Substring("Pregap length of 1st track of 2nd session: ".Length);
-
- // Calculate the session gap total
- if (!int.TryParse(firstSessionLeadOutLengthString, out int firstSessionLeadOutLength))
- firstSessionLeadOutLength = 0;
- if (!int.TryParse(secondSessionLeadInLengthString, out int secondSessionLeadInLength))
- secondSessionLeadInLength = 0;
- if (!int.TryParse(secondSessionPregapLengthString, out int secondSessionPregapLength))
- secondSessionPregapLength = 0;
- int sessionGapTotal = firstSessionLeadOutLength + secondSessionLeadInLength + secondSessionPregapLength;
-
- // Calculate first session length and total length
- int firstSessionLength = 0, totalLength = 0;
- foreach (var lengthMapping in trackLengthMapping)
- {
- if (!int.TryParse(lengthMapping.Value, out int trackLength))
- trackLength = 0;
-
- if (trackSessionMapping.TryGetValue(lengthMapping.Key, out var session))
- firstSessionLength += session == "1" ? trackLength : 0;
-
- totalLength += trackLength;
- }
-
- // Adjust the session gap in a consistent way
- if (firstSessionLength - sessionGapTotal < 0)
- sessionGapTotal = firstSessionLeadOutLength + secondSessionLeadInLength;
-
- // Create and return the formatted output
- string multisessionData =
- $"Session 1: 0-{firstSessionLength - sessionGapTotal - 1}\n"
- + $"Session 2: {firstSessionLength}-{totalLength - 1}";
-
- return multisessionData;
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Get the existence of an anti-modchip string from the input file, if possible
- ///
- /// _disc.txt file location
- /// Anti-modchip existence if possible, false on error
- private static bool? GetPlayStationAntiModchipDetected(string disc)
- {
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(disc))
- return null;
-
- try
- {
- // Check for either antimod string
- using var sr = File.OpenText(disc);
- var line = sr.ReadLine()?.Trim();
- if (line == null)
- return null;
-
- while (!sr.EndOfStream)
- {
- if (line == null)
- return false;
-
- if (line.StartsWith("Detected anti-mod string"))
- return true;
- else if (line.StartsWith("No anti-mod string"))
- return false;
-
- line = sr.ReadLine()?.Trim();
- }
-
- return false;
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Get the detected missing EDC count from the input files, if possible
- ///
- /// .img_EdcEcc.txt file location
- /// Status of PS1 EDC, if possible
- private static bool? GetPlayStationEDCStatus(string edcecc)
- {
- // If one of the files doesn't exist, we can't get info from them
- if (!File.Exists(edcecc))
- return null;
-
- // First line of defense is the EdcEcc error file
- int modeTwoNoEdc = 0;
- int modeTwoFormTwo = 0;
- try
- {
- using var sr = File.OpenText(edcecc);
- while (!sr.EndOfStream)
- {
- var line = sr.ReadLine();
- if (line == null)
- break;
-
- if (line.Contains("mode 2 form 2"))
- modeTwoFormTwo++;
- else if (line.Contains("mode 2 no edc"))
- modeTwoNoEdc++;
- }
-
- // This shouldn't happen
- if (modeTwoNoEdc == 0 && modeTwoFormTwo == 0)
- return null;
-
- // EDC exists
- else if (modeTwoNoEdc == 0 && modeTwoFormTwo != 0)
- return true;
-
- // EDC doesn't exist
- else if (modeTwoNoEdc != 0 && modeTwoFormTwo == 0)
- return false;
-
- // This shouldn't happen
- else if (modeTwoNoEdc != 0 && modeTwoFormTwo != 0)
- return null;
-
- // No idea how it would fall through
- return null;
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Get the PVD from the input file, if possible
- ///
- /// _mainInfo.txt file location
- /// Newline-delimited PVD if possible, null on error
- private static string? GetPVD(string mainInfo)
- {
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(mainInfo))
- return null;
-
- try
- {
- // If we're in a new mainInfo, the location of the header changed
- using var sr = File.OpenText(mainInfo);
- var line = sr.ReadLine();
- if (line == null)
- return null;
-
- if (line.StartsWith("========== OpCode")
- || line.StartsWith("========== TOC (Binary)")
- || line.StartsWith("========== FULL TOC (Binary)"))
- {
- // Seek to unscrambled data
- while ((line = sr.ReadLine())?.StartsWith("========== Check Volume Descriptor ==========") == false) ;
-
- // Read the next line so the search goes properly
- line = sr.ReadLine();
- }
-
- if (line == null)
- return null;
-
- // Make sure we're in the area
- if (line.StartsWith("========== LBA") == false)
- while ((line = sr.ReadLine())?.StartsWith("========== LBA") == false) ;
- if (line == null)
- return null;
-
- // If we have a Sega disc, skip sector 0
- if (line.StartsWith("========== LBA[000000, 0000000]: Main Channel =========="))
- while ((line = sr.ReadLine())?.StartsWith("========== LBA") == false) ;
- if (line == null)
- return null;
-
- // If we have a PlayStation disc, skip sector 4
- if (line.StartsWith("========== LBA[000004, 0x00004]: Main Channel =========="))
- while ((line = sr.ReadLine())?.StartsWith("========== LBA") == false) ;
- if (line == null)
- return null;
-
- // We assume the first non-LBA0/4 sector listed is the proper one
- // Fast forward to the PVD
- while ((line = sr.ReadLine())?.StartsWith("0310") == false) ;
-
- // Now that we're at the PVD, read each line in and concatenate
- string pvd = "";
- for (int i = 0; i < 6; i++)
- pvd += sr.ReadLine() + "\n"; // 320-370
-
- return pvd;
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Get the build info from a Saturn disc, if possible
- ///
- /// <String representing a formatter variant of the Saturn header
- /// True on successful extraction of info, false otherwise
- private static bool GetSaturnBuildInfo(string? segaHeader, out string? serial, out string? version, out string? date)
- {
- serial = null; version = null; date = null;
-
- // If the input header is null, we can't do a thing
- if (string.IsNullOrEmpty(segaHeader))
- return false;
-
- // Now read it in cutting it into lines for easier parsing
- try
- {
- string[] header = segaHeader!.Split('\n');
- string serialVersionLine = header[2].Substring(58);
- string dateLine = header[3].Substring(58);
- serial = serialVersionLine.Substring(0, 10).Trim();
- version = serialVersionLine.Substring(10, 6).TrimStart('V', 'v');
- date = dateLine.Substring(0, 8);
- date = $"{date[0]}{date[1]}{date[2]}{date[3]}-{date[4]}{date[5]}-{date[6]}{date[7]}";
- return true;
- }
- catch
- {
- // We don't care what the error is
- return false;
- }
- }
-
- ///
- /// Get the build info from a Sega CD disc, if possible
- ///
- /// <String representing a formatter variant of the Sega CD header
- /// True on successful extraction of info, false otherwise
- /// Note that this works for MOST headers, except ones where the copyright stretches > 1 line
- private static bool GetSegaCDBuildInfo(string? segaHeader, out string? serial, out string? date)
- {
- serial = null; date = null;
-
- // If the input header is null, we can't do a thing
- if (string.IsNullOrEmpty(segaHeader))
- return false;
-
- // Now read it in cutting it into lines for easier parsing
- try
- {
- string[] header = segaHeader!.Split('\n');
- string serialVersionLine = header[8].Substring(58);
- string dateLine = header[1].Substring(58);
- serial = serialVersionLine.Substring(3, 8).TrimEnd('-', ' ');
- date = dateLine.Substring(8).Trim();
-
- // Properly format the date string, if possible
- string[] dateSplit = date.Split('.');
-
- if (dateSplit.Length == 1)
- dateSplit = [date.Substring(0, 4), date.Substring(4)];
-
- string month = dateSplit[1];
- dateSplit[1] = month switch
- {
- "JAN" => "01",
- "FEB" => "02",
- "MAR" => "03",
- "APR" => "04",
- "MAY" => "05",
- "JUN" => "06",
- "JUL" => "07",
- "AUG" => "08",
- "SEP" => "09",
- "OCT" => "10",
- "NOV" => "11",
- "DEC" => "12",
- _ => "00",
- };
-
- date = string.Join("-", dateSplit);
-
- return true;
- }
- catch
- {
- // We don't care what the error is
- return false;
- }
- }
-
- ///
- /// Get the header from a Sega CD / Mega CD, Saturn, or Dreamcast Low-Density region, if possible
- ///
- /// _mainInfo.txt file location
- /// Header as a byte array if possible, null on error
- private static string? GetSegaHeader(string mainInfo)
- {
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(mainInfo))
- return null;
-
- try
- {
- // If we're in a new mainInfo, the location of the header changed
- using var sr = File.OpenText(mainInfo);
- var line = sr.ReadLine();
- if (line == null)
- return null;
-
- if (line.StartsWith("========== OpCode")
- || line.StartsWith("========== TOC (Binary)")
- || line.StartsWith("========== FULL TOC (Binary)"))
- {
- // Seek to unscrambled data
- while ((line = sr.ReadLine())?.Contains("Check MCN and/or ISRC") == false) ;
- if (line == null)
- return null;
-
- // Read the next line so the search goes properly
- line = sr.ReadLine();
- }
-
- if (line == null)
- return null;
-
- // Make sure we're in the area
- if (!line.StartsWith("========== LBA"))
- while ((line = sr.ReadLine())?.StartsWith("========== LBA") == false) ;
- if (line == null)
- return null;
-
- // Make sure we're in the right sector
- if (!line.StartsWith("========== LBA[000000, 0000000]: Main Channel =========="))
- while ((line = sr.ReadLine())?.StartsWith("========== LBA[000000, 0000000]: Main Channel ==========") == false) ;
- if (line == null)
- return null;
-
- // Fast forward to the header
- while ((line = sr.ReadLine())?.Trim()?.StartsWith("+0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F") == false) ;
- if (line == null)
- return null;
-
- // Now that we're at the Header, read each line in and concatenate
- string header = "";
- for (int i = 0; i < 32; i++)
- header += sr.ReadLine() + "\n"; // 0000-01F0
-
- return header;
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Get the write offset from the input file, if possible
- ///
- /// _disc.txt file location
- /// Sample write offset if possible, null on error
- private static string? GetWriteOffset(string disc)
- {
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(disc))
- return null;
-
- try
- {
- // Fast forward to the offsets
- using var sr = File.OpenText(disc);
- while (sr.ReadLine()?.Trim()?.StartsWith("========== Offset") == false) ;
- sr.ReadLine(); // Combined Offset
- sr.ReadLine(); // Drive Offset
- sr.ReadLine(); // Separator line
-
- // Now that we're at the offsets, attempt to get the sample offset
- return sr.ReadLine()?.Split(' ')?.LastOrDefault();
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Get the XGD auxiliary hash info from the outputted files, if possible
- ///
- /// Datafile representing the supplementary hashes
- /// Extracted DMI.bin CRC32 hash (upper-cased)
- /// Extracted PFI.bin CRC32 hash (upper-cased)
- /// Extracted SS.bin CRC32 hash (upper-cased)
- /// True on successful extraction of info, false otherwise
- /// Currently only the CRC32 values are returned for each, this may change in the future
- private static bool GetXGDAuxHashInfo(Datafile? suppl, out string? dmihash, out string? pfihash, out string? sshash)
- {
- // Assign values to all outputs first
- dmihash = null; pfihash = null; sshash = null;
-
- // If we don't have a valid datafile, we can't do anything
- if (suppl?.Games == null)
- return false;
-
- // Try to extract the hash information
- var roms = suppl.Games[0].Roms;
- if (roms == null || roms.Length == 0)
- return false;
-
- dmihash = roms.FirstOrDefault(r => r.Name?.EndsWith("DMI.bin") == true)?.Crc?.ToUpperInvariant();
- pfihash = roms.FirstOrDefault(r => r.Name?.EndsWith("PFI.bin") == true)?.Crc?.ToUpperInvariant();
- sshash = roms.FirstOrDefault(r => r.Name?.EndsWith("SS.bin") == true)?.Crc?.ToUpperInvariant();
-
- return true;
- }
-
- ///
- /// Get the XGD auxiliary info from the outputted files, if possible
- ///
- /// _disc.txt file location
- /// Extracted DMI.bin CRC32 hash (upper-cased)
- /// Extracted PFI.bin CRC32 hash (upper-cased)
- /// Extracted SS.bin CRC32 hash (upper-cased)
- /// Extracted security sector data
- /// Extracted security sector version
- /// True on successful extraction of info, false otherwise
- private static bool GetXGDAuxInfo(string disc, out string? dmihash, out string? pfihash, out string? sshash, out string? ss, out string? ssver)
- {
- dmihash = null; pfihash = null; sshash = null; ss = null; ssver = null;
-
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(disc))
- return false;
-
- // This flag is needed because recent versions of DIC include security data twice
- bool foundSecuritySectors = false;
-
- // SS version for all Kreon DIC dumps is v1
- ssver = "01";
-
- try
- {
- using var sr = File.OpenText(disc);
- while (!sr.EndOfStream)
- {
- var line = sr.ReadLine()?.Trim();
- if (line == null)
- break;
-
- // XGD version (1 = Xbox, 2 = Xbox360)
- /*
- if (line.StartsWith("Version of challenge table"))
- {
- xgdver = line.Split(' ')[4]; // "Version of challenge table: "
- }
- */
-
- // Security Sector ranges
- else if (line.StartsWith("Number of security sector ranges:") && !foundSecuritySectors)
- {
- // Set the flag so we don't read duplicate data
- foundSecuritySectors = true;
-
- var layerRegex = new Regex(@"Layer [01].*, startLBA-endLBA:\s*(\d+)-\s*(\d+)", RegexOptions.Compiled);
-
- line = sr.ReadLine()?.Trim();
- if (line == null)
- break;
-
- while (!line.StartsWith("========== TotalLength ==========")
- && !line.StartsWith("========== Unlock 2 state(wxripper) =========="))
- {
- // If we have a recognized line format, parse it
- if (line.StartsWith("Layer "))
- {
- var match = layerRegex.Match(line);
- ss += $"{match.Groups[1]}-{match.Groups[2]}\n";
- }
-
- line = sr.ReadLine()?.Trim();
- if (line == null)
- break;
- }
-
- if (line == null)
- break;
- }
-
- // Special File Hashes
- else if (line.StartsWith("
- /// Get the XGD auxiliary security sector info from the outputted files, if possible
- ///
- /// _disc.txt file location
- /// Extracted security sector data
- /// Extracted security sector version
- /// True on successful extraction of info, false otherwise
- private static bool GetXGDAuxSSInfo(string disc, out string? ss, out string? ssver)
- {
- ss = null; ssver = null;
-
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(disc))
- return false;
-
- // This flag is needed because recent versions of DIC include security data twice
- bool foundSecuritySectors = false;
-
- // SS version for all Kreon DIC dumps is v1
- ssver = "01";
-
- try
- {
- using var sr = File.OpenText(disc);
- while (!sr.EndOfStream)
- {
- var line = sr.ReadLine()?.Trim();
- if (line == null)
- break;
-
- // XGD version (1 = Xbox, 2 = Xbox360)
- /*
- if (line.StartsWith("Version of challenge table"))
- {
- xgdver = line.Split(' ')[4]; // "Version of challenge table: "
- }
- */
-
- // Security Sector ranges
- else if (line.StartsWith("Number of security sector ranges:") && !foundSecuritySectors)
- {
- // Set the flag so we don't read duplicate data
- foundSecuritySectors = true;
-
- var layerRegex = new Regex(@"Layer [01].*, startLBA-endLBA:\s*(\d+)-\s*(\d+)", RegexOptions.Compiled);
-
- line = sr.ReadLine()?.Trim();
- if (line == null)
- break;
-
- while (!line.StartsWith("========== TotalLength ==========")
- && !line.StartsWith("========== Unlock 2 state(wxripper) =========="))
- {
- // If we have a recognized line format, parse it
- if (line.StartsWith("Layer "))
- {
- var match = layerRegex.Match(line);
- ss += $"{match.Groups[1]}-{match.Groups[2]}\n";
- }
-
- line = sr.ReadLine()?.Trim();
- if (line == null)
- break;
- }
-
- if (line == null)
- break;
- }
- }
-
- return true;
- }
- catch
- {
- // We don't care what the exception is right now
- return false;
- }
- }
-
- #endregion
}
}
diff --git a/MPF.Core/Modules/PS3CFW/Parameters.cs b/MPF.Core/Modules/PS3CFW/Parameters.cs
index c75f7ce3..e770bb67 100644
--- a/MPF.Core/Modules/PS3CFW/Parameters.cs
+++ b/MPF.Core/Modules/PS3CFW/Parameters.cs
@@ -1,10 +1,4 @@
-using System.Collections.Generic;
-using System.IO;
-using System.Text.RegularExpressions;
-using MPF.Core.Converters;
-using MPF.Core.Data;
-using SabreTools.Hashing;
-using SabreTools.RedumpLib;
+using MPF.Core.Data;
using SabreTools.RedumpLib.Data;
namespace MPF.Core.Modules.PS3CFW
@@ -29,209 +23,5 @@ namespace MPF.Core.Modules.PS3CFW
: base(system, type, drivePath, filename, driveSpeed, options)
{
}
-
- #region BaseParameters Implementations
-
- ///
- public override (bool, List) CheckAllOutputFilesExist(string basePath, bool preCheck)
- {
- var missingFiles = new List();
-
- if (this.Type != MediaType.BluRay || this.System != RedumpSystem.SonyPlayStation3)
- {
- missingFiles.Add("Media and system combination not supported for PS3 CFW");
- }
- else
- {
- string? getKeyBasePath = GetCFWBasePath(basePath);
- if (!File.Exists($"{getKeyBasePath}.getkey.log"))
- missingFiles.Add($"{getKeyBasePath}.getkey.log");
- if (!File.Exists($"{getKeyBasePath}.disc.pic"))
- missingFiles.Add($"{getKeyBasePath}.disc.pic");
- }
-
- return (missingFiles.Count == 0, missingFiles);
- }
-
- ///
- public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive? drive, bool includeArtifacts)
- {
- // Ensure that required sections exist
- info = Builder.EnsureAllSections(info);
-
- info.DumpingInfo!.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
-
- // Get the Datafile information
- Datafile? datafile = GeneratePS3CFWDatafile(basePath + ".iso");
-
- // Fill in the hash data
- info.TracksAndWriteOffsets!.ClrMameProData = InfoTool.GenerateDatfile(datafile);
-
- // Get the individual hash data, as per internal
- if (InfoTool.GetISOHashValues(datafile, out long size, out var crc32, out var md5, out var sha1))
- {
- info.SizeAndChecksums!.Size = size;
- info.SizeAndChecksums.CRC32 = crc32;
- info.SizeAndChecksums.MD5 = md5;
- info.SizeAndChecksums.SHA1 = sha1;
- }
-
- // Get the PVD from the ISO
- if (GetPVD(basePath + ".iso", out string? pvd))
- info.Extras!.PVD = pvd;
-
- // Try get the serial, version, and firmware version if a drive is provided
- if (drive != null)
- {
- info.VersionAndEditions!.Version = InfoTool.GetPlayStation3Version(drive?.Name) ?? string.Empty;
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = InfoTool.GetPlayStation3Serial(drive?.Name) ?? string.Empty;
- string? firmwareVersion = InfoTool.GetPlayStation3FirmwareVersion(drive?.Name);
- if (firmwareVersion != null)
- info.CommonDiscInfo!.ContentsSpecialFields![SiteCode.Patches] = $"PS3 Firmware {firmwareVersion}";
- }
-
- // Try to determine the name of the GetKey file(s)
- string? getKeyBasePath = GetCFWBasePath(basePath);
-
- // If GenerateSubmissionInfo is run, .getkey.log existence should already be checked
- if (!File.Exists(getKeyBasePath + ".getkey.log"))
- return;
-
- // Get dumping date from GetKey log date
- info.DumpingInfo.DumpingDate = InfoTool.GetFileModifiedDate(getKeyBasePath + ".getkey.log")?.ToString("yyyy-MM-dd HH:mm:ss");
-
- // TODO: Put info about abnormal PIC info beyond 132 bytes in comments?
- if (File.Exists(getKeyBasePath + ".disc.pic"))
- info.Extras!.PIC = GetPIC(getKeyBasePath + ".disc.pic", 264);
-
- // Parse Disc Key, Disc ID, and PIC from the .getkey.log file
- if (Utilities.Tools.ParseGetKeyLog(getKeyBasePath + ".getkey.log", out string? key, out string? id, out string? pic))
- {
- if (key != null)
- info.Extras!.DiscKey = key.ToUpperInvariant();
- if (id != null)
- info.Extras!.DiscID = id.ToUpperInvariant().Substring(0, 24) + "XXXXXXXX";
- if (string.IsNullOrEmpty(info.Extras!.PIC) && !string.IsNullOrEmpty(pic))
- {
- pic = Regex.Replace(pic, ".{32}", "$0\n");
- info.Extras.PIC = pic;
- }
- }
-
- // Fill in any artifacts that exist, Base64-encoded, if we need to
- if (includeArtifacts)
- {
- info.Artifacts ??= [];
-
- if (File.Exists(getKeyBasePath + ".disc.pic"))
- info.Artifacts["discpic"] = GetBase64(GetFullFile(getKeyBasePath + ".disc.pic", binary: true)) ?? string.Empty;
- if (File.Exists(getKeyBasePath + ".getkey.log"))
- info.Artifacts["getkeylog"] = GetBase64(GetFullFile(getKeyBasePath + ".getkey.log")) ?? string.Empty;
- }
- }
-
- ///
- public override List GetLogFilePaths(string basePath)
- {
- var logFiles = new List();
- string? getKeyBasePath = GetCFWBasePath(basePath);
-
- if (this.System != RedumpSystem.SonyPlayStation3)
- return logFiles;
-
- switch (this.Type)
- {
- case MediaType.BluRay:
- if (File.Exists($"{getKeyBasePath}.getkey.log"))
- logFiles.Add($"{getKeyBasePath}.getkey.log");
- if (File.Exists($"{getKeyBasePath}.disc.pic"))
- logFiles.Add($"{getKeyBasePath}.disc.pic");
-
- break;
- }
-
- return logFiles;
- }
-
- #endregion
-
- #region Information Extraction Methods
-
- ///
- /// Get a formatted datfile from the PS3 CFW output, if possible
- ///
- /// Path to ISO file
- ///
- private static Datafile? GeneratePS3CFWDatafile(string iso)
- {
- // If the ISO file doesn't exist, we can't get info from it
- if (!File.Exists(iso))
- return null;
-
- try
- {
- if (HashTool.GetStandardHashes(iso, out long size, out string? crc, out string? md5, out string? sha1))
- {
- return new Datafile
- {
- Games = [new Game { Roms = [new Rom { Name = Path.GetFileName(iso), Size = size.ToString(), Crc = crc, Md5 = md5, Sha1 = sha1, }] }]
- };
- }
- return null;
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Get a formatted datfile from the PS3 CFW output, if possible
- ///
- /// Path to ISO file
- /// Formatted datfile, null if not valid
- private static string? GetPS3CFWDatfile(string iso)
- {
- // If the files don't exist, we can't get info from it
- if (!File.Exists(iso))
- return null;
-
- try
- {
- if (HashTool.GetStandardHashes(iso, out long size, out string? crc, out string? md5, out string? sha1))
- return $"";
- return null;
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- #endregion
-
- #region Helper Functions
-
- ///
- /// Estimate the base filename of the .getkey.log file associated with the dump
- ///
- /// Path to ISO file
- /// Base filename, null if not found
- private string? GetCFWBasePath(string iso)
- {
- string? dir = Path.GetDirectoryName(iso);
- dir ??= ".";
-
- string[] files = Directory.GetFiles(dir, "*.getkey.log");
-
- if (files.Length != 1)
- return null;
-
- return files[0].Substring(0, files[0].Length - 11);
- }
-
- #endregion
}
}
diff --git a/MPF.Core/Modules/Redumper/Parameters.cs b/MPF.Core/Modules/Redumper/Parameters.cs
index 73f4cbd7..b2c48406 100644
--- a/MPF.Core/Modules/Redumper/Parameters.cs
+++ b/MPF.Core/Modules/Redumper/Parameters.cs
@@ -3,10 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
-using MPF.Core.Converters;
using MPF.Core.Data;
-using SabreTools.Models.CueSheets;
-using SabreTools.RedumpLib;
using SabreTools.RedumpLib.Data;
namespace MPF.Core.Modules.Redumper
@@ -176,469 +173,6 @@ namespace MPF.Core.Modules.Redumper
#region BaseParameters Implementations
- ///
- public override (bool, List) CheckAllOutputFilesExist(string basePath, bool preCheck)
- {
- var missingFiles = new List();
-
- switch (this.Type)
- {
- case MediaType.CDROM:
- if (!File.Exists($"{basePath}.cue"))
- missingFiles.Add($"{basePath}.cue");
- if (!File.Exists($"{basePath}.scram") && !File.Exists($"{basePath}.scrap"))
- missingFiles.Add($"{basePath}.scram");
-
- if (!File.Exists($"{basePath}_logs.zip") || !preCheck)
- {
- if (!File.Exists($"{basePath}.fulltoc"))
- missingFiles.Add($"{basePath}.fulltoc");
- if (!File.Exists($"{basePath}.log"))
- missingFiles.Add($"{basePath}.log");
- else if (GetDatfile($"{basePath}.log") == null)
- missingFiles.Add($"{basePath}.log (dat section)");
- if (!File.Exists($"{basePath}.state"))
- missingFiles.Add($"{basePath}.state");
- if (!File.Exists($"{basePath}.subcode"))
- missingFiles.Add($"{basePath}.subcode");
- if (!File.Exists($"{basePath}.toc"))
- missingFiles.Add($"{basePath}.toc");
- }
-
- // Removed or inconsistent files
- //{
- // // Depends on the disc
- // if (!File.Exists($"{basePath}.cdtext"))
- // missingFiles.Add($"{basePath}.cdtext");
- //
- // // Not available in all versions
- // if (!File.Exists($"{basePath}.hash"))
- // missingFiles.Add($"{basePath}.hash");
- // // Also: "{basePath} (Track X).hash" (get from cuesheet)
- // if (!File.Exists($"{basePath}.skeleton"))
- // missingFiles.Add($"{basePath}.skeleton");
- // // Also: "{basePath} (Track X).skeleton" (get from cuesheet)
- //}
-
- break;
-
- case MediaType.DVD:
- if (!File.Exists($"{basePath}_logs.zip") || !preCheck)
- {
- if (!File.Exists($"{basePath}.log"))
- missingFiles.Add($"{basePath}.log");
- else if (GetDatfile($"{basePath}.log") == null)
- missingFiles.Add($"{basePath}.dat");
- if (!File.Exists($"{basePath}.manufacturer") && !File.Exists($"{basePath}.1.manufacturer") && !File.Exists($"{basePath}.2.manufacturer"))
- missingFiles.Add($"{basePath}.manufacturer");
- if (!File.Exists($"{basePath}.physical") && !File.Exists($"{basePath}.0.physical") && !File.Exists($"{basePath}.1.physical") && !File.Exists($"{basePath}.2.physical"))
- missingFiles.Add($"{basePath}.physical");
- if (!File.Exists($"{basePath}.state"))
- missingFiles.Add($"{basePath}.state");
- }
-
- // Removed or inconsistent files
- //{
- // // Not available in all versions
- // if (!File.Exists($"{basePath}.hash"))
- // missingFiles.Add($"{basePath}.hash");
- // if (!File.Exists($"{basePath}.skeleton"))
- // missingFiles.Add($"{basePath}.skeleton");
- //}
-
- break;
-
- case MediaType.HDDVD: // TODO: Verify that this is output
- case MediaType.BluRay:
- if (!File.Exists($"{basePath}_logs.zip") || !preCheck)
- {
- if (!File.Exists($"{basePath}.log"))
- missingFiles.Add($"{basePath}.log");
- else if (GetDatfile($"{basePath}.log") == null)
- missingFiles.Add($"{basePath}.dat");
- if (!File.Exists($"{basePath}.physical") && !File.Exists($"{basePath}.0.physical") && !File.Exists($"{basePath}.1.physical") && !File.Exists($"{basePath}.2.physical"))
- missingFiles.Add($"{basePath}.physical");
- if (!File.Exists($"{basePath}.state"))
- missingFiles.Add($"{basePath}.state");
- }
-
- // Removed or inconsistent files
- //{
- // // Not available in all versions
- // if (!File.Exists($"{basePath}.hash"))
- // missingFiles.Add($"{basePath}.hash");
- // if (!File.Exists($"{basePath}.skeleton"))
- // missingFiles.Add($"{basePath}.skeleton");
- //}
-
- break;
-
- default:
- missingFiles.Add("Media and system combination not supported for Redumper");
- break;
- }
-
- return (!missingFiles.Any(), missingFiles);
- }
-
- ///
- public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive? drive, bool includeArtifacts)
- {
- // Ensure that required sections exist
- info = Builder.EnsureAllSections(info);
-
- // Get the dumping program and version
- info.DumpingInfo!.DumpingProgram = $"{EnumConverter.LongName(this.InternalProgram)} {GetVersion($"{basePath}.log") ?? "Unknown Version"}";
- info.DumpingInfo.DumpingDate = InfoTool.GetFileModifiedDate($"{basePath}.log")?.ToString("yyyy-MM-dd HH:mm:ss");
-
- // Fill in the hardware data
- if (GetHardwareInfo($"{basePath}.log", out var manufacturer, out var model, out var firmware))
- {
- info.DumpingInfo.Manufacturer = manufacturer;
- info.DumpingInfo.Model = model;
- info.DumpingInfo.Firmware = firmware;
- }
-
- // Fill in the disc type data
- if (GetDiscType($"{basePath}.log", out var discTypeOrBookType))
- info.DumpingInfo.ReportedDiscType = discTypeOrBookType;
-
- // Fill in the volume labels
- if (GetVolumeLabels($"{basePath}.log", out var volLabels))
- VolumeLabels = volLabels;
-
- switch (this.Type)
- {
- case MediaType.CDROM:
- info.Extras!.PVD = GetPVD($"{basePath}.log") ?? "Disc has no PVD";
- info.TracksAndWriteOffsets!.ClrMameProData = GetDatfile($"{basePath}.log");
- info.TracksAndWriteOffsets.Cuesheet = GetFullFile($"{basePath}.cue") ?? string.Empty;
-
- // Attempt to get the write offset
- string cdWriteOffset = GetWriteOffset($"{basePath}.log") ?? string.Empty;
- info.CommonDiscInfo!.RingWriteOffset = cdWriteOffset;
- info.TracksAndWriteOffsets.OtherWriteOffsets = cdWriteOffset;
-
- // Attempt to get the error count
- if (GetErrorCount($"{basePath}.log", out long redumpErrors, out long c2Errors))
- {
- info.CommonDiscInfo.ErrorsCount = (redumpErrors == -1 ? "Error retrieving error count" : redumpErrors.ToString());
- info.DumpingInfo.C2ErrorsCount = (c2Errors == -1 ? "Error retrieving error count" : c2Errors.ToString());
- }
-
- // Attempt to get multisession data
- string cdMultiSessionInfo = GetMultisessionInformation($"{basePath}.log") ?? string.Empty;
- if (!string.IsNullOrEmpty(cdMultiSessionInfo))
- info.CommonDiscInfo.CommentsSpecialFields![SiteCode.Multisession] = cdMultiSessionInfo;
-
- // Attempt to get the universal hash, if it's an audio disc
- if (this.System.IsAudio())
- {
- string universalHash = GetUniversalHash($"{basePath}.log") ?? string.Empty;
- info.CommonDiscInfo.CommentsSpecialFields![SiteCode.UniversalHash] = universalHash;
- }
-
- // Attempt to get the non-zero data start, if it's an audio disc
- if (this.System.IsAudio())
- {
- string ringNonZeroDataStart = GetRingNonZeroDataStart($"{basePath}.log") ?? string.Empty;
- info.CommonDiscInfo.CommentsSpecialFields![SiteCode.RingNonZeroDataStart] = ringNonZeroDataStart;
- }
-
- break;
-
- case MediaType.DVD:
- case MediaType.HDDVD:
- case MediaType.BluRay:
- info.Extras!.PVD = GetPVD($"{basePath}.log") ?? "Disc has no PVD";
- info.TracksAndWriteOffsets!.ClrMameProData = GetDatfile($"{basePath}.log");
-
- // Get the individual hash data, as per internal
- if (InfoTool.GetISOHashValues(info.TracksAndWriteOffsets.ClrMameProData, out long size, out var crc32, out var md5, out var sha1))
- {
- info.SizeAndChecksums!.Size = size;
- info.SizeAndChecksums.CRC32 = crc32;
- info.SizeAndChecksums.MD5 = md5;
- info.SizeAndChecksums.SHA1 = sha1;
- }
-
- // Deal with the layerbreaks
- if (GetLayerbreaks($"{basePath}.log", out var layerbreak1, out var layerbreak2, out var layerbreak3))
- {
- info.SizeAndChecksums!.Layerbreak = !string.IsNullOrEmpty(layerbreak1) ? Int64.Parse(layerbreak1) : default;
- info.SizeAndChecksums!.Layerbreak2 = !string.IsNullOrEmpty(layerbreak2) ? Int64.Parse(layerbreak2) : default;
- info.SizeAndChecksums!.Layerbreak3 = !string.IsNullOrEmpty(layerbreak3) ? Int64.Parse(layerbreak3) : default;
- }
-
- // Bluray-specific options
- if (this.Type == MediaType.BluRay)
- {
- int trimLength = -1;
- switch (this.System)
- {
- case RedumpSystem.MicrosoftXboxOne:
- case RedumpSystem.MicrosoftXboxSeriesXS:
- case RedumpSystem.SonyPlayStation3:
- case RedumpSystem.SonyPlayStation4:
- case RedumpSystem.SonyPlayStation5:
- if (info.SizeAndChecksums!.Layerbreak3 != default)
- trimLength = 520;
- else if (info.SizeAndChecksums!.Layerbreak2 != default)
- trimLength = 392;
- else
- trimLength = 264;
- break;
- }
-
- info.Extras!.PIC = GetPIC($"{basePath}.physical", trimLength)
- ?? GetPIC($"{basePath}.0.physical", trimLength)
- ?? GetPIC($"{basePath}.1.physical", trimLength)
- ?? string.Empty;
-
- var di = InfoTool.GetDiscInformation($"{basePath}.physical")
- ?? InfoTool.GetDiscInformation($"{basePath}.0.physical")
- ?? InfoTool.GetDiscInformation($"{basePath}.1.physical");
- info.SizeAndChecksums!.PICIdentifier = InfoTool.GetPICIdentifier(di);
- }
-
- break;
- }
-
- switch (this.System)
- {
- case RedumpSystem.AppleMacintosh:
- case RedumpSystem.EnhancedCD:
- case RedumpSystem.IBMPCcompatible:
- case RedumpSystem.RainbowDisc:
- case RedumpSystem.SonyElectronicBook:
- info.CopyProtection!.SecuROMData = GetSecuROMData($"{basePath}.log") ?? string.Empty;
-
- // Needed for some odd copy protections
- info.CopyProtection!.Protection = GetDVDProtection($"{basePath}.log", false) ?? string.Empty;
- break;
-
- case RedumpSystem.DVDAudio:
- case RedumpSystem.DVDVideo:
- info.CopyProtection!.Protection = GetDVDProtection($"{basePath}.log", true) ?? string.Empty;
- break;
-
- case RedumpSystem.KonamiPython2:
- // Get metadata from log if possible
- if (GetPlayStationInfo($"{basePath}.log", out string? kp2EXEDate, out string? kp2Serial, out string? kp2Version, out var _))
- {
- info.CommonDiscInfo!.EXEDateBuildDate = kp2EXEDate;
- info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = kp2Serial ?? string.Empty;
- if (!string.IsNullOrEmpty(kp2Serial))
- info.CommonDiscInfo.Region = InfoTool.GetPlayStationRegion(info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName]);
- info.VersionAndEditions!.Version = kp2Version ?? string.Empty;
- }
- // Get metadata from drive if not available from log
- else if (InfoTool.GetPlayStationExecutableInfo(drive?.Name, out var pythonTwoSerial, out Region? pythonTwoRegion, out var pythonTwoDate))
- {
- info.CommonDiscInfo!.EXEDateBuildDate = pythonTwoDate;
- info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = pythonTwoSerial ?? string.Empty;
- info.CommonDiscInfo.Region ??= pythonTwoRegion;
- info.VersionAndEditions!.Version = InfoTool.GetPlayStation2Version(drive?.Name) ?? string.Empty;
- }
-
- break;
-
- case RedumpSystem.MicrosoftXbox:
- // TODO: Support DMI and additional file information when generated
- break;
-
- case RedumpSystem.MicrosoftXbox360:
- // TODO: Support DMI and additional file information when generated
- break;
-
- case RedumpSystem.NamcoSegaNintendoTriforce:
- // TODO: Support header information and GD-ROM info when generated
- break;
-
- case RedumpSystem.SegaMegaCDSegaCD:
- info.Extras!.Header = GetSegaCDHeader($"{basePath}.log", out var scdBuildDate, out var scdSerial, out _) ?? string.Empty;
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = scdSerial ?? string.Empty;
- info.CommonDiscInfo.EXEDateBuildDate = scdBuildDate ?? string.Empty;
- // TODO: Support region setting from parsed value
- break;
-
- case RedumpSystem.SegaChihiro:
- // TODO: Support header information and GD-ROM info when generated
- break;
-
- case RedumpSystem.SegaDreamcast:
- // TODO: Support header information and GD-ROM info when generated
- break;
-
- case RedumpSystem.SegaNaomi:
- // TODO: Support header information and GD-ROM info when generated
- break;
-
- case RedumpSystem.SegaNaomi2:
- // TODO: Support header information and GD-ROM info when generated
- break;
-
- case RedumpSystem.SegaSaturn:
- info.Extras!.Header = GetSaturnHeader($"{basePath}.log") ?? string.Empty;
-
- // Take only the first 16 lines for Saturn
- if (!string.IsNullOrEmpty(info.Extras.Header))
- info.Extras.Header = string.Join("\n", info.Extras.Header.Split('\n').Take(16).ToArray());
-
- if (GetSaturnBuildInfo(info.Extras.Header, out var saturnSerial, out var saturnVersion, out var buildDate))
- {
- // Ensure internal serial is pulled from local data
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = saturnSerial ?? string.Empty;
- info.VersionAndEditions!.Version = saturnVersion ?? string.Empty;
- info.CommonDiscInfo.EXEDateBuildDate = buildDate ?? string.Empty;
- }
-
- break;
-
- case RedumpSystem.SonyPlayStation:
- // Get metadata from log if possible
- if (GetPlayStationInfo($"{basePath}.log", out string? psxEXEDate, out string? psxSerial, out var _, out var _))
- {
- info.CommonDiscInfo!.EXEDateBuildDate = psxEXEDate;
- info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = psxSerial ?? string.Empty;
- if (!string.IsNullOrEmpty(psxSerial))
- info.CommonDiscInfo.Region = InfoTool.GetPlayStationRegion(info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName]);
- }
- // Get metadata from drive if not available from log
- else if (InfoTool.GetPlayStationExecutableInfo(drive?.Name, out var playstationSerial, out Region? playstationRegion, out var playstationDate))
- {
- info.CommonDiscInfo!.EXEDateBuildDate = playstationDate;
- info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = playstationSerial ?? string.Empty;
- info.CommonDiscInfo.Region ??= playstationRegion;
- }
-
- info.CopyProtection!.AntiModchip = GetPlayStationAntiModchipDetected($"{basePath}.log").ToYesNo();
- info.EDC!.EDC = GetPlayStationEDCStatus($"{basePath}.log").ToYesNo();
- info.CopyProtection.LibCrypt = GetPlayStationLibCryptStatus($"{basePath}.log").ToYesNo();
- info.CopyProtection.LibCryptData = GetPlayStationLibCryptData($"{basePath}.log");
- break;
-
- case RedumpSystem.SonyPlayStation2:
- // Get metadata from log if possible
- if (GetPlayStationInfo($"{basePath}.log", out string? ps2EXEDate, out string? ps2Serial, out var ps2Version, out var _))
- {
- info.CommonDiscInfo!.EXEDateBuildDate = ps2EXEDate;
- info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = ps2Serial ?? string.Empty;
- if (!string.IsNullOrEmpty(ps2Serial))
- info.CommonDiscInfo.Region = InfoTool.GetPlayStationRegion(info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName]);
- info.VersionAndEditions!.Version = ps2Version ?? string.Empty;
- }
- // Get metadata from drive if not available from log
- else if (InfoTool.GetPlayStationExecutableInfo(drive?.Name, out var playstationTwoSerial, out Region? playstationTwoRegion, out var playstationTwoDate))
- {
- info.CommonDiscInfo!.EXEDateBuildDate ??= playstationTwoDate;
- info.CommonDiscInfo.CommentsSpecialFields![SiteCode.InternalSerialName] = playstationTwoSerial ?? string.Empty;
- info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationTwoRegion;
- info.VersionAndEditions!.Version = InfoTool.GetPlayStation2Version(drive?.Name) ?? string.Empty;
- }
-
- break;
-
- case RedumpSystem.SonyPlayStation3:
- // Get metadata from log if possible
- if (GetPlayStationInfo($"{basePath}.log", out var _, out string? ps3Serial, out var ps3Version, out string? firmwareVersion))
- {
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = ps3Serial ?? string.Empty;
- info.VersionAndEditions!.Version = ps3Version ?? string.Empty;
- }
- // Get metadata from drive if not available from log
- else
- {
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = InfoTool.GetPlayStation3Serial(drive?.Name) ?? string.Empty;
- info.VersionAndEditions!.Version = InfoTool.GetPlayStation3Version(drive?.Name) ?? string.Empty;
- firmwareVersion = InfoTool.GetPlayStation3FirmwareVersion(drive?.Name);
- }
-
- // Set the firmware version as a piece of content
- if (firmwareVersion != null)
- info.CommonDiscInfo.ContentsSpecialFields![SiteCode.Patches] = $"PS3 Firmware {firmwareVersion}";
-
- break;
-
- case RedumpSystem.SonyPlayStation4:
- // Get metadata from log if possible
- if (GetPlayStationInfo($"{basePath}.log", out var _, out string? ps4Serial, out var ps4Version, out var _))
- {
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = ps4Serial ?? string.Empty;
- info.VersionAndEditions!.Version = ps4Version ?? string.Empty;
- }
- // Get metadata from drive if not available from log
- else
- {
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = InfoTool.GetPlayStation4Serial(drive?.Name) ?? string.Empty;
- info.VersionAndEditions!.Version = InfoTool.GetPlayStation4Version(drive?.Name) ?? string.Empty;
- }
-
- break;
-
- case RedumpSystem.SonyPlayStation5:
- // Get metadata from log if possible
- if (GetPlayStationInfo($"{basePath}.log", out var _, out string? ps5Serial, out var ps5Version, out var _))
- {
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = ps5Serial ?? string.Empty;
- info.VersionAndEditions!.Version = ps5Version ?? string.Empty;
- }
- // Get metadata from drive if not available from log
- else
- {
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.InternalSerialName] = InfoTool.GetPlayStation5Serial(drive?.Name) ?? string.Empty;
- info.VersionAndEditions!.Version = InfoTool.GetPlayStation5Version(drive?.Name) ?? string.Empty;
- }
-
- break;
- }
-
- // Fill in any artifacts that exist, Base64-encoded, if we need to
- if (includeArtifacts)
- {
- info.Artifacts ??= [];
-
- if (File.Exists($"{basePath}.cdtext"))
- info.Artifacts["cdtext"] = GetBase64(GetFullFile($"{basePath}.cdtext")) ?? string.Empty;
- if (File.Exists($"{basePath}.cue"))
- info.Artifacts["cue"] = GetBase64(GetFullFile($"{basePath}.cue")) ?? string.Empty;
- if (File.Exists($"{basePath}.fulltoc"))
- info.Artifacts["fulltoc"] = GetBase64(GetFullFile($"{basePath}.fulltoc")) ?? string.Empty;
- if (File.Exists($"{basePath}.hash"))
- info.Artifacts["hash"] = GetBase64(GetFullFile($"{basePath}.hash")) ?? string.Empty;
- // TODO: "{basePath} (Track X).hash" (get from cuesheet)
- if (File.Exists($"{basePath}.log"))
- info.Artifacts["log"] = GetBase64(GetFullFile($"{basePath}.log")) ?? string.Empty;
- if (File.Exists($"{basePath}.manufacturer"))
- info.Artifacts["manufacturer"] = GetBase64(GetFullFile($"{basePath}.manufacturer")) ?? string.Empty;
- if (File.Exists($"{basePath}.1.manufacturer"))
- info.Artifacts["manufacturer1"] = GetBase64(GetFullFile($"{basePath}.1.manufacturer")) ?? string.Empty;
- if (File.Exists($"{basePath}.2.manufacturer"))
- info.Artifacts["manufacturer2"] = GetBase64(GetFullFile($"{basePath}.2.manufacturer")) ?? string.Empty;
- if (File.Exists($"{basePath}.physical"))
- info.Artifacts["physical"] = GetBase64(GetFullFile($"{basePath}.physical")) ?? string.Empty;
- if (File.Exists($"{basePath}.0.physical"))
- info.Artifacts["physical0"] = GetBase64(GetFullFile($"{basePath}.0.physical")) ?? string.Empty;
- if (File.Exists($"{basePath}.1.physical"))
- info.Artifacts["physical1"] = GetBase64(GetFullFile($"{basePath}.1.physical")) ?? string.Empty;
- if (File.Exists($"{basePath}.2.physical"))
- info.Artifacts["physical2"] = GetBase64(GetFullFile($"{basePath}.2.physical")) ?? string.Empty;
- // if (File.Exists($"{basePath}.skeleton"))
- // info.Artifacts["skeleton"] = GetBase64(GetFullFile($"{basePath}.skeleton")) ?? string.Empty;
- // // Also: "{basePath} (Track X).skeleton" (get from cuesheet)
- // if (File.Exists($"{basePath}.scram"))
- // info.Artifacts["scram"] = GetBase64(GetFullFile($"{basePath}.scram")) ?? string.Empty;
- // if (File.Exists($"{basePath}.scrap"))
- // info.Artifacts["scrap"] = GetBase64(GetFullFile($"{basePath}.scrap")) ?? string.Empty;
- if (File.Exists($"{basePath}.state"))
- info.Artifacts["state"] = GetBase64(GetFullFile($"{basePath}.state")) ?? string.Empty;
- if (File.Exists($"{basePath}.subcode"))
- info.Artifacts["subcode"] = GetBase64(GetFullFile($"{basePath}.subcode")) ?? string.Empty;
- if (File.Exists($"{basePath}.toc"))
- info.Artifacts["toc"] = GetBase64(GetFullFile($"{basePath}.toc")) ?? string.Empty;
- }
- }
-
///
///
/// Redumper is unique in that the base command can be multiple
@@ -958,117 +492,6 @@ namespace MPF.Core.Modules.Redumper
///
public override string? GetDefaultExtension(MediaType? mediaType) => Converters.Extension(mediaType);
- ///
- public override List GetDeleteableFilePaths(string basePath)
- {
- var deleteableFiles = new List();
-
- if (File.Exists($"{basePath}.scram"))
- deleteableFiles.Add($"{basePath}.scram");
- if (File.Exists($"{basePath}.scrap"))
- deleteableFiles.Add($"{basePath}.scrap");
-
- return deleteableFiles;
- }
-
- ///
- public override List GetLogFilePaths(string basePath)
- {
- var logFiles = new List();
-
- switch (this.Type)
- {
- case MediaType.CDROM:
- if (File.Exists($"{basePath}.cdtext"))
- logFiles.Add($"{basePath}.cdtext");
- if (File.Exists($"{basePath}.fulltoc"))
- logFiles.Add($"{basePath}.fulltoc");
- if (File.Exists($"{basePath}.log"))
- logFiles.Add($"{basePath}.log");
- if (File.Exists($"{basePath}.state"))
- logFiles.Add($"{basePath}.state");
- if (File.Exists($"{basePath}.subcode"))
- logFiles.Add($"{basePath}.subcode");
- if (File.Exists($"{basePath}.toc"))
- logFiles.Add($"{basePath}.toc");
-
- // Include .hash and .skeleton for all files in cuesheet
- var cueSheet = SabreTools.Serialization.Deserializers.CueSheet.DeserializeFile($"{basePath}.cue");
- string? baseDir = Path.GetDirectoryName(basePath);
- if (cueSheet?.Files != null && baseDir != null)
- {
- foreach (CueFile? file in cueSheet.Files)
- {
- string? trackName = Path.GetFileNameWithoutExtension(file?.FileName);
- if (trackName == null)
- continue;
-
- string trackPath = Path.Combine(baseDir, trackName);
- if (File.Exists($"{trackPath}.hash"))
- logFiles.Add($"{trackPath}.hash");
- if (File.Exists($"{trackPath}.skeleton"))
- logFiles.Add($"{trackPath}.skeleton");
- }
- }
- else
- {
- if (File.Exists($"{basePath}.hash"))
- logFiles.Add($"{basePath}.hash");
- if (File.Exists($"{basePath}.skeleton"))
- logFiles.Add($"{basePath}.skeleton");
- }
-
- break;
-
- case MediaType.DVD:
- if (File.Exists($"{basePath}.hash"))
- logFiles.Add($"{basePath}.hash");
- if (File.Exists($"{basePath}.log"))
- logFiles.Add($"{basePath}.log");
- if (File.Exists($"{basePath}.manufacturer"))
- logFiles.Add($"{basePath}.manufacturer");
- if (File.Exists($"{basePath}.1.manufacturer"))
- logFiles.Add($"{basePath}.1.manufacturer");
- if (File.Exists($"{basePath}.2.manufacturer"))
- logFiles.Add($"{basePath}.2.manufacturer");
- if (File.Exists($"{basePath}.physical"))
- logFiles.Add($"{basePath}.physical");
- if (File.Exists($"{basePath}.0.physical"))
- logFiles.Add($"{basePath}.0.physical");
- if (File.Exists($"{basePath}.1.physical"))
- logFiles.Add($"{basePath}.1.physical");
- if (File.Exists($"{basePath}.2.physical"))
- logFiles.Add($"{basePath}.2.physical");
- if (File.Exists($"{basePath}.skeleton"))
- logFiles.Add($"{basePath}.skeleton");
- if (File.Exists($"{basePath}.state"))
- logFiles.Add($"{basePath}.state");
- break;
-
- case MediaType.HDDVD: // TODO: Confirm that this information outputs
- case MediaType.BluRay:
- if (File.Exists($"{basePath}.hash"))
- logFiles.Add($"{basePath}.hash");
- if (File.Exists($"{basePath}.log"))
- logFiles.Add($"{basePath}.log");
- if (File.Exists($"{basePath}.physical"))
- logFiles.Add($"{basePath}.physical");
- if (File.Exists($"{basePath}.0.physical"))
- logFiles.Add($"{basePath}.0.physical");
- if (File.Exists($"{basePath}.1.physical"))
- logFiles.Add($"{basePath}.1.physical");
- if (File.Exists($"{basePath}.2.physical"))
- logFiles.Add($"{basePath}.2.physical");
- if (File.Exists($"{basePath}.skeleton"))
- logFiles.Add($"{basePath}.skeleton");
- if (File.Exists($"{basePath}.state"))
- logFiles.Add($"{basePath}.state");
- break;
- }
-
- return logFiles;
- }
-
///
public override bool IsDumpingCommand()
{
@@ -1473,1104 +896,5 @@ namespace MPF.Core.Modules.Redumper
}
#endregion
-
- #region Information Extraction Methods
-
- ///
- /// Get the cuesheet from the input file, if possible
- ///
- /// Log file location
- /// Newline-delimited cuesheet if possible, null on error
- private static string? GetCuesheet(string log)
- {
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(log))
- return null;
-
- try
- {
- // Fast forward to the dat line
- using var sr = File.OpenText(log);
- while (!sr.EndOfStream && sr.ReadLine()?.TrimStart()?.StartsWith("CUE [") == false) ;
- if (sr.EndOfStream)
- return null;
-
- // Now that we're at the relevant entries, read each line in and concatenate
- string? cueString = string.Empty, line = sr.ReadLine()?.Trim();
- while (!string.IsNullOrEmpty(line))
- {
- cueString += line + "\n";
- line = sr.ReadLine()?.Trim();
- }
-
- return cueString.TrimEnd('\n');
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Get the datfile from the input file, if possible
- ///
- /// Log file location
- /// Newline-delimited datfile if possible, null on error
- private static string? GetDatfile(string log)
- {
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(log))
- return null;
-
- try
- {
- using var sr = File.OpenText(log);
- string? datString = null;
-
- // Find all occurrences of the hash information
- while (!sr.EndOfStream)
- {
- // Fast forward to the dat line
- while (!sr.EndOfStream && sr.ReadLine()?.TrimStart()?.StartsWith("dat:") == false) ;
- if (sr.EndOfStream)
- break;
-
- // Now that we're at the relevant entries, read each line in and concatenate
- datString = string.Empty;
- var line = sr.ReadLine()?.Trim();
- while (line?.StartsWith("
- /// Get reported disc type information, if possible
- ///
- /// Log file location
- /// True if disc type info was set, false otherwise
- private static bool GetDiscType(string log, out string? discTypeOrBookType)
- {
- // Set the default values
- discTypeOrBookType = null;
-
- // If the file doesn't exist, we can't get the info
- if (!File.Exists(log))
- return false;
-
- try
- {
- using var sr = File.OpenText(log);
- var line = sr.ReadLine();
- while (line != null)
- {
- // Trim the line for later use
- line = line.Trim();
-
- // The profile is listed in a single line
- if (line.StartsWith("current profile:"))
- {
- // current profile:
- discTypeOrBookType = line.Substring("current profile: ".Length);
- }
-
- line = sr.ReadLine();
- }
-
- return true;
- }
- catch
- {
- // We don't care what the exception is right now
- discTypeOrBookType = null;
- return false;
- }
- }
-
- ///
- /// Get all Volume Identifiers
- ///
- /// Log file location
- /// Volume labels (by type), or null if none present
- private static bool GetVolumeLabels(string log, out Dictionary> volLabels)
- {
- // If the file doesn't exist, can't get the volume labels
- volLabels = [];
- if (!File.Exists(log))
- return false;
-
- try
- {
- using var sr = File.OpenText(log);
- var line = sr.ReadLine();
-
- while (line != null)
- {
- // Trim the line for later use
- line = line.Trim();
-
- // ISO9660 Volume Identifier
- if (line.StartsWith("volume identifier: "))
- {
- string label = line.Substring("volume identifier: ".Length);
-
- // Skip if label is blank
- if (label == null || label.Length <= 0)
- break;
-
- if (volLabels.ContainsKey(label))
- volLabels[label].Add("ISO");
- else
- volLabels[label] = ["ISO"];
-
- // Redumper log currently only outputs ISO9660 label, end here
- break;
- }
-
- line = sr.ReadLine();
- }
-
- // Return true if a volume label was found
- return volLabels.Count > 0;
- }
- catch
- {
- // We don't care what the exception is right now
- volLabels = [];
- return false;
- }
- }
-
- ///
- /// Get the DVD protection information, if possible
- ///
- /// Log file location
- /// Indicates whether region and protection type are always included
- /// Formatted string representing the DVD protection, null on error
- private static string? GetDVDProtection(string log, bool includeAlways)
- {
- // If one of the files doesn't exist, we can't get info from them
- if (!File.Exists(log))
- return null;
-
- // Setup all of the individual pieces
- string? region = null, rceProtection = null, copyrightProtectionSystemType = null, vobKeys = null, decryptedDiscKey = null;
- using (var sr = File.OpenText(log))
- {
- try
- {
- // Fast forward to the copyright information
- while (sr.ReadLine()?.Trim().StartsWith("copyright:") == false) ;
-
- // Now read until we hit the manufacturing information
- var line = sr.ReadLine()?.Trim();
- while (line != null && !sr.EndOfStream)
- {
- if (line.StartsWith("protection system type"))
- {
- copyrightProtectionSystemType = line.Substring("protection system type: ".Length);
- if (copyrightProtectionSystemType == "none" || copyrightProtectionSystemType == "")
- copyrightProtectionSystemType = "No";
- }
- else if (line.StartsWith("region management information:"))
- {
- region = line.Substring("region management information: ".Length);
- }
- else if (line.StartsWith("disc key"))
- {
- decryptedDiscKey = line.Substring("disc key: ".Length).Replace(':', ' ');
- }
- else if (line.StartsWith("title keys"))
- {
- vobKeys = string.Empty;
-
- line = sr.ReadLine()?.Trim();
- while (!string.IsNullOrEmpty(line))
- {
- var match = Regex.Match(line, @"^(.*?): (.*?)$", RegexOptions.Compiled);
- if (match.Success)
- {
- string normalizedKey = match.Groups[2].Value.Replace(':', ' ');
- if (normalizedKey == "none" || normalizedKey == "")
- normalizedKey = "No Title Key";
- else if (normalizedKey == "")
- normalizedKey = "Error Retrieving Title Key";
-
- vobKeys += $"{match.Groups[1].Value} Title Key: {match.Groups[2].Value.Replace(':', ' ')}\n";
- }
- else
- {
- break;
- }
-
- line = sr.ReadLine()?.Trim();
- }
- }
- else
- {
- break;
- }
-
- line = sr.ReadLine()?.Trim();
- }
- }
- catch { }
- }
-
- // Filter out if we're not always including information
- if (!includeAlways)
- {
- if (region == "1 2 3 4 5 6 7 8")
- region = null;
- if (copyrightProtectionSystemType == "No")
- copyrightProtectionSystemType = null;
- }
-
- // Now we format everything we can
- string protection = string.Empty;
- if (!string.IsNullOrEmpty(region))
- protection += $"Region: {region}\n";
- if (!string.IsNullOrEmpty(rceProtection))
- protection += $"RCE Protection: {rceProtection}\n";
- if (!string.IsNullOrEmpty(copyrightProtectionSystemType))
- protection += $"Copyright Protection System Type: {copyrightProtectionSystemType}\n";
- if (!string.IsNullOrEmpty(vobKeys))
- protection += vobKeys;
- if (!string.IsNullOrEmpty(decryptedDiscKey))
- protection += $"Decrypted Disc Key: {decryptedDiscKey}\n";
-
- return protection;
- }
-
- ///
- /// Get the detected error counts from the input files, if possible
- ///
- /// Log file location
- /// True if error counts could be retrieved, false otherwise
- public static bool GetErrorCount(string log, out long redumpErrors, out long c2Errors)
- {
- // Set the default values for error counts
- redumpErrors = -1; c2Errors = -1;
-
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(log))
- return false;
-
- try
- {
- using var sr = File.OpenText(log);
-
- // Find the error counts
- while (!sr.EndOfStream)
- {
- var line = sr.ReadLine()?.Trim();
- if (line == null)
- break;
-
- // C2:
- if (line.StartsWith("C2:"))
- {
- string[] parts = line.Split(' ');
- if (!long.TryParse(parts[1], out c2Errors))
- c2Errors = -1;
- }
-
- // REDUMP.ORG errors:
- else if (line.StartsWith("REDUMP.ORG errors:"))
- {
- string[] parts = line!.Split(' ');
- if (!long.TryParse(parts[2], out redumpErrors))
- redumpErrors = -1;
- }
- }
-
- // If the Redump error count is -1, then an issue occurred
- return redumpErrors != -1;
- }
- catch
- {
- // We don't care what the exception is right now
- return false;
- }
- }
-
- ///
- /// Get hardware information from the input file, if possible
- ///
- /// Log file location
- /// True if hardware info was set, false otherwise
- private static bool GetHardwareInfo(string log, out string? manufacturer, out string? model, out string? firmware)
- {
- // Set the default values
- manufacturer = null; model = null; firmware = null;
-
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(log))
- return false;
-
- try
- {
- // Fast forward to the drive information line
- using var sr = File.OpenText(log);
- while (!(sr.ReadLine()?.Trim().StartsWith("drive path:") ?? true)) ;
-
- // If we find the hardware info line, return each value
- // drive: - (revision level: , vendor specific: )
- var regex = new Regex(@"drive: (.+) - (.+) \(revision level: (.+), vendor specific: (.+)\)", RegexOptions.Compiled);
-
- string? line;
- while ((line = sr.ReadLine()) != null)
- {
- var match = regex.Match(line.Trim());
- if (match.Success)
- {
- manufacturer = match.Groups[1].Value;
- model = match.Groups[2].Value;
- firmware = match.Groups[3].Value;
- firmware += match.Groups[4].Value == "" ? "" : $" ({match.Groups[4].Value})";
- return true;
- }
- }
-
- // We couldn't detect it then
- return false;
- }
- catch
- {
- // We don't care what the exception is right now
- return false;
- }
- }
-
- ///
- /// Get the layerbreaks from the input file, if possible
- ///
- /// Log file location
- /// True if any layerbreaks were found, false otherwise
- private static bool GetLayerbreaks(string log, out string? layerbreak1, out string? layerbreak2, out string? layerbreak3)
- {
- // Set the default values
- layerbreak1 = null; layerbreak2 = null; layerbreak3 = null;
-
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(log))
- return false;
-
- try
- {
- // Find the layerbreak
- using var sr = File.OpenText(log);
- while (!sr.EndOfStream)
- {
- var line = sr.ReadLine()?.Trim();
-
- // If we have a null line, just break
- if (line == null)
- break;
-
- // Single-layer discs have no layerbreak
- if (line.Contains("layers count: 1"))
- {
- return false;
- }
-
- // Dual-layer discs have a regular layerbreak (old)
- else if (line.StartsWith("data "))
- {
- // data { LBA: .. , length: , hLBA: .. }
- string[] split = line.Split(' ').Where(s => !string.IsNullOrEmpty(s)).ToArray();
- layerbreak1 ??= split[7].TrimEnd(',');
- }
-
- // Dual-layer discs have a regular layerbreak (new)
- else if (line.StartsWith("layer break:"))
- {
- // layer break:
- layerbreak1 = line.Substring("layer break: ".Length).Trim();
- }
-
- // Multi-layer discs have the layer in the name
- else if (line.StartsWith("layer break (layer: 0):"))
- {
- // layer break (layer: 0):
- layerbreak1 = line.Substring("layer break (layer: 0): ".Length).Trim();
- }
- else if (line.StartsWith("layer break (layer: 1):"))
- {
- // layer break (layer: 1):
- layerbreak2 = line.Substring("layer break (layer: 1): ".Length).Trim();
- }
- else if (line.StartsWith("layer break (layer: 2):"))
- {
- // layer break (layer: 2):
- layerbreak3 = line.Substring("layer break (layer: 2): ".Length).Trim();
- }
- }
-
- // Return the layerbreak, if possible
- return true;
- }
- catch
- {
- // We don't care what the exception is right now
- return false;
- }
- }
-
- ///
- /// Get multisession information from the input file, if possible
- ///
- /// Log file location
- /// Formatted multisession information, null on error
- private static string? GetMultisessionInformation(string log)
- {
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(log))
- return null;
-
- try
- {
- // Fast forward to the multisession lines
- using var sr = File.OpenText(log);
- while (!sr.EndOfStream && sr.ReadLine()?.Trim()?.StartsWith("multisession:") == false) ;
- if (sr.EndOfStream)
- return null;
-
- // Now that we're at the relevant lines, find the session info
- string? firstSession = null, secondSession = null;
- while (!sr.EndOfStream)
- {
- var line = sr.ReadLine()?.Trim();
-
- // If we have a null line, just break
- if (line == null)
- break;
-
- // Store the first session range
- if (line.Contains("session 1:"))
- firstSession = line.Substring("session 1: ".Length).Trim();
-
- // Store the secomd session range
- else if (line.Contains("session 2:"))
- secondSession = line.Substring("session 2: ".Length).Trim();
- }
-
- // If either is blank, we don't have multisession
- if (string.IsNullOrEmpty(firstSession) || string.IsNullOrEmpty(secondSession))
- return null;
-
- // Create and return the formatted output
- return $"Session 1: {firstSession}\nSession 2: {secondSession}";
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Get the existence of an anti-modchip string from the input file, if possible
- ///
- /// Log file location
- /// Anti-modchip existence if possible, false on error
- private static bool? GetPlayStationAntiModchipDetected(string log)
- {
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(log))
- return null;
-
- try
- {
- // Check for the anti-modchip strings
- using var sr = File.OpenText(log);
- var line = sr.ReadLine()?.Trim();
- while (!sr.EndOfStream)
- {
- if (line == null)
- return false;
-
- if (line.StartsWith("anti-modchip: no"))
- return false;
- else if (line.StartsWith("anti-modchip: yes"))
- return true;
-
- line = sr.ReadLine()?.Trim();
- }
-
- return false;
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Get the detected missing EDC count from the input files, if possible
- ///
- /// Log file location
- /// Status of PS1 EDC, if possible
- private static bool? GetPlayStationEDCStatus(string log)
- {
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(log))
- return null;
-
- try
- {
- // Check for the EDC strings
- using var sr = File.OpenText(log);
- var line = sr.ReadLine()?.Trim();
- while (!sr.EndOfStream)
- {
- if (line == null)
- return false;
-
- if (line.Contains("EDC: no"))
- return false;
- else if (line.Contains("EDC: yes"))
- return true;
-
- line = sr.ReadLine()?.Trim();
- }
-
- return false;
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Get the info from a PlayStation disc, if possible
- ///
- /// Log file location
- /// True if section found, null on error
- private static bool GetPlayStationInfo(string log, out string? exeDate, out string? serial, out string? version, out string? firmware)
- {
- // Set the default values
- exeDate = null; serial = null; version = null; firmware = null;
-
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(log))
- return false;
-
- try
- {
- // Fast forward to the PS info line
- using var sr = File.OpenText(log);
- string? line;
- while (!sr.EndOfStream)
- {
- line = sr.ReadLine()?.TrimStart();
- if (line?.StartsWith("PSX [") == true ||
- line?.StartsWith("PS2 [") == true ||
- line?.StartsWith("PS3 [") == true ||
- line?.StartsWith("PS4 [") == true ||
- line?.StartsWith("PS5 [") == true)
- break;
- }
- if (sr.EndOfStream)
- return false;
-
- while (!sr.EndOfStream)
- {
- line = sr.ReadLine()?.TrimStart();
- if (line == null)
- break;
-
- if (line.StartsWith("EXE date:"))
- {
- exeDate = line.Substring("EXE date: ".Length).Trim();
- }
- else if (line.StartsWith("serial:"))
- {
- serial = line.Substring("serial: ".Length).Trim();
- }
- else if (line.StartsWith("version:"))
- {
- version = line.Substring("version: ".Length).Trim();
- }
- else if (line.StartsWith("firmware:"))
- {
- firmware = line.Substring("firmware: ".Length).Trim();
- }
- else
- {
- break;
- }
- }
-
- return true;
- }
- catch
- {
- // We don't care what the exception is right now
- return false;
- }
- }
-
- ///
- /// Get the LibCrypt data from the input file, if possible
- ///
- /// Log file location
- /// PS1 LibCrypt data, if possible
- private static string? GetPlayStationLibCryptData(string log)
- {
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(log))
- return null;
-
- try
- {
- // Fast forward to the LibCrypt line
- using var sr = File.OpenText(log);
- while (!sr.EndOfStream && sr.ReadLine()?.TrimStart()?.StartsWith("libcrypt:") == false) ;
- if (sr.EndOfStream)
- return null;
-
- // Now that we're at the relevant entries, read each line in and concatenate
- string? libCryptString = "", line = sr.ReadLine()?.Trim();
- while (line?.StartsWith("MSF:") == true)
- {
- libCryptString += line + "\n";
- line = sr.ReadLine()?.Trim();
- }
-
- return libCryptString.TrimEnd('\n');
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Get the existence of LibCrypt from the input file, if possible
- ///
- /// Log file location
- /// Status of PS1 LibCrypt, if possible
- private static bool? GetPlayStationLibCryptStatus(string log)
- {
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(log))
- return null;
-
- try
- {
- // Check for the libcrypt strings
- using var sr = File.OpenText(log);
- var line = sr.ReadLine()?.Trim();
- while (!sr.EndOfStream)
- {
- if (line == null)
- return false;
-
- if (line.StartsWith("libcrypt: no"))
- return false;
- else if (line.StartsWith("libcrypt: yes"))
- return true;
-
- line = sr.ReadLine()?.Trim();
- }
-
- return false;
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Get the PVD from the input file, if possible
- ///
- /// Log file location
- /// Newline-delimited PVD if possible, null on error
- private static string? GetPVD(string log)
- {
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(log))
- return null;
-
- try
- {
- // Fast forward to the PVD line
- using var sr = File.OpenText(log);
- while (!sr.EndOfStream && sr.ReadLine()?.TrimStart()?.StartsWith("PVD:") == false) ;
- if (sr.EndOfStream)
- return null;
-
- // Now that we're at the relevant entries, read each line in and concatenate
- string? pvdString = "", line = sr.ReadLine();
- while (line?.StartsWith("03") == true)
- {
- pvdString += line + "\n";
- line = sr.ReadLine();
- }
-
- return pvdString.TrimEnd('\n');
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Get the non-zero data start from the input file, if possible
- ///
- /// Log file location
- /// Non-zero dta start if possible, null on error
- private static string? GetRingNonZeroDataStart(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 sample range, return the start value only
- using var sr = File.OpenText(log);
- while (!sr.EndOfStream)
- {
- string? line = sr.ReadLine()?.TrimStart();
- if (line?.StartsWith("non-zero data sample range") == true)
- return line.Substring("non-zero data sample range: [".Length).Trim().Split(' ')[0];
- }
-
- // We couldn't detect it then
- return null;
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Get the build info from a Saturn disc, if possible
- ///
- /// <String representing a formatter variant of the Saturn header
- /// True on successful extraction of info, false otherwise
- /// TODO: Remove when Redumper gets native reading support
- private static bool GetSaturnBuildInfo(string? segaHeader, out string? serial, out string? version, out string? date)
- {
- serial = null; version = null; date = null;
-
- // If the input header is null, we can't do a thing
- if (string.IsNullOrEmpty(segaHeader))
- return false;
-
- // Now read it in cutting it into lines for easier parsing
- try
- {
- string[] header = segaHeader!.Split('\n');
- string serialVersionLine = header[2].Substring(58);
- string dateLine = header[3].Substring(58);
- serial = serialVersionLine.Substring(0, 10).Trim();
- version = serialVersionLine.Substring(10, 6).TrimStart('V', 'v');
- date = dateLine.Substring(0, 8);
- date = $"{date[0]}{date[1]}{date[2]}{date[3]}-{date[4]}{date[5]}-{date[6]}{date[7]}";
- return true;
- }
- catch
- {
- // We don't care what the error is
- return false;
- }
- }
-
- ///
- /// Get the header from a Saturn, if possible
- ///
- /// Log file location
- /// Header as a byte array if possible, null on error
- private static string? GetSaturnHeader(string log)
- {
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(log))
- return null;
-
- try
- {
- // Fast forward to the SS line
- using var sr = File.OpenText(log);
- while (!sr.EndOfStream && sr.ReadLine()?.TrimStart()?.StartsWith("SS [") == false) ;
- if (sr.EndOfStream)
- return null;
-
- string? line, headerString = "";
- while (!sr.EndOfStream)
- {
- line = sr.ReadLine()?.TrimStart();
- if (line?.StartsWith("header:") == true)
- {
- 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 header from a Saturn, if possible
- ///
- /// Log file location
- /// Header as a byte array if possible, null on error
- private static string? GetSecuROMData(string log)
- {
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(log))
- return null;
-
- try
- {
- // Fast forward to the SecuROM line
- using var sr = File.OpenText(log);
- while (!sr.EndOfStream && sr.ReadLine()?.TrimStart()?.StartsWith("SecuROM [") == false) ;
- if (sr.EndOfStream)
- return null;
-
- var lines = new List();
- while (!sr.EndOfStream)
- {
- var line = sr.ReadLine()?.TrimStart();
-
- // Skip the "version"/"scheme" line
- if (line?.StartsWith("version:") == true || line?.StartsWith("scheme:") == true)
- continue;
-
- // Only read until while there are MSF lines
- if (line?.StartsWith("MSF:") != true)
- break;
-
- lines.Add(line);
- }
-
- return string.Join("\n", [.. lines]).TrimEnd('\n');
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Get the header from a Sega CD / Mega CD, if possible
- ///
- /// Log file location
- /// Header as a byte array if possible, null on error
- private static string? GetSegaCDHeader(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("MCD [") == 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("01") == 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 universal hash from the input file, if possible
- ///
- /// Log file location
- /// Universal hash if possible, null on error
- private static string? GetUniversalHash(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 universal hash line, return the hash only
- using var sr = File.OpenText(log);
- while (!sr.EndOfStream)
- {
- string? line = sr.ReadLine()?.TrimStart();
- if (line?.StartsWith("Universal Hash") == true)
- return line.Substring("Universal Hash (SHA-1): ".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 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
- ///
- /// Log file location
- /// Version if possible, null on error
- private static string? GetVersion(string log)
- {
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(log))
- return null;
-
- // Samples:
- // redumper v2022.10.28 [Oct 28 2022, 05:41:43] (print usage: --help,-h)
- // redumper v2022.12.22 build_87 [Dec 22 2022, 01:56:26]
-
- try
- {
- // Skip first line (dump date)
- using var sr = File.OpenText(log);
- sr.ReadLine();
-
- // Get the next non-warning line
- string nextLine = sr.ReadLine()?.Trim() ?? string.Empty;
- if (nextLine.StartsWith("warning:", StringComparison.OrdinalIgnoreCase))
- nextLine = sr.ReadLine()?.Trim() ?? string.Empty;
-
- // Generate regex
- // Permissive
- var regex = new Regex(@"^redumper (v.+) \[.+\]", RegexOptions.Compiled);
- // Strict
- //var regex = new Regex(@"^redumper (v\d{4}\.\d{2}\.\d{2}(| build_\d+)) \[.+\]", RegexOptions.Compiled);
-
- // Extract the version string
- var match = regex.Match(nextLine);
- var version = match.Groups[1].Value;
- return string.IsNullOrEmpty(version) ? null : version;
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- #endregion
}
}
diff --git a/MPF.Core/Modules/UmdImageCreator/Parameters.cs b/MPF.Core/Modules/UmdImageCreator/Parameters.cs
index 79294d11..62e50c60 100644
--- a/MPF.Core/Modules/UmdImageCreator/Parameters.cs
+++ b/MPF.Core/Modules/UmdImageCreator/Parameters.cs
@@ -1,11 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using MPF.Core.Converters;
-using MPF.Core.Data;
-using SabreTools.Hashing;
-using SabreTools.RedumpLib;
+using MPF.Core.Data;
using SabreTools.RedumpLib.Data;
namespace MPF.Core.Modules.UmdImageCreator
@@ -30,306 +23,5 @@ namespace MPF.Core.Modules.UmdImageCreator
: base(system, type, drivePath, filename, driveSpeed, options)
{
}
-
- #region BaseParameters Implementations
-
- ///
- public override (bool, List) CheckAllOutputFilesExist(string basePath, bool preCheck)
- {
- var missingFiles = new List();
- switch (this.Type)
- {
- case MediaType.UMD:
- if (!File.Exists($"{basePath}_logs.zip") || !preCheck)
- {
- if (!File.Exists($"{basePath}_disc.txt"))
- missingFiles.Add($"{basePath}_disc.txt");
- if (!File.Exists($"{basePath}_mainError.txt"))
- missingFiles.Add($"{basePath}_mainError.txt");
- if (!File.Exists($"{basePath}_mainInfo.txt"))
- missingFiles.Add($"{basePath}_mainInfo.txt");
- if (!File.Exists($"{basePath}_volDesc.txt"))
- missingFiles.Add($"{basePath}_volDesc.txt");
- }
-
- break;
-
- default:
- missingFiles.Add("Media and system combination not supported for UmdImageCreator");
- break;
- }
-
- return (!missingFiles.Any(), missingFiles);
- }
-
- ///
- public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive? drive, bool includeArtifacts)
- {
- // Ensure that required sections exist
- info = Builder.EnsureAllSections(info);
-
- // TODO: Determine if there's a UMDImageCreator version anywhere
- info.DumpingInfo!.DumpingProgram = EnumConverter.LongName(this.InternalProgram);
- info.DumpingInfo.DumpingDate = InfoTool.GetFileModifiedDate(basePath + "_disc.txt")?.ToString("yyyy-MM-dd HH:mm:ss");
-
- // Fill in the volume labels
- if (GetVolumeLabels($"{basePath}_volDesc.txt", out var volLabels))
- VolumeLabels = volLabels;
-
- // Extract info based generically on MediaType
- switch (this.Type)
- {
- case MediaType.UMD:
- info.Extras!.PVD = GetPVD(basePath + "_mainInfo.txt") ?? string.Empty;
-
- if (HashTool.GetStandardHashes(basePath + ".iso", out long filesize, out var crc32, out var md5, out var sha1))
- {
- // Get the Datafile information
- var datafile = new Datafile
- {
- Games = [new Game { Roms = [new Rom { Name = string.Empty, Size = filesize.ToString(), Crc = crc32, Md5 = md5, Sha1 = sha1, }] }]
- };
-
- // Fill in the hash data
- info.TracksAndWriteOffsets!.ClrMameProData = InfoTool.GenerateDatfile(datafile);
-
- info.SizeAndChecksums!.Size = filesize;
- info.SizeAndChecksums.CRC32 = crc32;
- info.SizeAndChecksums.MD5 = md5;
- info.SizeAndChecksums.SHA1 = sha1;
- }
-
- if (GetUMDAuxInfo(basePath + "_disc.txt", out var title, out DiscCategory? umdcat, out var umdversion, out var umdlayer, out long umdsize))
- {
- info.CommonDiscInfo!.Title = title ?? string.Empty;
- info.CommonDiscInfo.Category = umdcat ?? DiscCategory.Games;
- info.VersionAndEditions!.Version = umdversion ?? string.Empty;
- info.SizeAndChecksums!.Size = umdsize;
-
- if (!string.IsNullOrEmpty(umdlayer))
- info.SizeAndChecksums.Layerbreak = Int64.Parse(umdlayer ?? "-1");
- }
-
- break;
- }
-
- // Fill in any artifacts that exist, Base64-encoded, if we need to
- if (includeArtifacts)
- {
- info.Artifacts ??= [];
-
- if (File.Exists($"{basePath}_disc.txt"))
- info.Artifacts["disc"] = GetBase64(GetFullFile($"{basePath}_disc.txt")) ?? string.Empty;
- if (File.Exists($"{basePath}_drive.txt"))
- info.Artifacts["drive"] = GetBase64(GetFullFile($"{basePath}_drive.txt")) ?? string.Empty;
- if (File.Exists($"{basePath}_mainError.txt"))
- info.Artifacts["mainError"] = GetBase64(GetFullFile($"{basePath}_mainError.txt")) ?? string.Empty;
- if (File.Exists($"{basePath}_mainInfo.txt"))
- info.Artifacts["mainInfo"] = GetBase64(GetFullFile($"{basePath}_mainInfo.txt")) ?? string.Empty;
- //if (File.Exists($"{basePath}_PFI.bin"))
- // info.Artifacts["pfi"] = Convert.ToBase64String(File.ReadAllBytes($"{basePath}_PFI.bin")) ?? string.Empty;
- if (File.Exists($"{basePath}_volDesc.txt"))
- info.Artifacts["volDesc"] = GetBase64(GetFullFile($"{basePath}_volDesc.txt")) ?? string.Empty;
- }
- }
-
- ///
- public override List GetLogFilePaths(string basePath)
- {
- var logFiles = new List();
- switch (this.Type)
- {
- case MediaType.UMD:
- if (File.Exists($"{basePath}_disc.txt"))
- logFiles.Add($"{basePath}_disc.txt");
- if (File.Exists($"{basePath}_drive.txt"))
- logFiles.Add($"{basePath}_drive.txt");
- if (File.Exists($"{basePath}_mainError.txt"))
- logFiles.Add($"{basePath}_mainError.txt");
- if (File.Exists($"{basePath}_mainInfo.txt"))
- logFiles.Add($"{basePath}_mainInfo.txt");
- if (File.Exists($"{basePath}_volDesc.txt"))
- logFiles.Add($"{basePath}_volDesc.txt");
-
- if (File.Exists($"{basePath}_PFI.bin"))
- logFiles.Add($"{basePath}_PFI.bin");
-
- break;
- }
-
- return logFiles;
- }
-
- #endregion
-
- #region Information Extraction Methods
-
- ///
- /// Get the PVD from the input file, if possible
- ///
- /// _mainInfo.txt file location
- /// Newline-deliminated PVD if possible, null on error
- private static string? GetPVD(string mainInfo)
- {
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(mainInfo))
- return null;
-
- try
- {
- // Make sure we're in the right sector
- using var sr = File.OpenText(mainInfo);
- while (sr.ReadLine()?.StartsWith("========== LBA[000016, 0x0000010]: Main Channel ==========") == false) ;
-
- // Fast forward to the PVD
- while (sr.ReadLine()?.StartsWith("0310") == false) ;
-
- // Now that we're at the PVD, read each line in and concatenate
- string pvd = "";
- for (int i = 0; i < 6; i++)
- pvd += sr.ReadLine() + "\n"; // 320-370
-
- return pvd;
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Get the UMD auxiliary info from the outputted files, if possible
- ///
- /// _disc.txt file location
- /// True on successful extraction of info, false otherwise
- private static bool GetUMDAuxInfo(string disc, out string? title, out DiscCategory? umdcat, out string? umdversion, out string? umdlayer, out long umdsize)
- {
- title = null; umdcat = null; umdversion = null; umdlayer = null; umdsize = -1;
-
- // If the file doesn't exist, we can't get info from it
- if (!File.Exists(disc))
- return false;
-
- try
- {
- // Loop through everything to get the first instance of each required field
- using var sr = File.OpenText(disc);
- while (!sr.EndOfStream)
- {
- string? line = sr.ReadLine()?.Trim();
- if (line == null)
- break;
-
- if (line.StartsWith("TITLE") && title == null)
- title = line.Substring("TITLE: ".Length);
- else if (line.StartsWith("DISC_VERSION") && umdversion == null)
- umdversion = line.Split(' ')[1];
- else if (line.StartsWith("pspUmdTypes"))
- umdcat = InfoTool.GetUMDCategory(line.Split(' ')[1]);
- else if (line.StartsWith("L0 length"))
- umdlayer = line.Split(' ')[2];
- else if (line.StartsWith("FileSize:"))
- umdsize = Int64.Parse(line.Split(' ')[1]);
- }
-
- // If the L0 length is the size of the full disc, there's no layerbreak
- if (Int64.TryParse(umdlayer, out long umdlayerValue) && umdlayerValue * 2048 == umdsize)
- umdlayer = null;
-
- return true;
- }
- catch
- {
- // We don't care what the exception is right now
- return false;
- }
- }
-
- ///
- /// Get all Volume Identifiers
- ///
- /// _volDesc.txt file location
- /// Volume labels (by type), or null if none present
- /// This is a copy of the code from DiscImageCreator and has extrandous checks
- private static bool GetVolumeLabels(string volDesc, out Dictionary> volLabels)
- {
- // If the file doesn't exist, can't get the volume labels
- volLabels = [];
- if (!File.Exists(volDesc))
- return false;
-
- try
- {
- using var sr = File.OpenText(volDesc);
- var line = sr.ReadLine();
-
- string volType = "UNKNOWN";
- string label;
- while (line != null)
- {
- // Trim the line for later use
- line = line.Trim();
-
- // ISO9660 and extensions section
- if (line.StartsWith("Volume Descriptor Type: "))
- {
- Int32.TryParse(line.Substring("Volume Descriptor Type: ".Length), out int volTypeInt);
- volType = volTypeInt switch
- {
- // 0 => "Boot Record" // Should not not contain a Volume Identifier
- 1 => "ISO", // ISO9660
- 2 => "Joliet",
- // 3 => "Volume Partition Descriptor" // Should not not contain a Volume Identifier
- // 255 => "???" // Should not not contain a Volume Identifier
- _ => "UNKNOWN" // Should not contain a Volume Identifier
- };
- }
- // UDF section
- else if (line.StartsWith("Primary Volume Descriptor Number:"))
- {
- volType = "UDF";
- }
- // Identifier
- else if (line.StartsWith("Volume Identifier: "))
- {
- label = line.Substring("Volume Identifier: ".Length);
-
- // Remove leading non-printable character (unsure why DIC outputs this)
- if (Convert.ToUInt32(label[0]) == 0x7F || Convert.ToUInt32(label[0]) < 0x20)
- label = label.Substring(1);
-
- // Skip if label is blank
- if (label == null || label.Length <= 0)
- {
- volType = "UNKNOWN";
- line = sr.ReadLine();
- continue;
- }
-
- if (volLabels.ContainsKey(label))
- volLabels[label].Add(volType);
- else
- volLabels.Add(label, [volType]);
-
- // Reset volume type
- volType = "UNKNOWN";
- }
-
- line = sr.ReadLine();
- }
-
- // Return true if a volume label was found
- return volLabels.Count > 0;
- }
- catch
- {
- // We don't care what the exception is right now
- volLabels = [];
- return false;
- }
- }
-
- #endregion
}
}
diff --git a/MPF.Core/Modules/XboxBackupCreator/Parameters.cs b/MPF.Core/Modules/XboxBackupCreator/Parameters.cs
index 27d9aa8f..453aa5c7 100644
--- a/MPF.Core/Modules/XboxBackupCreator/Parameters.cs
+++ b/MPF.Core/Modules/XboxBackupCreator/Parameters.cs
@@ -1,11 +1,4 @@
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using MPF.Core.Converters;
-using MPF.Core.Data;
-using MPF.Core.Utilities;
-using SabreTools.Hashing;
-using SabreTools.RedumpLib;
+using MPF.Core.Data;
using SabreTools.RedumpLib.Data;
namespace MPF.Core.Modules.XboxBackupCreator
@@ -30,648 +23,5 @@ namespace MPF.Core.Modules.XboxBackupCreator
: base(system, type, drivePath, filename, driveSpeed, options)
{
}
-
- #region BaseParameters Implementations
-
- ///
- public override (bool, List) CheckAllOutputFilesExist(string basePath, bool preCheck)
- {
- var missingFiles = new List();
- switch (this.Type)
- {
- case MediaType.DVD:
- if (!File.Exists($"{basePath}_logs.zip") || !preCheck)
- {
- string baseDir = Path.GetDirectoryName(basePath) + Path.DirectorySeparatorChar;
- string? logPath = GetLogName(baseDir);
- if (string.IsNullOrEmpty(logPath))
- missingFiles.Add($"{baseDir}Log.txt");
- if (!File.Exists($"{baseDir}DMI.bin"))
- missingFiles.Add($"{baseDir}DMI.bin");
- if (!File.Exists($"{baseDir}PFI.bin"))
- missingFiles.Add($"{baseDir}PFI.bin");
- if (!File.Exists($"{baseDir}SS.bin"))
- missingFiles.Add($"{baseDir}SS.bin");
-
- // Not required from XBC
- //if (!File.Exists($"{basePath}.dvd"))
- // missingFiles.Add($"{basePath}.dvd");
- }
-
- break;
-
- default:
- missingFiles.Add("Media and system combination not supported for XboxBackupCreator");
- break;
- }
-
- return (!missingFiles.Any(), missingFiles);
- }
-
- ///
- public override void GenerateSubmissionInfo(SubmissionInfo info, Options options, string basePath, Drive? drive, bool includeArtifacts)
- {
- // Ensure that required sections exist
- info = Builder.EnsureAllSections(info);
-
- // Get base directory
- string baseDir = Path.GetDirectoryName(basePath) + Path.DirectorySeparatorChar;
-
- // Get log filename
- string? logPath = GetLogName(baseDir);
- if (string.IsNullOrEmpty(logPath))
- return;
-
- // XBC dump info
- info.DumpingInfo!.DumpingProgram = $"{EnumConverter.LongName(this.InternalProgram)} {GetVersion(logPath) ?? "Unknown Version"}";
- info.DumpingInfo.DumpingDate = InfoTool.GetFileModifiedDate(logPath)?.ToString("yyyy-MM-dd HH:mm:ss");
- info.DumpingInfo.Model = GetDrive(logPath) ?? "Unknown Drive";
-
- // Look for read errors
- if (GetReadErrors(logPath, out long readErrors))
- info.CommonDiscInfo!.ErrorsCount = readErrors == -1 ? "Error retrieving error count" : readErrors.ToString();
-
- // Extract info based generically on MediaType
- switch (this.Type)
- {
- case MediaType.DVD:
-
- // Get Layerbreak from .dvd file if possible
- if (GetLayerbreak($"{basePath}.dvd", out long layerbreak))
- info.SizeAndChecksums!.Layerbreak = layerbreak;
-
- // Hash data
- if (HashTool.GetStandardHashes(basePath + ".iso", out long filesize, out var crc32, out var md5, out var sha1))
- {
- // Get the Datafile information
- var datafile = new Datafile
- {
- Games = [new Game { Roms = [new Rom { Name = string.Empty, Size = filesize.ToString(), Crc = crc32, Md5 = md5, Sha1 = sha1, }] }]
- };
-
- // Fill in the hash data
- info.TracksAndWriteOffsets!.ClrMameProData = InfoTool.GenerateDatfile(datafile);
-
- info.SizeAndChecksums!.Size = filesize;
- info.SizeAndChecksums.CRC32 = crc32;
- info.SizeAndChecksums.MD5 = md5;
- info.SizeAndChecksums.SHA1 = sha1;
- }
-
- switch (this.System)
- {
- case RedumpSystem.MicrosoftXbox:
-
- // Parse DMI.bin
- string xmidString = Tools.GetXGD1XMID($"{baseDir}DMI.bin");
- var xmid = SabreTools.Serialization.Wrappers.XMID.Create(xmidString);
- if (xmid != null)
- {
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.XMID] = xmidString?.TrimEnd('\0') ?? string.Empty;
- info.CommonDiscInfo.Serial = xmid.Serial ?? string.Empty;
- if (!options.EnableRedumpCompatibility)
- info.VersionAndEditions!.Version = xmid.Version ?? string.Empty;
-
- info.CommonDiscInfo.Region = InfoTool.GetXGDRegion(xmid.Model.RegionIdentifier);
- }
-
- break;
-
- case RedumpSystem.MicrosoftXbox360:
-
- // Get PVD from ISO
- if (GetPVD(basePath + ".iso", out string? pvd))
- info.Extras!.PVD = pvd;
-
- // Parse Media ID
- //string? mediaID = GetMediaID(logPath);
-
- // Parse DMI.bin
- string xemidString = Tools.GetXGD23XeMID($"{baseDir}DMI.bin");
- var xemid = SabreTools.Serialization.Wrappers.XeMID.Create(xemidString);
- if (xemid != null)
- {
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.XeMID] = xemidString?.TrimEnd('\0') ?? string.Empty;
- info.CommonDiscInfo.Serial = xemid.Serial ?? string.Empty;
- if (!options.EnableRedumpCompatibility)
- info.VersionAndEditions!.Version = xemid.Version ?? string.Empty;
-
- info.CommonDiscInfo.Region = InfoTool.GetXGDRegion(xemid.Model.RegionIdentifier);
- }
-
- break;
- }
-
- // Deal with SS.bin
- if (File.Exists($"{baseDir}SS.bin"))
- {
- // Save security sector ranges
- string? ranges = Tools.GetSSRanges($"{baseDir}SS.bin");
- if (!string.IsNullOrEmpty(ranges))
- info.Extras!.SecuritySectorRanges = ranges;
-
- // TODO: Determine SS version?
- //info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.SSVersion] =
-
- // Recreate RawSS.bin
- RecreateSS(logPath!, $"{baseDir}SS.bin", $"{baseDir}RawSS.bin");
-
- // Run ss_sector_range to get repeatable SS hash
- Tools.CleanSS($"{baseDir}SS.bin", $"{baseDir}SS.bin");
- }
-
- // DMI/PFI/SS CRC32 hashes
- if (File.Exists($"{baseDir}DMI.bin"))
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.DMIHash] = HashTool.GetFileHash($"{baseDir}DMI.bin", HashType.CRC32)?.ToUpperInvariant() ?? string.Empty;
- if (File.Exists($"{baseDir}PFI.bin"))
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.PFIHash] = HashTool.GetFileHash($"{baseDir}PFI.bin", HashType.CRC32)?.ToUpperInvariant() ?? string.Empty;
- if (File.Exists($"{baseDir}SS.bin"))
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.SSHash] = HashTool.GetFileHash($"{baseDir}SS.bin", HashType.CRC32)?.ToUpperInvariant() ?? string.Empty;
-
- break;
- }
-
- // Fill in any artifacts that exist, Base64-encoded, if we need to
- if (includeArtifacts)
- {
- info.Artifacts ??= [];
-
- if (File.Exists(logPath))
- info.Artifacts["log"] = GetBase64(GetFullFile(logPath!)) ?? string.Empty;
- if (File.Exists($"{basePath}.dvd"))
- info.Artifacts["dvd"] = GetBase64(GetFullFile($"{basePath}.dvd")) ?? string.Empty;
- //if (File.Exists($"{baseDir}DMI.bin"))
- // info.Artifacts["dmi"] = Convert.ToBase64String(File.ReadAllBytes($"{baseDir}DMI.bin")) ?? string.Empty;
- // TODO: Include PFI artifact only if the hash doesn't match known PFI hashes
- //if (File.Exists($"{baseDir}PFI.bin"))
- // info.Artifacts["pfi"] = Convert.ToBase64String(File.ReadAllBytes($"{baseDir}PFI.bin")) ?? string.Empty;
- //if (File.Exists($"{baseDir}SS.bin"))
- // info.Artifacts["ss"] = Convert.ToBase64String(File.ReadAllBytes($"{baseDir}SS.bin")) ?? string.Empty;
- //if (File.Exists($"{baseDir}RawSS.bin"))
- // info.Artifacts["rawss"] = Convert.ToBase64String(File.ReadAllBytes($"{baseDir}RawSS.bin")) ?? string.Empty;
- }
- }
-
- ///
- public override List GetLogFilePaths(string basePath)
- {
- var logFiles = new List();
- string baseDir = Path.GetDirectoryName(basePath) + Path.DirectorySeparatorChar;
- switch (this.Type)
- {
- case MediaType.DVD:
- string? logPath = GetLogName(baseDir);
- if (!string.IsNullOrEmpty(logPath))
- logFiles.Add(logPath!);
- if (File.Exists($"{basePath}.dvd"))
- logFiles.Add($"{basePath}.dvd");
- if (File.Exists($"{baseDir}DMI.bin"))
- logFiles.Add($"{baseDir}DMI.bin");
- if (File.Exists($"{baseDir}PFI.bin"))
- logFiles.Add($"{baseDir}PFI.bin");
- if (File.Exists($"{baseDir}SS.bin"))
- logFiles.Add($"{baseDir}SS.bin");
- if (File.Exists($"{baseDir}RawSS.bin"))
- logFiles.Add($"{baseDir}RawSS.bin");
-
- break;
- }
-
- return logFiles;
- }
-
- #endregion
-
- #region Information Extraction Methods
-
- ///
- /// Determines the file path of the XBC log
- ///
- /// Base directory to search in
- /// Log path if found, null otherwise
- private static string? GetLogName(string baseDir)
- {
- if (IsSuccessfulLog($"{baseDir}Log.txt"))
- return $"{baseDir}Log.txt";
-
- // Search for a renamed log file (assume there is only one)
- string[] files = Directory.GetFiles(baseDir, "*.txt", SearchOption.TopDirectoryOnly);
- foreach (string file in files)
- {
- if (IsSuccessfulLog(file))
- return file;
- }
-
- return null;
- }
-
- ///
- /// Checks if Log file has a successful read in it
- ///
- /// Path to log file
- /// True if successful log found, false otherwise
- private static bool IsSuccessfulLog(string log)
- {
- if (!File.Exists(log))
- return false;
-
- // Successful Example:
- // Read completed in 00:50:23
- // Failed Example:
- // Read failed
-
- try
- {
- // If Version is not found, not a valid log file
- if (string.IsNullOrEmpty(GetVersion(log)))
- return false;
-
- // Look for " Read completed in " in log file
- using var sr = File.OpenText(log);
- while (!sr.EndOfStream)
- {
- string? line = sr.ReadLine();
- if (line?.StartsWith(" Read completed in ") == true)
- {
- return true;
- }
- }
-
- // We couldn't find a successful dump
- return false;
- }
- catch
- {
- // We don't care what the exception is right now
- return false;
- }
- }
-
- ///
- /// Get the XBC version if possible
- ///
- /// Path to XBC log file
- /// Version if possible, null on error
- private static string? GetVersion(string? log)
- {
- if (string.IsNullOrEmpty(log) || !File.Exists(log))
- return null;
-
- // Sample:
- // ====================================================================
- // Xbox Backup Creator v2.9 Build:0425 By Redline99
- //
-
- try
- {
- // Assume version is appended after first mention of Xbox Backup Creator
- using var sr = File.OpenText(log);
- while (!sr.EndOfStream)
- {
- string? line = sr.ReadLine()?.Trim();
- if (line?.StartsWith("Xbox Backup Creator ") == true)
- return line.Substring("Xbox Backup Creator ".Length).Trim();
- }
-
- // We couldn't detect the version
- return null;
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Get the drive model from the log
- ///
- /// Path to XBC log file
- /// Drive model if found, null otherwise
- private static string? GetDrive(string? log)
- {
- if (string.IsNullOrEmpty(log) || !File.Exists(log))
- return null;
-
- // Example:
- // ========================================
- // < --Security Sector Details -->
- // Source Drive: SH-D162D
- // ----------------------------------------
-
- try
- {
- // Parse drive model from log file
- using var sr = File.OpenText(log);
- while (!sr.EndOfStream)
- {
- string? line = sr.ReadLine()?.Trim();
- if (line?.StartsWith("Source Drive: ") == true)
- {
- return line.Substring("Source Drive: ".Length).Trim();
- }
- }
-
- // We couldn't detect the drive model
- return null;
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Get the Layerbreak value if possible
- ///
- /// Path to layerbreak file
- /// Layerbreak value if found
- /// True if successful, otherwise false
- ///
- private static bool GetLayerbreak(string? dvd, out long layerbreak)
- {
- layerbreak = 0;
-
- if (string.IsNullOrEmpty(dvd) || !File.Exists(dvd))
- return false;
-
- // Example:
- // LayerBreak=1913776
- // track.iso
-
- try
- {
- // Parse Layerbreak value from DVD file
- using var sr = File.OpenText(dvd);
- while (!sr.EndOfStream)
- {
- string? line = sr.ReadLine()?.Trim();
- if (line?.StartsWith("LayerBreak=") == true)
- {
- return long.TryParse(line.Substring("LayerBreak=".Length).Trim(), out layerbreak);
- }
- }
-
- // We couldn't detect the Layerbreak
- return false;
- }
- catch
- {
- // We don't care what the exception is right now
- return false;
- }
- }
-
- ///
- /// Get the read error count if possible
- ///
- /// Path to XBC log file
- /// Read error count if found, -1 otherwise
- /// True if sucessful, otherwise false
- private bool GetReadErrors(string? log, out long readErrors)
- {
- readErrors = -1;
-
- if (string.IsNullOrEmpty(log) || !File.Exists(log))
- return false;
-
- // TODO: Logic when more than one dump is in the logs
-
- // Example: (replace [E] with drive letter)
- // Creating SplitVid backup image [E]
- // ...
- // Reading Game Partition
- // Setting read speed to 1x
- // Unrecovered read error at Partition LBA: 0
-
- // Example: (replace track with base filename)
- // Creating Layer Break File
- // LayerBreak file saved as: "track.dvd"
- // A total of 1 sectors were zeroed out.
-
- // Example: (for Original Xbox)
- // A total of 65,536 sectors were zeroed out.
- // A total of 31 sectors with read errors were recovered.
-
- try
- {
- // Parse Layerbreak value from DVD file
- using var sr = File.OpenText(log);
- while (!sr.EndOfStream)
- {
- string? line = sr.ReadLine()?.Trim();
- if (line?.StartsWith("Creating Layer Break File") == true)
- {
- // Read error count is two lines below
- line = sr.ReadLine()?.Trim();
- line = sr.ReadLine()?.Trim();
- if (line?.StartsWith("A total of ") == true && line?.EndsWith(" sectors were zeroed out.") == true)
- {
- string? errorCount = line.Substring("A total of ".Length, line.Length - 36).Replace(",", "").Trim();
- bool success = long.TryParse(errorCount, out readErrors);
-
- // Original Xbox should have 65536 read errors when dumping with XBC
- if (this.System == RedumpSystem.MicrosoftXbox)
- {
- if (readErrors == 65536)
- readErrors = 0;
- else if (readErrors > 65536)
- readErrors -= 65536;
- }
-
- return success;
- }
- }
- }
-
- // We couldn't detect the read error count
- return false;
- }
- catch
- {
- // We don't care what the exception is right now
- return false;
- }
- }
-
- ///
- /// Get Xbox360 Media ID from XBC log file
- ///
- /// Path to XBC log file
- /// Media ID if Log successfully parsed, null otherwise
- private string? GetMediaID(string? log)
- {
- if (string.IsNullOrEmpty(log) || !File.Exists(log))
- return null;
-
- if (this.System == RedumpSystem.MicrosoftXbox)
- return null;
-
- // Example:
- // ----------------------------------------
- // Media ID
- // A76B9983D170EFF8749A892BC-8B62A812
- // ----------------------------------------
-
- try
- {
- // Parse Layerbreak value from DVD file
- using var sr = File.OpenText(log);
- while (!sr.EndOfStream)
- {
- string? line = sr.ReadLine()?.Trim();
- if (line?.StartsWith("Media ID") == true)
- {
- line = sr.ReadLine()?.Trim();
- return line?.Substring(25).Trim();
- }
- }
-
- // We couldn't detect the Layerbreak
- return null;
- }
- catch
- {
- // We don't care what the exception is right now
- return null;
- }
- }
-
- ///
- /// Recreate an SS.bin file from XBC log and write it to a file
- ///
- /// Path to XBC log
- /// Path to the clean SS file to read from
- /// Path to the raw SS file to write to
- /// True if successful, false otherwise
- private static bool RecreateSS(string log, string cleanSS, string rawSS)
- {
- if (!File.Exists(log) || !File.Exists(cleanSS))
- return false;
-
- byte[] ss = File.ReadAllBytes(cleanSS);
- if (ss.Length != 2048)
- return false;
-
- if (!RecreateSS(log!, ss))
- return false;
-
- File.WriteAllBytes(rawSS, ss);
- return true;
- }
-
- ///
- /// Recreate an SS.bin byte array from an XBC log.
- /// With help from https://github.com/hadzz/SS-Angle-Fixer/
- ///
- /// Path to XBC log
- /// Byte array of SS sector
- /// True if successful, false otherwise
- private static bool RecreateSS(string log, byte[] ss)
- {
- // Log file must exist
- if (!File.Exists(log))
- return false;
-
- // SS must be complete sector
- if (ss.Length != 2048)
- return false;
-
- // Ignore XGD1 discs
- if (!Tools.GetXGDType(ss, out int xgdType))
- return false;
- if (xgdType == 0)
- return false;
-
- // Don't recreate an already raw SS
- // (but do save to file, so return true)
- if (!Tools.IsCleanSS(ss))
- return true;
-
- // Example replay table:
- /*
- ----------------------------------------
- RT CID MOD DATA Drive Response
- -- -- -- ------------- -------------------
- 01 14 00 033100 0340FF B7D8C32A B703590100
- 03 BE 00 244530 24552F F4B9B528 BE46360500
- 01 97 00 DBBAD0 DBCACF DD7787F4 484977ED00
- 03 45 00 FCAF00 FCBEFF FB7A7773 AAB662FC00
- 05 6B 00 033100 033E7F 0A31252A 0200000200
- 07 46 00 244530 2452AF F8E77EBC 5B00005B00
- 05 36 00 DBBAD0 DBC84F F5DFA735 B50000B500
- 07 A1 00 FCAF00 FCBC7F 6B749DBF 0E01000E01
- E0 50 00 42F4E1 00B6F7 00000000 0000000000
- --------------------------------------------
- */
-
- try
- {
- // Parse Replay Table from log
- using var sr = File.OpenText(log);
- while (!sr.EndOfStream)
- {
- string? line = sr.ReadLine()?.Trim();
- if (line?.StartsWith("RT CID MOD DATA Drive Response") == true)
- {
- // Ignore next line
- line = sr.ReadLine()?.Trim();
- if (sr.EndOfStream)
- return false;
-
- byte[][] responses = new byte[4][];
-
- // Parse the nine rows from replay table
- for (int i = 0; i < 9; i++)
- {
- line = sr.ReadLine()?.Trim();
- // Validate line
- if (sr.EndOfStream || string.IsNullOrEmpty(line) || line!.Length < 44)
- return false;
-
- // Save useful angle responses
- if (i >= 4 && i <= 7)
- {
- byte[]? angles = Tools.HexStringToByteArray(line!.Substring(34, 10));
- if (angles == null || angles.Length != 5)
- return false;
- responses[i - 4] = angles!;
- }
- }
-
- int rtOffset = 0x204;
- if (xgdType == 3)
- rtOffset = 0x24;
-
- // Replace angles
- for (int i = 0; i < 4; i++)
- {
- int offset = rtOffset + (9 * (i + 4));
- for (int j = 0; j < 5; j++)
- {
- // Ignore the middle byte
- if (j == 2)
- continue;
-
- ss[offset + j] = responses[i][j];
- }
- }
-
- return true;
- }
- }
-
- // We couldn't detect the replay table
- return false;
- }
- catch
- {
- // We don't care what the exception is right now
- return false;
- }
- }
-
- #endregion
}
}
diff --git a/MPF.Core/SubmissionInfoTool.cs b/MPF.Core/SubmissionInfoTool.cs
index 43a258a0..a167a561 100644
--- a/MPF.Core/SubmissionInfoTool.cs
+++ b/MPF.Core/SubmissionInfoTool.cs
@@ -5,6 +5,7 @@ using System.Linq;
using System.Threading.Tasks;
using MPF.Core.Data;
using MPF.Core.Modules;
+using MPF.Core.Processors;
using SabreTools.RedumpLib;
using SabreTools.RedumpLib.Data;
using SabreTools.RedumpLib.Web;
@@ -27,6 +28,7 @@ namespace MPF.Core
/// Currently selected media type
/// Options object representing user-defined options
/// Parameters object representing what to send to the internal program
+ /// Processor object representing how to process the outputs
/// Optional result progress callback
/// Optional protection progress callback
/// SubmissionInfo populated based on outputs, null on error
@@ -37,6 +39,7 @@ namespace MPF.Core
MediaType? mediaType,
Options options,
BaseParameters? parameters,
+ BaseProcessor? processor,
IProgress? resultProgress = null,
IProgress? protectionProgress = null)
{
@@ -49,7 +52,7 @@ namespace MPF.Core
string outputFilename = Path.GetFileName(outputPath);
// Check that all of the relevant files are there
- (bool foundFiles, List missingFiles) = parameters.FoundAllFiles(outputDirectory, outputFilename, false);
+ (bool foundFiles, List missingFiles) = processor.FoundAllFiles(outputDirectory, outputFilename, false);
if (!foundFiles)
{
resultProgress?.Report(Result.Failure($"There were files missing from the output:\n{string.Join("\n", [.. missingFiles])}"));
@@ -99,7 +102,7 @@ namespace MPF.Core
info = Builder.EnsureAllSections(info);
// Get specific tool output handling
- parameters?.GenerateSubmissionInfo(info, options, combinedBase, drive, options.IncludeArtifacts);
+ processor?.GenerateSubmissionInfo(info, options, combinedBase, drive, options.IncludeArtifacts);
// Get a list of matching IDs for each line in the DAT
if (!string.IsNullOrEmpty(info.TracksAndWriteOffsets!.ClrMameProData) && options.HasRedumpLogin)
@@ -114,7 +117,7 @@ namespace MPF.Core
info.TracksAndWriteOffsets.ClrMameProData = null;
// Add the volume label to comments, if possible or necessary
- string? volLabels = FormatVolumeLabels(drive?.VolumeLabel, parameters?.VolumeLabels);
+ string? volLabels = FormatVolumeLabels(drive?.VolumeLabel, processor?.VolumeLabels);
if (volLabels != null)
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.VolumeLabel] = volLabels;
diff --git a/MPF.Core/UI/ViewModels/MainViewModel.cs b/MPF.Core/UI/ViewModels/MainViewModel.cs
index 89f1e28b..41b3d256 100644
--- a/MPF.Core/UI/ViewModels/MainViewModel.cs
+++ b/MPF.Core/UI/ViewModels/MainViewModel.cs
@@ -1810,7 +1810,7 @@ namespace MPF.Core.UI.ViewModels
string outputFilename = Path.GetFileName(_environment.OutputPath);
// If a complete dump already exists
- (bool foundFiles, List _) = _environment.Parameters.FoundAllFiles(outputDirectory, outputFilename, true);
+ (bool foundFiles, List _) = _environment.Processor.FoundAllFiles(outputDirectory, outputFilename, true);
if (foundFiles && _displayUserMessage != null)
{
bool? mbresult = _displayUserMessage("Overwrite?", "A complete dump already exists! Are you sure you want to overwrite?", 2, true);
@@ -1826,34 +1826,22 @@ namespace MPF.Core.UI.ViewModels
InternalProgram? programFound = null;
if (programFound == null && _environment.InternalProgram != InternalProgram.Aaru)
{
- Modules.Aaru.Parameters parameters = new("")
- {
- Type = _environment.Type,
- System = _environment.System
- };
- (bool foundOtherFiles, _) = parameters.FoundAllFiles(outputDirectory, outputFilename, true);
+ var processor = new Processors.Aaru(_environment.System, _environment.Type);
+ (bool foundOtherFiles, _) = processor.FoundAllFiles(outputDirectory, outputFilename, true);
if (foundOtherFiles)
programFound = InternalProgram.Aaru;
}
if (programFound == null && _environment.InternalProgram != InternalProgram.DiscImageCreator)
{
- Modules.DiscImageCreator.Parameters parameters = new("")
- {
- Type = _environment.Type,
- System = _environment.System
- };
- (bool foundOtherFiles, _) = parameters.FoundAllFiles(outputDirectory, outputFilename, true);
+ var processor = new Processors.DiscImageCreator(_environment.System, _environment.Type);
+ (bool foundOtherFiles, _) = processor.FoundAllFiles(outputDirectory, outputFilename, true);
if (foundOtherFiles)
programFound = InternalProgram.DiscImageCreator;
}
if (programFound == null && _environment.InternalProgram != InternalProgram.Redumper)
{
- Modules.Redumper.Parameters parameters = new("")
- {
- Type = _environment.Type,
- System = _environment.System
- };
- (bool foundOtherFiles, _) = parameters.FoundAllFiles(outputDirectory, outputFilename, true);
+ var processor = new Processors.Redumper(_environment.System, _environment.Type);
+ (bool foundOtherFiles, _) = processor.FoundAllFiles(outputDirectory, outputFilename, true);
if (foundOtherFiles)
programFound = InternalProgram.Redumper;
}