using System; using System.IO; using DICUI.Data; using DICUI.Utilities; using DICUI.Web; namespace DICUI.CleanRip { /// /// Represents a generic set of CleanRip parameters /// public class Parameters : BaseParameters { /// /// Populate a Parameters object from a param string /// /// String possibly representing a set of parameters public Parameters(string parameters) : base(parameters) { this.InternalProgram = InternalProgram.CleanRip; } /// /// Generate parameters based on a set of known inputs /// /// KnownSystem value to use /// MediaType value to use /// Drive letter to use /// Filename to use /// Drive speed to use /// Enable paranoid mode (safer dumping) /// Enable quiet mode (no beeps) /// User-defined reread count public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, bool paranoid, bool quietMode, int retryCount) : base(system, type, driveLetter, filename, driveSpeed, paranoid, quietMode, retryCount) { } /// /// Blindly generate a parameter string based on the inputs /// /// Correctly formatted parameter string, null on error public override string GenerateParameters() => null; /// /// Get the input path from the implementation /// /// String representing the path, null on error public override string InputPath() => null; /// /// Get the output path from the implementation /// /// String representing the path, null on error public override string OutputPath() => null; /// /// Get the processing speed from the implementation /// /// int? representing the speed, null on error public override int? GetSpeed() => null; /// /// Set the processing speed int the implementation /// /// int? representing the speed public override void SetSpeed(int? speed) { } /// /// Get the MediaType from the current set of parameters /// /// MediaType value if successful, null on error public override MediaType? GetMediaType() => null; /// /// Gets if the current command is considered a dumping command or not /// /// True if it's a dumping command, false otherwise public override bool IsDumpingCommand() => true; /// /// Reset all special variables to have default values /// protected override void ResetValues() { } /// /// Set default parameters for a given system and media type /// /// KnownSystem value to use /// MediaType value to use /// Drive letter to use /// Filename to use /// Drive speed to use /// Enable paranoid mode (safer dumping) /// User-defined reread count protected override void SetDefaultParameters( KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, bool paranoid, int retryCount) { } /// /// Scan a possible parameter string and populate whatever possible /// /// String possibly representing parameters /// protected override bool ValidateAndSetParameters(string parameters) => true; /// /// Validate if all required output files exist /// /// Base filename and path to use for checking /// KnownSystem type representing the media /// MediaType type representing the media /// Optional result progress callback /// public override bool CheckAllOutputFilesExist(string basePath, KnownSystem? system, MediaType? type, IProgress progress = null) { string missingFiles = string.Empty; switch (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")) missingFiles += $";{basePath}-dumpinfo.txt"; if (!File.Exists($"{basePath}.bca")) missingFiles += $";{basePath}.bca"; break; default: return false; } // Use the missing files list as an indicator if (string.IsNullOrEmpty(missingFiles)) { return true; } else { progress?.Report(Result.Failure($"The following files were missing: {missingFiles.TrimStart(';')}")); return false; } } /// /// Generate a SubmissionInfo for the output files /// /// Base submission info to fill in specifics for /// Base filename and path to use for checking /// KnownSystem type representing the media /// MediaType type representing the media /// Drive representing the disc to get information from /// public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, KnownSystem? system, MediaType? type, Drive drive) { info.TracksAndWriteOffsets.ClrMameProData = GetCleanripDatfile(basePath + ".iso", basePath + "-dumpinfo.txt"); // Get the individual hash data, as per internal if (GetISOHashValues(info.TracksAndWriteOffsets.ClrMameProData, out long size, out string crc32, out string md5, out string 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 (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 = GetFullFile(basePath + ".bca", true); if (GetGameCubeWiiInformation(basePath + "-dumpinfo.txt", out Region? gcRegion, out string gcVersion)) { info.CommonDiscInfo.Region = gcRegion ?? info.CommonDiscInfo.Region; info.VersionAndEditions.Version = gcVersion ?? info.VersionAndEditions.Version; } break; } } #region Information Extraction Methods /// /// 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 file doesn't exist, we can't get info from it if (!File.Exists(dumpinfo)) return null; using (StreamReader sr = File.OpenText(dumpinfo)) { 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 if (!sr.ReadLine().Contains("--File Generated by CleanRip")) return null; // Read all lines and gather dat information while (!sr.EndOfStream) { string line = sr.ReadLine().Trim(); 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 /// private static bool GetGameCubeWiiInformation(string dumpinfo, out Region? region, out string version) { region = null; version = null; // If the file doesn't exist, we can't get info from it if (!File.Exists(dumpinfo)) return false; using (StreamReader sr = File.OpenText(dumpinfo)) { try { // Make sure this file is a dumpinfo if (!sr.ReadLine().Contains("--File Generated by CleanRip")) return false; // Read all lines and gather dat information while (!sr.EndOfStream) { string line = sr.ReadLine().Trim(); if (line.StartsWith("Version")) { version = line.Substring(9); } else if (line.StartsWith("Filename")) { string serial = line.Substring(10); // 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.USA; break; case 'F': region = Region.France; break; case 'I': region = Region.Italy; break; case 'J': region = Region.Japan; break; case 'K': region = Region.Korea; 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.USA; // Japanese import to USA break; case 'P': region = Region.Europe; break; case 'R': region = Region.Russia; break; case 'S': region = Region.Spain; break; case 'Q': region = Region.Korea; // Korea with Japanese language break; case 'T': region = Region.Korea; // 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 } }