From 512f7ae016cd4428372970883d11d3b468fb63ca Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Fri, 12 Mar 2021 14:59:04 -0800 Subject: [PATCH] Clean up parameters and related This makes some former virtual methods into properties, cleans up the location of some logic, and makes the BaseParameters class a little neater --- MPF.Check/Program.cs | 1 - MPF.Library/Aaru/Parameters.cs | 686 +++++------ MPF.Library/CleanRIp/Parameters.cs | 18 +- MPF.Library/DD/Parameters.cs | 174 +-- MPF.Library/Data/BaseParameters.cs | 144 ++- MPF.Library/DiscImageCreator/Parameters.cs | 1195 ++++++++++---------- MPF.Library/UmdImageCreator/Parameters.cs | 18 +- MPF.Library/Utilities/DumpEnvironment.cs | 182 ++- MPF.Test/Utilities/DumpEnvironmentTest.cs | 9 +- MPF/Windows/MainWindow.xaml.cs | 20 +- 10 files changed, 1239 insertions(+), 1208 deletions(-) diff --git a/MPF.Check/Program.cs b/MPF.Check/Program.cs index 7362db44..e6106f01 100644 --- a/MPF.Check/Program.cs +++ b/MPF.Check/Program.cs @@ -171,7 +171,6 @@ namespace MPF.Check drive = new Drive(null, new DriveInfo(path)); var env = new DumpEnvironment(options, "", filepath, drive, knownSystem, mediaType, null); - env.FixOutputPaths(); // Finally, attempt to do the output dance var result = env.VerifyAndSaveDumpOutput(resultProgress, protectionProgress).ConfigureAwait(false).GetAwaiter().GetResult(); diff --git a/MPF.Library/Aaru/Parameters.cs b/MPF.Library/Aaru/Parameters.cs index 32490742..d94c4128 100644 --- a/MPF.Library/Aaru/Parameters.cs +++ b/MPF.Library/Aaru/Parameters.cs @@ -19,11 +19,35 @@ namespace MPF.Aaru /// public class Parameters : BaseParameters { + #region Generic Dumping Information + + /// + public override string InputPath => InputValue; + + /// + public override string OutputPath => OutputValue; + + /// + public override int? Speed + { + get { return SpeedValue; } + set { SpeedValue = (sbyte?)value; } + } + + #endregion + + #region Metadata + /// /// Base command to run /// public Command BaseCommand { get; set; } + /// + public override InternalProgram InternalProgram => InternalProgram.Aaru; + + #endregion + /// /// Set of flags to pass to the executable /// @@ -125,134 +149,235 @@ namespace MPF.Aaru #endregion /// - public Parameters(string parameters) - : base(parameters) - { - this.InternalProgram = InternalProgram.Aaru; - } + public Parameters(string parameters) : base(parameters) { } /// public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options) : base(system, type, driveLetter, filename, driveSpeed, options) { - this.InternalProgram = InternalProgram.Aaru; } - /// - protected override void ResetValues() - { - BaseCommand = Command.NONE; - - _flags = new Dictionary(); - - BlockSizeValue = null; - CommentsValue = null; - CreatorValue = null; - CountValue = null; - DriveManufacturerValue = null; - DriveModelValue = null; - DriveRevisionValue = null; - DriveSerialValue = null; - EncodingValue = null; - FormatConvertValue = null; - FormatDumpValue = null; - ImgBurnLogValue = null; - InputValue = null; - Input1Value = null; - Input2Value = null; - LengthValue = null; - MediaBarcodeValue = null; - MediaLastSequenceValue = null; - MediaManufacturerValue = null; - MediaModelValue = null; - MediaPartNumberValue = null; - MediaSequenceValue = null; - MediaSerialValue = null; - MediaTitleValue = null; - MHDDLogValue = null; - NamespaceValue = null; - OptionsValue = null; - OutputValue = null; - OutputPrefixValue = null; - RemoteHostValue = null; - ResumeFileValue = null; - RetryPassesValue = null; - SkipValue = null; - SpeedValue = null; - StartValue = null; - SubchannelValue = null; - WidthValue = null; - XMLSidecarValue = null; - } + #region BaseParameters Implementations /// - protected override void SetDefaultParameters(char driveLetter, string filename, int? driveSpeed, Options options) + public override (bool, List) CheckAllOutputFilesExist(string basePath) { - BaseCommand = Command.MediaDump; - - InputValue = $"\\\\?\\{driveLetter}:"; - OutputValue = filename; - - if (driveSpeed != null) - { - this[Flag.Speed] = true; - SpeedValue = (sbyte?)driveSpeed; - } - - // First check to see if the combination of system and MediaType is valid - var validTypes = Validators.GetValidMediaTypes(this.System); - if (!validTypes.Contains(this.Type)) - return; - - // Set retry count - if (options.AaruRereadCount > 0) - { - this[Flag.RetryPasses] = true; - RetryPassesValue = (short)options.AaruRereadCount; - } - - // Set user-defined options - this[Flag.Debug] = options.AaruEnableDebug; - this[Flag.Verbose] = options.AaruEnableVerbose; - this[Flag.Force] = options.AaruForceDumping; - this[Flag.Private] = options.AaruStripPersonalData; - - // TODO: Look at dump-media formats and the like and see what options there are there to fill in defaults - // Now sort based on disc type + List missingFiles = new List(); switch (this.Type) { case MediaType.CDROM: - this[Flag.FirstPregap] = true; - this[Flag.FixOffset] = true; - this[Flag.Subchannel] = true; - SubchannelValue = "any"; + 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: - // Currently no defaults set - break; - case MediaType.GDROM: - // Currently no defaults set - break; case MediaType.HDDVD: - // Currently no defaults set - break; case MediaType.BluRay: - // Currently no defaults set + 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; - // Special Formats - case MediaType.NintendoGameCubeGameDisc: - // Currently no defaults set - break; - case MediaType.NintendoWiiOpticalDisc: - // Currently no defaults set + default: + return (false, missingFiles); // TODO: Figure out more formats + } + + return (!missingFiles.Any(), missingFiles); + } + + /// + public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, Drive drive) + { + // TODO: Fill in submission info specifics for Aaru + string outputDirectory = Path.GetDirectoryName(basePath); + + // Deserialize the sidecar, if possible + var sidecar = GenerateSidecar(basePath + ".cicm.xml"); + + // Fill in the hash data + info.TracksAndWriteOffsets.ClrMameProData = GenerateDatfile(sidecar, basePath); + + switch (this.Type) + { + case MediaType.CDROM: + // TODO: Can this do GD-ROM? + 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 cdWriteOffset = GetWriteOffset(sidecar) ?? ""; + info.CommonDiscInfo.RingWriteOffset = cdWriteOffset; + info.TracksAndWriteOffsets.OtherWriteOffsets = cdWriteOffset; break; - // Non-optical - case MediaType.FloppyDisk: - // Currently no defaults set + case MediaType.DVD: + case MediaType.HDDVD: + case MediaType.BluRay: + // 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; + } + + // Deal with the layerbreak + string layerbreak = null; + if (this.Type == MediaType.DVD) + layerbreak = GetLayerbreak(sidecar) ?? ""; + 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.IsNullOrWhiteSpace(layerbreak)) + { + info.Extras.PVD = GeneratePVD(sidecar) ?? "Disc has no PVD"; + } + // If we have a dual-layer disc + else + { + info.Extras.PVD = GeneratePVD(sidecar) ?? "Disc has no PVD"; + 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 KnownSystem.DVDAudio: + case KnownSystem.DVDVideo: + info.CopyProtection.Protection = GetDVDProtection(sidecar) ?? ""; + break; + + case KnownSystem.KonamiPython2: + if (GetPlayStationExecutableInfo(drive?.Letter, out string pythonTwoSerial, out RedumpRegion? pythonTwoRegion, out string pythonTwoDate)) + { + info.CommonDiscInfo.Comments += $"Internal Disc Serial: {pythonTwoSerial}\n"; + info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? pythonTwoRegion; + info.CommonDiscInfo.EXEDateBuildDate = pythonTwoDate; + } + + info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? ""; + break; + + case KnownSystem.MicrosoftXBOX: + if (GetXgdAuxInfo(sidecar, out string dmihash, out string pfihash, out string sshash, out string ss, out string ssver)) + { + info.CommonDiscInfo.Comments += $"{Template.XBOXDMIHash}: {dmihash ?? ""}\n" + + $"{Template.XBOXPFIHash}: {pfihash ?? ""}\n" + + $"{Template.XBOXSSHash}: {sshash ?? ""}\n" + + $"{Template.XBOXSSVersion}: {ssver ?? ""}\n"; + info.Extras.SecuritySectorRanges = ss ?? ""; + } + + if (GetXboxDMIInfo(sidecar, out string serial, out string version, out RedumpRegion? region)) + { + info.CommonDiscInfo.Serial = serial ?? ""; + info.VersionAndEditions.Version = version ?? ""; + info.CommonDiscInfo.Region = region; + } + + break; + + case KnownSystem.MicrosoftXBOX360: + if (GetXgdAuxInfo(sidecar, out string dmi360hash, out string pfi360hash, out string ss360hash, out string ss360, out string ssver360)) + { + info.CommonDiscInfo.Comments += $"{Template.XBOXDMIHash}: {dmi360hash ?? ""}\n" + + $"{Template.XBOXPFIHash}: {pfi360hash ?? ""}\n" + + $"{Template.XBOXSSHash}: {ss360hash ?? ""}\n" + + $"{Template.XBOXSSVersion}: {ssver360 ?? ""}\n"; + info.Extras.SecuritySectorRanges = ss360 ?? ""; + } + + if (GetXbox360DMIInfo(sidecar, out string serial360, out string version360, out RedumpRegion? region360)) + { + info.CommonDiscInfo.Serial = serial360 ?? ""; + info.VersionAndEditions.Version = version360 ?? ""; + info.CommonDiscInfo.Region = region360; + } + break; + + case KnownSystem.SonyPlayStation: + if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationSerial, out RedumpRegion? playstationRegion, out string playstationDate)) + { + info.CommonDiscInfo.Comments += $"Internal Disc Serial: {playstationSerial}\n"; + info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationRegion; + info.CommonDiscInfo.EXEDateBuildDate = playstationDate; + } + + info.CopyProtection.AntiModchip = GetPlayStationAntiModchipDetected(drive?.Letter) ? YesNo.Yes : YesNo.No; + break; + + case KnownSystem.SonyPlayStation2: + if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationTwoSerial, out RedumpRegion? playstationTwoRegion, out string playstationTwoDate)) + { + info.CommonDiscInfo.Comments += $"Internal Disc Serial: {playstationTwoSerial}\n"; + info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationTwoRegion; + info.CommonDiscInfo.EXEDateBuildDate = playstationTwoDate; + } + + info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? ""; + break; + + case KnownSystem.SonyPlayStation4: + info.VersionAndEditions.Version = GetPlayStation4Version(drive?.Letter) ?? ""; + break; + + case KnownSystem.SonyPlayStation5: + info.VersionAndEditions.Version = GetPlayStation5Version(drive?.Letter) ?? ""; + break; + } + + // Fill in any artifacts that exist, Base64-encoded + if (File.Exists(basePath + ".cicm.xml")) + info.Artifacts["cicm"] = GetBase64(GetFullFile(basePath + ".cicm.xml")); + 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")); + 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")); + if (File.Exists(basePath + ".sub.log")) + info.Artifacts["sub_log"] = GetBase64(GetFullFile(basePath + ".sub.log")); } /// @@ -903,16 +1028,7 @@ namespace MPF.Aaru } /// - public override string InputPath() => InputValue; - - /// - public override string OutputPath() => OutputValue; - - /// - public override int? GetSpeed() => SpeedValue; - - /// - public override void SetSpeed(int? speed) => SpeedValue = (sbyte?)speed; + public override string GetDefaultExtension(MediaType? mediaType) => Converters.Extension(mediaType); /// public override bool IsDumpingCommand() @@ -927,6 +1043,123 @@ namespace MPF.Aaru } } + /// + protected override void ResetValues() + { + BaseCommand = Command.NONE; + + _flags = new Dictionary(); + + BlockSizeValue = null; + CommentsValue = null; + CreatorValue = null; + CountValue = null; + DriveManufacturerValue = null; + DriveModelValue = null; + DriveRevisionValue = null; + DriveSerialValue = null; + EncodingValue = null; + FormatConvertValue = null; + FormatDumpValue = null; + ImgBurnLogValue = null; + InputValue = null; + Input1Value = null; + Input2Value = null; + LengthValue = null; + MediaBarcodeValue = null; + MediaLastSequenceValue = null; + MediaManufacturerValue = null; + MediaModelValue = null; + MediaPartNumberValue = null; + MediaSequenceValue = null; + MediaSerialValue = null; + MediaTitleValue = null; + MHDDLogValue = null; + NamespaceValue = null; + OptionsValue = null; + OutputValue = null; + OutputPrefixValue = null; + RemoteHostValue = null; + ResumeFileValue = null; + RetryPassesValue = null; + SkipValue = null; + SpeedValue = null; + StartValue = null; + SubchannelValue = null; + WidthValue = null; + XMLSidecarValue = null; + } + + /// + protected override void SetDefaultParameters(char driveLetter, string filename, int? driveSpeed, Options options) + { + BaseCommand = Command.MediaDump; + + InputValue = $"\\\\?\\{driveLetter}:"; + OutputValue = filename; + + if (driveSpeed != null) + { + this[Flag.Speed] = true; + SpeedValue = (sbyte?)driveSpeed; + } + + // First check to see if the combination of system and MediaType is valid + var validTypes = Validators.GetValidMediaTypes(this.System); + if (!validTypes.Contains(this.Type)) + return; + + // Set retry count + if (options.AaruRereadCount > 0) + { + this[Flag.RetryPasses] = true; + RetryPassesValue = (short)options.AaruRereadCount; + } + + // Set user-defined options + this[Flag.Debug] = options.AaruEnableDebug; + this[Flag.Verbose] = options.AaruEnableVerbose; + this[Flag.Force] = options.AaruForceDumping; + this[Flag.Private] = options.AaruStripPersonalData; + + // TODO: Look at dump-media formats and the like and see what options there are there to fill in defaults + // Now sort based on disc type + switch (this.Type) + { + case MediaType.CDROM: + this[Flag.FirstPregap] = true; + this[Flag.FixOffset] = true; + this[Flag.Subchannel] = true; + SubchannelValue = "any"; + break; + case MediaType.DVD: + // Currently no defaults set + break; + case MediaType.GDROM: + // Currently no defaults set + break; + case MediaType.HDDVD: + // Currently no defaults set + break; + case MediaType.BluRay: + // Currently no defaults set + break; + + // Special Formats + case MediaType.NintendoGameCubeGameDisc: + // Currently no defaults set + break; + case MediaType.NintendoWiiOpticalDisc: + // Currently no defaults set + break; + + // Non-optical + case MediaType.FloppyDisk: + // Currently no defaults set + break; + } + } + /// protected override bool ValidateAndSetParameters(string parameters) { @@ -1410,226 +1643,9 @@ namespace MPF.Aaru return true; } - /// - public override (bool, List) CheckAllOutputFilesExist(string basePath) - { - List missingFiles = new List(); - switch (this.Type) - { - case MediaType.CDROM: - 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"); + #endregion - break; - - case MediaType.DVD: - case MediaType.HDDVD: - case MediaType.BluRay: - 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: - return (false, missingFiles); // TODO: Figure out more formats - } - - return (!missingFiles.Any(), missingFiles); - } - - /// - public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, Drive drive) - { - // TODO: Fill in submission info specifics for Aaru - string outputDirectory = Path.GetDirectoryName(basePath); - - // Deserialize the sidecar, if possible - var sidecar = GenerateSidecar(basePath + ".cicm.xml"); - - // Fill in the hash data - info.TracksAndWriteOffsets.ClrMameProData = GenerateDatfile(sidecar, basePath); - - switch (this.Type) - { - case MediaType.CDROM: - // TODO: Can this do GD-ROM? - 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 cdWriteOffset = GetWriteOffset(sidecar) ?? ""; - 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 (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; - } - - // Deal with the layerbreak - string layerbreak = null; - if (this.Type == MediaType.DVD) - layerbreak = GetLayerbreak(sidecar) ?? ""; - 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.IsNullOrWhiteSpace(layerbreak)) - { - info.Extras.PVD = GeneratePVD(sidecar) ?? "Disc has no PVD"; - } - // If we have a dual-layer disc - else - { - info.Extras.PVD = GeneratePVD(sidecar) ?? "Disc has no PVD"; - 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 KnownSystem.DVDAudio: - case KnownSystem.DVDVideo: - info.CopyProtection.Protection = GetDVDProtection(sidecar) ?? ""; - break; - - case KnownSystem.KonamiPython2: - if (GetPlayStationExecutableInfo(drive?.Letter, out string pythonTwoSerial, out RedumpRegion? pythonTwoRegion, out string pythonTwoDate)) - { - info.CommonDiscInfo.Comments += $"Internal Disc Serial: {pythonTwoSerial}\n"; - info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? pythonTwoRegion; - info.CommonDiscInfo.EXEDateBuildDate = pythonTwoDate; - } - - info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? ""; - break; - - case KnownSystem.MicrosoftXBOX: - if (GetXgdAuxInfo(sidecar, out string dmihash, out string pfihash, out string sshash, out string ss, out string ssver)) - { - info.CommonDiscInfo.Comments += $"{Template.XBOXDMIHash}: {dmihash ?? ""}\n" + - $"{Template.XBOXPFIHash}: {pfihash ?? ""}\n" + - $"{Template.XBOXSSHash}: {sshash ?? ""}\n" + - $"{Template.XBOXSSVersion}: {ssver ?? ""}\n"; - info.Extras.SecuritySectorRanges = ss ?? ""; - } - - if (GetXboxDMIInfo(sidecar, out string serial, out string version, out RedumpRegion? region)) - { - info.CommonDiscInfo.Serial = serial ?? ""; - info.VersionAndEditions.Version = version ?? ""; - info.CommonDiscInfo.Region = region; - } - - break; - - case KnownSystem.MicrosoftXBOX360: - if (GetXgdAuxInfo(sidecar, out string dmi360hash, out string pfi360hash, out string ss360hash, out string ss360, out string ssver360)) - { - info.CommonDiscInfo.Comments += $"{Template.XBOXDMIHash}: {dmi360hash ?? ""}\n" + - $"{Template.XBOXPFIHash}: {pfi360hash ?? ""}\n" + - $"{Template.XBOXSSHash}: {ss360hash ?? ""}\n" + - $"{Template.XBOXSSVersion}: {ssver360 ?? ""}\n"; - info.Extras.SecuritySectorRanges = ss360 ?? ""; - } - - if (GetXbox360DMIInfo(sidecar, out string serial360, out string version360, out RedumpRegion? region360)) - { - info.CommonDiscInfo.Serial = serial360 ?? ""; - info.VersionAndEditions.Version = version360 ?? ""; - info.CommonDiscInfo.Region = region360; - } - break; - - case KnownSystem.SonyPlayStation: - if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationSerial, out RedumpRegion? playstationRegion, out string playstationDate)) - { - info.CommonDiscInfo.Comments += $"Internal Disc Serial: {playstationSerial}\n"; - info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationRegion; - info.CommonDiscInfo.EXEDateBuildDate = playstationDate; - } - - info.CopyProtection.AntiModchip = GetPlayStationAntiModchipDetected(drive?.Letter) ? YesNo.Yes : YesNo.No; - break; - - case KnownSystem.SonyPlayStation2: - if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationTwoSerial, out RedumpRegion? playstationTwoRegion, out string playstationTwoDate)) - { - info.CommonDiscInfo.Comments += $"Internal Disc Serial: {playstationTwoSerial}\n"; - info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationTwoRegion; - info.CommonDiscInfo.EXEDateBuildDate = playstationTwoDate; - } - - info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? ""; - break; - - case KnownSystem.SonyPlayStation4: - info.VersionAndEditions.Version = GetPlayStation4Version(drive?.Letter) ?? ""; - break; - - case KnownSystem.SonyPlayStation5: - info.VersionAndEditions.Version = GetPlayStation5Version(drive?.Letter) ?? ""; - break; - } - - // Fill in any artifacts that exist, Base64-encoded - if (File.Exists(basePath + ".cicm.xml")) - info.Artifacts["cicm"] = GetBase64(GetFullFile(basePath + ".cicm.xml")); - 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")); - 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")); - if (File.Exists(basePath + ".sub.log")) - info.Artifacts["sub_log"] = GetBase64(GetFullFile(basePath + ".sub.log")); - } + #region Private Extra Methods /// /// Get the list of commands that use a given flag @@ -1907,6 +1923,8 @@ namespace MPF.Aaru return commands; } + #endregion + #region Process Parameter Helpers /// diff --git a/MPF.Library/CleanRIp/Parameters.cs b/MPF.Library/CleanRIp/Parameters.cs index 7b484693..3a57a5f5 100644 --- a/MPF.Library/CleanRIp/Parameters.cs +++ b/MPF.Library/CleanRIp/Parameters.cs @@ -12,20 +12,24 @@ namespace MPF.CleanRip /// public class Parameters : BaseParameters { + #region Metadata + /// - public Parameters(string parameters) - : base(parameters) - { - this.InternalProgram = InternalProgram.CleanRip; - } + public override InternalProgram InternalProgram => InternalProgram.CleanRip; + + #endregion + + /// + public Parameters(string parameters) : base(parameters) { } /// public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options) : base(system, type, driveLetter, filename, driveSpeed, options) { - this.InternalProgram = InternalProgram.CleanRip; } + #region BaseParameters Implementations + /// public override (bool, List) CheckAllOutputFilesExist(string basePath) { @@ -92,6 +96,8 @@ namespace MPF.CleanRip info.Artifacts["dumpinfo"] = GetBase64(GetFullFile(basePath + "-dumpinfo.txt")); } + #endregion + #region Information Extraction Methods /// diff --git a/MPF.Library/DD/Parameters.cs b/MPF.Library/DD/Parameters.cs index de5a1ce8..5eff05b0 100644 --- a/MPF.Library/DD/Parameters.cs +++ b/MPF.Library/DD/Parameters.cs @@ -13,11 +13,36 @@ namespace MPF.DD /// public class Parameters : BaseParameters { + #region Generic Dumping Information + + /// + public override string InputPath => InputFileValue; + + /// + public override string OutputPath => OutputFileValue; + + /// + /// + public override int? Speed + { + get { return 1; } + set { } + } + + #endregion + + #region Metadata + /// /// Base command to run /// public Command BaseCommand { get; set; } + /// + public override InternalProgram InternalProgram => InternalProgram.DD; + + #endregion + /// /// Set of flags to pass to the executable /// @@ -58,17 +83,77 @@ namespace MPF.DD #endregion /// - public Parameters(string parameters) - : base(parameters) - { - this.InternalProgram = InternalProgram.DD; - } + public Parameters(string parameters) : base(parameters) { } /// public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options) : base(system, type, driveLetter, filename, driveSpeed, options) { - this.InternalProgram = InternalProgram.DD; + } + + #region BaseParameters Implementations + + /// + public override (bool, List) CheckAllOutputFilesExist(string basePath) + { + // TODO: Figure out what sort of output files are expected... just `.bin`? + return (true, new List()); + } + + /// + public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, Drive drive) + { + // TODO: Fill in submission info specifics for DD + string outputDirectory = Path.GetDirectoryName(basePath); + + switch (this.Type) + { + // Determine type-specific differences + } + + switch (this.System) + { + case KnownSystem.KonamiPython2: + if (GetPlayStationExecutableInfo(drive?.Letter, out string pythonTwoSerial, out RedumpRegion? pythonTwoRegion, out string pythonTwoDate)) + { + info.CommonDiscInfo.Comments += $"Internal Disc Serial: {pythonTwoSerial}\n"; + info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? pythonTwoRegion; + info.CommonDiscInfo.EXEDateBuildDate = pythonTwoDate; + } + + info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? ""; + break; + + case KnownSystem.SonyPlayStation: + if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationSerial, out RedumpRegion? playstationRegion, out string playstationDate)) + { + info.CommonDiscInfo.Comments += $"Internal Disc Serial: {playstationSerial}\n"; + info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationRegion; + info.CommonDiscInfo.EXEDateBuildDate = playstationDate; + } + + info.CopyProtection.AntiModchip = GetPlayStationAntiModchipDetected(drive?.Letter) ? YesNo.Yes : YesNo.No; + break; + + case KnownSystem.SonyPlayStation2: + if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationTwoSerial, out RedumpRegion? playstationTwoRegion, out string playstationTwoDate)) + { + info.CommonDiscInfo.Comments += $"Internal Disc Serial: {playstationTwoSerial}\n"; + info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationTwoRegion; + info.CommonDiscInfo.EXEDateBuildDate = playstationTwoDate; + } + + info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? ""; + break; + + case KnownSystem.SonyPlayStation4: + info.VersionAndEditions.Version = GetPlayStation4Version(drive?.Letter) ?? ""; + break; + + case KnownSystem.SonyPlayStation5: + info.VersionAndEditions.Version = GetPlayStation5Version(drive?.Letter) ?? ""; + break; + } } /// @@ -162,13 +247,7 @@ namespace MPF.DD } /// - public override string InputPath() => InputFileValue; - - /// - public override string OutputPath() => OutputFileValue; - - /// - public override int? GetSpeed() => 1; + public override string GetDefaultExtension(MediaType? mediaType) => Converters.Extension(mediaType); /// public override bool IsDumpingCommand() @@ -326,68 +405,9 @@ namespace MPF.DD return true; } - /// - public override (bool, List) CheckAllOutputFilesExist(string basePath) - { - // TODO: Figure out what sort of output files are expected... just `.bin`? - return (true, new List()); - } + #endregion - /// - public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, Drive drive) - { - // TODO: Fill in submission info specifics for DD - string outputDirectory = Path.GetDirectoryName(basePath); - - switch (this.Type) - { - // Determine type-specific differences - } - - switch (this.System) - { - case KnownSystem.KonamiPython2: - if (GetPlayStationExecutableInfo(drive?.Letter, out string pythonTwoSerial, out RedumpRegion? pythonTwoRegion, out string pythonTwoDate)) - { - info.CommonDiscInfo.Comments += $"Internal Disc Serial: {pythonTwoSerial}\n"; - info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? pythonTwoRegion; - info.CommonDiscInfo.EXEDateBuildDate = pythonTwoDate; - } - - info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? ""; - break; - - case KnownSystem.SonyPlayStation: - if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationSerial, out RedumpRegion? playstationRegion, out string playstationDate)) - { - info.CommonDiscInfo.Comments += $"Internal Disc Serial: {playstationSerial}\n"; - info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationRegion; - info.CommonDiscInfo.EXEDateBuildDate = playstationDate; - } - - info.CopyProtection.AntiModchip = GetPlayStationAntiModchipDetected(drive?.Letter) ? YesNo.Yes : YesNo.No; - break; - - case KnownSystem.SonyPlayStation2: - if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationTwoSerial, out RedumpRegion? playstationTwoRegion, out string playstationTwoDate)) - { - info.CommonDiscInfo.Comments += $"Internal Disc Serial: {playstationTwoSerial}\n"; - info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationTwoRegion; - info.CommonDiscInfo.EXEDateBuildDate = playstationTwoDate; - } - - info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? ""; - break; - - case KnownSystem.SonyPlayStation4: - info.VersionAndEditions.Version = GetPlayStation4Version(drive?.Letter) ?? ""; - break; - - case KnownSystem.SonyPlayStation5: - info.VersionAndEditions.Version = GetPlayStation5Version(drive?.Letter) ?? ""; - break; - } - } + #region Private Extra Methods /// /// Get the list of commands that use a given flag @@ -449,6 +469,10 @@ namespace MPF.DD return commands; } + #endregion + + #region Process Parameter Helpers + /// /// Process a boolean parameter /// @@ -587,5 +611,7 @@ namespace MPF.DD return string.Empty; } + + #endregion } } diff --git a/MPF.Library/Data/BaseParameters.cs b/MPF.Library/Data/BaseParameters.cs index 581be892..7c5e6096 100644 --- a/MPF.Library/Data/BaseParameters.cs +++ b/MPF.Library/Data/BaseParameters.cs @@ -32,11 +32,43 @@ namespace MPF.Data #endregion + #region Generic Dumping Information + + /// + /// Input path for operations + /// + public virtual string InputPath => null; + + /// + /// Output path for operations + /// + /// String representing the path, null on error + public virtual string OutputPath => null; + + /// + /// Get the processing speed from the implementation + /// + public virtual int? Speed { get; set; } = null; + + /// + /// Process to track external program + /// + private Process process; + + #endregion + + #region Metadata + /// /// Path to the executable /// public string ExecutablePath { get; set; } + /// + /// Program that this set of parameters represents + /// + public virtual InternalProgram InternalProgram { get; } + /// /// Currently represented system /// @@ -47,15 +79,7 @@ namespace MPF.Data /// public MediaType? Type { get; set; } - /// - /// Program that this set of parameters represents - /// - public InternalProgram InternalProgram { get; set; } - - /// - /// Process to track external program - /// - private Process process; + #endregion /// /// Populate a Parameters object from a param string @@ -84,35 +108,39 @@ namespace MPF.Data SetDefaultParameters(driveLetter, filename, driveSpeed, options); } + #region Abstract Methods + + /// + /// Validate if all required output files exist + /// + /// Base filename and path to use for checking + /// Tuple of true if all required files exist, false otherwise and a list representing missing files + public abstract (bool, List) CheckAllOutputFilesExist(string basePath); + + /// + /// Generate a SubmissionInfo for the output files + /// + /// Base submission info to fill in specifics for + /// Base filename and path to use for checking + /// Drive representing the disc to get information from + public abstract void GenerateSubmissionInfo(SubmissionInfo submissionInfo, string basePath, Drive drive); + + #endregion + + #region Virtual Methods + /// /// Blindly generate a parameter string based on the inputs /// - /// Correctly formatted parameter string, null on error + /// Parameter string for invocation, null on error public virtual string GenerateParameters() => null; /// - /// Get the input path from the implementation + /// Get the default extension for a given media type /// - /// String representing the path, null on error - public virtual string InputPath() => null; - - /// - /// Get the output path from the implementation - /// - /// String representing the path, null on error - public virtual string OutputPath() => null; - - /// - /// Get the processing speed from the implementation - /// - /// int? representing the speed, null on error - public virtual int? GetSpeed() => null; - - /// - /// Set the processing speed int the implementation - /// - /// int? representing the speed - public virtual void SetSpeed(int? speed) { } + /// MediaType value to check + /// String representing the media type, null on error + public virtual string GetDefaultExtension(MediaType? mediaType) => null; /// /// Get the MediaType from the current set of parameters @@ -153,20 +181,9 @@ namespace MPF.Data /// True if the parameters were set correctly, false otherwise protected virtual bool ValidateAndSetParameters(string parameters) => true; - /// - /// Validate if all required output files exist - /// - /// Base filename and path to use for checking - /// Tuple of true if all required files exist, false otherwise and a list representing missing files - public abstract (bool, List) CheckAllOutputFilesExist(string basePath); + #endregion - /// - /// Generate a SubmissionInfo for the output files - /// - /// Base submission info to fill in specifics for - /// Base filename and path to use for checking - /// Drive representing the disc to get information from - public abstract void GenerateSubmissionInfo(SubmissionInfo submissionInfo, string basePath, Drive drive); + #region Execution /// /// Run internal program @@ -209,43 +226,6 @@ namespace MPF.Data process.Close(); } - /// - /// Run internal program async with an input set of parameters - /// - /// - /// Standard output from commandline window - public async Task ExecuteInternalProgram(BaseParameters parameters) - { - Process childProcess; - string output = await Task.Run(() => - { - childProcess = new Process() - { - StartInfo = new ProcessStartInfo() - { - FileName = parameters.ExecutablePath, - Arguments = parameters.GenerateParameters(), - CreateNoWindow = true, - UseShellExecute = false, - RedirectStandardInput = true, - RedirectStandardOutput = true, - }, - }; - childProcess.Start(); - childProcess.WaitForExit(1000); - - // Just in case, we want to push a button 5 times to clear any errors - for (int i = 0; i < 5; i++) - childProcess.StandardInput.WriteLine("Y"); - - string stdout = childProcess.StandardOutput.ReadToEnd(); - childProcess.Dispose(); - return stdout; - }); - - return output; - } - /// /// Cancel an in-progress dumping process /// @@ -262,6 +242,8 @@ namespace MPF.Data { } } + #endregion + #region Parameter Parsing /// diff --git a/MPF.Library/DiscImageCreator/Parameters.cs b/MPF.Library/DiscImageCreator/Parameters.cs index 034f9204..ffdd3ccd 100644 --- a/MPF.Library/DiscImageCreator/Parameters.cs +++ b/MPF.Library/DiscImageCreator/Parameters.cs @@ -15,11 +15,36 @@ namespace MPF.DiscImageCreator /// public class Parameters : BaseParameters { + #region Generic Dumping Information + + /// + public override string InputPath => DriveLetter; + + /// + public override string OutputPath => Filename; + + /// + /// + public override int? Speed + { + get { return DriveSpeed; } + set { DriveSpeed = (sbyte?)value; } + } + + #endregion + + #region Metadata + /// /// Base command to run /// public Command BaseCommand { get; set; } + /// + public override InternalProgram InternalProgram => InternalProgram.DiscImageCreator; + + #endregion + /// /// Set of flags to pass to the executable /// @@ -151,19 +176,585 @@ namespace MPF.DiscImageCreator #endregion /// - public Parameters(string parameters) - : base(parameters) - { - this.InternalProgram = InternalProgram.DiscImageCreator; - } + public Parameters(string parameters) : base(parameters) { } /// public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options) : base(system, type, driveLetter, filename, driveSpeed, options) { - this.InternalProgram = InternalProgram.DiscImageCreator; - if (options.DICQuietMode) - this[Flag.DisableBeep] = true; + } + + #region BaseParameters Implementations + + /// + public override (bool, List) CheckAllOutputFilesExist(string basePath) + { + /* + 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` + - volDesc - Volume descriptor information + */ + + List missingFiles = new List(); + switch (this.Type) + { + case MediaType.CDROM: + case MediaType.GDROM: // TODO: Verify GD-ROM outputs this + if (!File.Exists($"{basePath}.ccd")) + missingFiles.Add($"{basePath}.ccd"); + if (!File.Exists($"{basePath}.cue")) + missingFiles.Add($"{basePath}.cue"); + if (!File.Exists($"{basePath}.dat")) + missingFiles.Add($"{basePath}.dat"); + if (!File.Exists($"{basePath}.img") && !File.Exists($"{basePath}.imgtmp")) + missingFiles.Add($"{basePath}.img"); + 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"); + if (!File.Exists($"{basePath}.scm") && !File.Exists($"{basePath}.scmtmp")) + missingFiles.Add($"{basePath}.scm"); + } + + // Removed or inconsistent files + if (false) + { + // 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"); + } + + break; + + case MediaType.DVD: + case MediaType.HDDVD: + case MediaType.BluRay: + case MediaType.NintendoGameCubeGameDisc: + case MediaType.NintendoWiiOpticalDisc: + 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 + if (false) + { + // Replaced by timestamp-named file + if (!File.Exists($"{basePath}_cmd.txt")) + missingFiles.Add($"{basePath}_cmd.txt"); + } + + break; + + case MediaType.FloppyDisk: + case MediaType.HardDisk: + // TODO: Determine what outputs come out from a HDD, SD, etc. + if (!File.Exists($"{basePath}.dat")) + missingFiles.Add($"{basePath}.dat"); + if (!File.Exists($"{basePath}_disc.txt")) + missingFiles.Add($"{basePath}_disc.txt"); + + // Removed or inconsistent files + if (false) + { + // Replaced by timestamp-named file + if (!File.Exists($"{basePath}_cmd.txt")) + missingFiles.Add($"{basePath}_cmd.txt"); + } + + break; + + default: + return (false, missingFiles); + } + + return (!missingFiles.Any(), missingFiles); + } + + /// + public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, Drive drive) + { + string outputDirectory = Path.GetDirectoryName(basePath); + + // Fill in the hash data + info.TracksAndWriteOffsets.ClrMameProData = GetDatfile(basePath + ".dat"); + + // 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") ?? ""; + var cueSheet = new CueSheet(basePath + ".cue"); // TODO: Do something with this + + string cdWriteOffset = GetWriteOffset(basePath + "_disc.txt") ?? ""; + 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 (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; + } + + // Deal with the layerbreaks + if (this.Type == MediaType.DVD) + { + string layerbreak = GetLayerbreak(basePath + "_disc.txt", System.IsXGD()) ?? ""; + info.SizeAndChecksums.Layerbreak = !string.IsNullOrEmpty(layerbreak) ? Int64.Parse(layerbreak) : default; + } + else if (this.Type == MediaType.BluRay) + { + if (GetLayerbreak(Path.Combine(outputDirectory, "PIC.bin"), 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 + info.Extras.PVD = GetPVD(basePath + "_mainInfo.txt") ?? ""; + + // Bluray-specific options + if (this.Type == MediaType.BluRay) + info.Extras.PIC = GetPIC(Path.Combine(outputDirectory, "PIC.bin")) ?? ""; + + break; + } + + // Extract info based specifically on KnownSystem + switch (this.System) + { + case KnownSystem.AppleMacintosh: + case KnownSystem.EnhancedCD: + case KnownSystem.IBMPCCompatible: + case KnownSystem.RainbowDisc: + if (File.Exists(basePath + "_subIntention.txt")) + { + FileInfo fi = new FileInfo(basePath + "_subIntention.txt"); + if (fi.Length > 0) + info.CopyProtection.SecuROMData = GetFullFile(basePath + "_subIntention.txt") ?? ""; + } + + break; + + case KnownSystem.DVDAudio: + case KnownSystem.DVDVideo: + info.CopyProtection.Protection = GetDVDProtection(basePath + "_CSSKey.txt", basePath + "_disc.txt") ?? ""; + break; + + case KnownSystem.KonamiPython2: + if (GetPlayStationExecutableInfo(drive?.Letter, out string pythonTwoSerial, out RedumpRegion? pythonTwoRegion, out string pythonTwoDate)) + { + info.CommonDiscInfo.Comments += $"Internal Disc Serial: {pythonTwoSerial}\n"; + info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? pythonTwoRegion; + info.CommonDiscInfo.EXEDateBuildDate = pythonTwoDate; + } + + info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? ""; + break; + + case KnownSystem.MicrosoftXBOX: + if (GetXgdAuxInfo(basePath + "_disc.txt", out string dmihash, out string pfihash, out string sshash, out string ss, out string ssver)) + { + info.CommonDiscInfo.Comments += $"{Template.XBOXDMIHash}: {dmihash ?? ""}\n" + + $"{Template.XBOXPFIHash}: {pfihash ?? ""}\n" + + $"{Template.XBOXSSHash}: {sshash ?? ""}\n" + + $"{Template.XBOXSSVersion}: {ssver ?? ""}\n"; + info.Extras.SecuritySectorRanges = ss ?? ""; + } + + if (GetXboxDMIInfo(Path.Combine(outputDirectory, "DMI.bin"), out string serial, out string version, out RedumpRegion? region)) + { + info.CommonDiscInfo.Serial = serial ?? ""; + info.VersionAndEditions.Version = version ?? ""; + info.CommonDiscInfo.Region = region; + } + + break; + + case KnownSystem.MicrosoftXBOX360: + if (GetXgdAuxInfo(basePath + "_disc.txt", out string dmi360hash, out string pfi360hash, out string ss360hash, out string ss360, out string ssver360)) + { + info.CommonDiscInfo.Comments += $"{Template.XBOXDMIHash}: {dmi360hash ?? ""}\n" + + $"{Template.XBOXPFIHash}: {pfi360hash ?? ""}\n" + + $"{Template.XBOXSSHash}: {ss360hash ?? ""}\n" + + $"{Template.XBOXSSVersion}: {ssver360 ?? ""}\n"; + info.Extras.SecuritySectorRanges = ss360 ?? ""; + } + + if (GetXbox360DMIInfo(Path.Combine(outputDirectory, "DMI.bin"), out string serial360, out string version360, out RedumpRegion? region360)) + { + info.CommonDiscInfo.Serial = serial360 ?? ""; + info.VersionAndEditions.Version = version360 ?? ""; + info.CommonDiscInfo.Region = region360; + } + break; + + case KnownSystem.NamcoSegaNintendoTriforce: + if (this.Type == MediaType.CDROM) + { + info.Extras.Header = GetSegaHeader(basePath + "_mainInfo.txt") ?? ""; + + // 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)); + + if (GetGDROMBuildInfo(info.Extras.Header, out string gdSerial, out string gdVersion, out string gdDate)) + { + info.CommonDiscInfo.Comments += $"Internal Serial: {gdSerial ?? ""}"; + info.VersionAndEditions.Version = gdVersion ?? ""; + info.CommonDiscInfo.EXEDateBuildDate = gdDate ?? ""; + } + } + + break; + + case KnownSystem.SegaCDMegaCD: + info.Extras.Header = GetSegaHeader(basePath + "_mainInfo.txt") ?? ""; + + // 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)); + + if (GetSegaCDBuildInfo(info.Extras.Header, out string scdSerial, out string fixedDate)) + { + info.CommonDiscInfo.Comments += $"Internal Serial: {scdSerial ?? ""}"; + info.CommonDiscInfo.EXEDateBuildDate = fixedDate ?? ""; + } + + break; + + case KnownSystem.SegaChihiro: + if (this.Type == MediaType.CDROM) + { + info.Extras.Header = GetSegaHeader(basePath + "_mainInfo.txt") ?? ""; + + // 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)); + + if (GetGDROMBuildInfo(info.Extras.Header, out string gdSerial, out string gdVersion, out string gdDate)) + { + info.CommonDiscInfo.Comments += $"Internal Serial: {gdSerial ?? ""}"; + info.VersionAndEditions.Version = gdVersion ?? ""; + info.CommonDiscInfo.EXEDateBuildDate = gdDate ?? ""; + } + } + + break; + + case KnownSystem.SegaDreamcast: + if (this.Type == MediaType.CDROM) + { + info.Extras.Header = GetSegaHeader(basePath + "_mainInfo.txt") ?? ""; + + // 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)); + + if (GetGDROMBuildInfo(info.Extras.Header, out string gdSerial, out string gdVersion, out string gdDate)) + { + info.CommonDiscInfo.Comments += $"Internal Serial: {gdSerial ?? ""}"; + info.VersionAndEditions.Version = gdVersion ?? ""; + info.CommonDiscInfo.EXEDateBuildDate = gdDate ?? ""; + } + } + + break; + + case KnownSystem.SegaNaomi: + if (this.Type == MediaType.CDROM) + { + info.Extras.Header = GetSegaHeader(basePath + "_mainInfo.txt") ?? ""; + + // 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)); + + if (GetGDROMBuildInfo(info.Extras.Header, out string gdSerial, out string gdVersion, out string gdDate)) + { + info.CommonDiscInfo.Comments += $"Internal Serial: {gdSerial ?? ""}"; + info.VersionAndEditions.Version = gdVersion ?? ""; + info.CommonDiscInfo.EXEDateBuildDate = gdDate ?? ""; + } + } + + break; + + case KnownSystem.SegaNaomi2: + if (this.Type == MediaType.CDROM) + { + info.Extras.Header = GetSegaHeader(basePath + "_mainInfo.txt") ?? ""; + + // 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)); + + if (GetGDROMBuildInfo(info.Extras.Header, out string gdSerial, out string gdVersion, out string gdDate)) + { + info.CommonDiscInfo.Comments += $"Internal Serial: {gdSerial ?? ""}"; + info.VersionAndEditions.Version = gdVersion ?? ""; + info.CommonDiscInfo.EXEDateBuildDate = gdDate ?? ""; + } + } + + break; + + case KnownSystem.SegaSaturn: + info.Extras.Header = GetSegaHeader(basePath + "_mainInfo.txt") ?? ""; + + // 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)); + + if (GetSaturnBuildInfo(info.Extras.Header, out string saturnSerial, out string saturnVersion, out string buildDate)) + { + info.CommonDiscInfo.Comments += $"Internal Serial: {saturnSerial ?? ""}"; + info.VersionAndEditions.Version = saturnVersion ?? ""; + info.CommonDiscInfo.EXEDateBuildDate = buildDate ?? ""; + } + + break; + + case KnownSystem.SonyPlayStation: + if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationSerial, out RedumpRegion? playstationRegion, out string playstationDate)) + { + info.CommonDiscInfo.Comments += $"Internal Serial: {playstationSerial ?? ""}\n"; + 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"); + + if (psEdcStatus == true) + info.EDC.EDC = YesNo.Yes; + else if (psEdcStatus == false) + info.EDC.EDC = YesNo.No; + else + info.EDC.EDC = YesNo.NULL; + + info.CopyProtection.AntiModchip = GetPlayStationAntiModchipDetected(basePath + "_disc.txt") ? YesNo.Yes : YesNo.No; + + bool? psLibCryptStatus = GetLibCryptDetected(basePath + ".sub"); + if (psLibCryptStatus == true) + { + // Guard against false positives + if (File.Exists(basePath + "_subIntention.txt")) + { + string libCryptData = GetFullFile(basePath + "_subIntention.txt") ?? ""; + if (string.IsNullOrEmpty(libCryptData)) + { + info.CopyProtection.LibCrypt = YesNo.No; + } + else + { + info.CopyProtection.LibCrypt = YesNo.Yes; + info.CopyProtection.LibCryptData = libCryptData; + } + } + else + { + info.CopyProtection.LibCrypt = YesNo.No; + } + } + else if (psLibCryptStatus == false) + { + info.CopyProtection.LibCrypt = YesNo.No; + } + else + { + info.CopyProtection.LibCrypt = YesNo.NULL; + info.CopyProtection.LibCryptData = "LibCrypt could not be detected because subchannel file is missing"; + } + + break; + + case KnownSystem.SonyPlayStation2: + if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationTwoSerial, out RedumpRegion? playstationTwoRegion, out string playstationTwoDate)) + { + info.CommonDiscInfo.Comments += $"Internal Disc Serial: {playstationTwoSerial}\n"; + info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationTwoRegion; + info.CommonDiscInfo.EXEDateBuildDate = playstationTwoDate; + } + + info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? ""; + break; + + case KnownSystem.SonyPlayStation4: + info.VersionAndEditions.Version = GetPlayStation4Version(drive?.Letter) ?? ""; + break; + + case KnownSystem.SonyPlayStation5: + info.VersionAndEditions.Version = GetPlayStation5Version(drive?.Letter) ?? ""; + break; + } + + // Fill in any artifacts that exist, Base64-encoded + //if (File.Exists(basePath + ".c2")) + // info.Artifacts["c2"] = Convert.ToBase64String(File.ReadAllBytes(basePath + ".c2")); + if (File.Exists(basePath + "_c2Error.txt")) + info.Artifacts["c2Error"] = GetBase64(GetFullFile(basePath + "_c2Error.txt")); + if (File.Exists(basePath + ".ccd")) + info.Artifacts["ccd"] = GetBase64(GetFullFile(basePath + ".ccd")); + 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")); + if (File.Exists(basePath + ".cue")) + info.Artifacts["cue"] = GetBase64(GetFullFile(basePath + ".cue")); + if (File.Exists(basePath + ".dat")) + info.Artifacts["dat"] = GetBase64(GetFullFile(basePath + ".dat")); + if (File.Exists(basePath + "_disc.txt")) + info.Artifacts["disc"] = GetBase64(GetFullFile(basePath + "_disc.txt")); + //if (File.Exists(Path.Combine(outputDirectory, "DMI.bin"))) + // info.Artifacts["dmi"] = Convert.ToBase64String(File.ReadAllBytes(Path.Combine(outputDirectory, "DMI.bin"))); + if (File.Exists(basePath + "_drive.txt")) + info.Artifacts["drive"] = GetBase64(GetFullFile(basePath + "_drive.txt")); + if (File.Exists(basePath + "_img.cue")) + info.Artifacts["img_cue"] = GetBase64(GetFullFile(basePath + "_img.cue")); + if (File.Exists(basePath + ".img_EdcEcc.txt")) + info.Artifacts["img_EdcEcc"] = GetBase64(GetFullFile(basePath + ".img_EdcEcc.txt")); + if (File.Exists(basePath + ".img_EccEdc.txt")) + info.Artifacts["img_EdcEcc"] = GetBase64(GetFullFile(basePath + ".img_EccEdc.txt")); + if (File.Exists(basePath + "_mainError.txt")) + info.Artifacts["mainError"] = GetBase64(GetFullFile(basePath + "_mainError.txt")); + if (File.Exists(basePath + "_mainInfo.txt")) + info.Artifacts["mainInfo"] = GetBase64(GetFullFile(basePath + "_mainInfo.txt")); + //if (File.Exists(Path.Combine(outputDirectory, "PFI.bin"))) + // info.Artifacts["pfi"] = Convert.ToBase64String(File.ReadAllBytes(Path.Combine(outputDirectory, "PFI.bin"))); + //if (File.Exists(Path.Combine(outputDirectory, "SS.bin"))) + // info.Artifacts["ss"] = Convert.ToBase64String(File.ReadAllBytes(Path.Combine(outputDirectory, "SS.bin"))); + if (File.Exists(basePath + ".sub")) + info.Artifacts["sub"] = Convert.ToBase64String(File.ReadAllBytes(basePath + ".sub")); + if (File.Exists(basePath + "_subError.txt")) + info.Artifacts["subError"] = GetBase64(GetFullFile(basePath + "_subError.txt")); + if (File.Exists(basePath + "_subInfo.txt")) + info.Artifacts["subInfo"] = GetBase64(GetFullFile(basePath + "_subInfo.txt")); + if (File.Exists(basePath + "_subIntention.txt")) + info.Artifacts["subIntention"] = GetBase64(GetFullFile(basePath + "_subIntention.txt")); + //if (File.Exists(basePath + "_sub.txt")) + // info.Artifacts["subReadable"] = GetBase64(GetFullFile(basePath + "_sub.txt")); + //if (File.Exists(basePath + "_subReadable.txt")) + // info.Artifacts["subReadable"] = GetBase64(GetFullFile(basePath + "_subReadable.txt")); + if (File.Exists(basePath + "_volDesc.txt")) + info.Artifacts["volDesc"] = GetBase64(GetFullFile(basePath + "_volDesc.txt")); } /// @@ -623,16 +1214,7 @@ namespace MPF.DiscImageCreator } /// - public override string InputPath() => DriveLetter; - - /// - public override string OutputPath() => Filename; - - /// - public override int? GetSpeed() => DriveSpeed; - - /// - public override void SetSpeed(int? speed) => DriveSpeed = speed; + public override string GetDefaultExtension(MediaType? mediaType) => Converters.Extension(mediaType); /// public override MediaType? GetMediaType() => Converters.ToMediaType(BaseCommand); @@ -704,6 +1286,10 @@ namespace MPF.DiscImageCreator if (!validTypes.Contains(this.Type)) return; + // Set disable beep flag, if needed + if (options.DICQuietMode) + this[Flag.DisableBeep] = true; + // Set the C2 reread count switch (options.DICRereadCount) { @@ -1629,576 +2215,9 @@ namespace MPF.DiscImageCreator return true; } - /// - public override (bool, List) CheckAllOutputFilesExist(string basePath) - { - /* - 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: + #endregion - .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` - - volDesc - Volume descriptor information - */ - - List missingFiles = new List(); - switch (this.Type) - { - case MediaType.CDROM: - case MediaType.GDROM: // TODO: Verify GD-ROM outputs this - if (!File.Exists($"{basePath}.ccd")) - missingFiles.Add($"{basePath}.ccd"); - if (!File.Exists($"{basePath}.cue")) - missingFiles.Add($"{basePath}.cue"); - if (!File.Exists($"{basePath}.dat")) - missingFiles.Add($"{basePath}.dat"); - if (!File.Exists($"{basePath}.img") && !File.Exists($"{basePath}.imgtmp")) - missingFiles.Add($"{basePath}.img"); - 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"); - if (!File.Exists($"{basePath}.scm") && !File.Exists($"{basePath}.scmtmp")) - missingFiles.Add($"{basePath}.scm"); - } - - // Removed or inconsistent files - if (false) - { - // 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"); - } - - break; - - case MediaType.DVD: - case MediaType.HDDVD: - case MediaType.BluRay: - case MediaType.NintendoGameCubeGameDisc: - case MediaType.NintendoWiiOpticalDisc: - 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 - if (false) - { - // Replaced by timestamp-named file - if (!File.Exists($"{basePath}_cmd.txt")) - missingFiles.Add($"{basePath}_cmd.txt"); - } - - break; - - case MediaType.FloppyDisk: - case MediaType.HardDisk: - // TODO: Determine what outputs come out from a HDD, SD, etc. - if (!File.Exists($"{basePath}.dat")) - missingFiles.Add($"{basePath}.dat"); - if (!File.Exists($"{basePath}_disc.txt")) - missingFiles.Add($"{basePath}_disc.txt"); - - // Removed or inconsistent files - if (false) - { - // Replaced by timestamp-named file - if (!File.Exists($"{basePath}_cmd.txt")) - missingFiles.Add($"{basePath}_cmd.txt"); - } - - break; - - default: - return (false, missingFiles); - } - - return (!missingFiles.Any(), missingFiles); - } - - /// - public override void GenerateSubmissionInfo(SubmissionInfo info, string basePath, Drive drive) - { - string outputDirectory = Path.GetDirectoryName(basePath); - - // Fill in the hash data - info.TracksAndWriteOffsets.ClrMameProData = GetDatfile(basePath + ".dat"); - - // 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") ?? ""; - var cueSheet = new CueSheet(basePath + ".cue"); // TODO: Do something with this - - string cdWriteOffset = GetWriteOffset(basePath + "_disc.txt") ?? ""; - 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 (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; - } - - // Deal with the layerbreaks - if (this.Type == MediaType.DVD) - { - string layerbreak = GetLayerbreak(basePath + "_disc.txt", System.IsXGD()) ?? ""; - info.SizeAndChecksums.Layerbreak = !string.IsNullOrEmpty(layerbreak) ? Int64.Parse(layerbreak) : default; - } - else if (this.Type == MediaType.BluRay) - { - if (GetLayerbreak(Path.Combine(outputDirectory, "PIC.bin"), 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 - info.Extras.PVD = GetPVD(basePath + "_mainInfo.txt") ?? ""; - - // Bluray-specific options - if (this.Type == MediaType.BluRay) - info.Extras.PIC = GetPIC(Path.Combine(outputDirectory, "PIC.bin")) ?? ""; - - break; - } - - // Extract info based specifically on KnownSystem - switch (this.System) - { - case KnownSystem.AppleMacintosh: - case KnownSystem.EnhancedCD: - case KnownSystem.IBMPCCompatible: - case KnownSystem.RainbowDisc: - if (File.Exists(basePath + "_subIntention.txt")) - { - FileInfo fi = new FileInfo(basePath + "_subIntention.txt"); - if (fi.Length > 0) - info.CopyProtection.SecuROMData = GetFullFile(basePath + "_subIntention.txt") ?? ""; - } - - break; - - case KnownSystem.DVDAudio: - case KnownSystem.DVDVideo: - info.CopyProtection.Protection = GetDVDProtection(basePath + "_CSSKey.txt", basePath + "_disc.txt") ?? ""; - break; - - case KnownSystem.KonamiPython2: - if (GetPlayStationExecutableInfo(drive?.Letter, out string pythonTwoSerial, out RedumpRegion? pythonTwoRegion, out string pythonTwoDate)) - { - info.CommonDiscInfo.Comments += $"Internal Disc Serial: {pythonTwoSerial}\n"; - info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? pythonTwoRegion; - info.CommonDiscInfo.EXEDateBuildDate = pythonTwoDate; - } - - info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? ""; - break; - - case KnownSystem.MicrosoftXBOX: - if (GetXgdAuxInfo(basePath + "_disc.txt", out string dmihash, out string pfihash, out string sshash, out string ss, out string ssver)) - { - info.CommonDiscInfo.Comments += $"{Template.XBOXDMIHash}: {dmihash ?? ""}\n" + - $"{Template.XBOXPFIHash}: {pfihash ?? ""}\n" + - $"{Template.XBOXSSHash}: {sshash ?? ""}\n" + - $"{Template.XBOXSSVersion}: {ssver ?? ""}\n"; - info.Extras.SecuritySectorRanges = ss ?? ""; - } - - if (GetXboxDMIInfo(Path.Combine(outputDirectory, "DMI.bin"), out string serial, out string version, out RedumpRegion? region)) - { - info.CommonDiscInfo.Serial = serial ?? ""; - info.VersionAndEditions.Version = version ?? ""; - info.CommonDiscInfo.Region = region; - } - - break; - - case KnownSystem.MicrosoftXBOX360: - if (GetXgdAuxInfo(basePath + "_disc.txt", out string dmi360hash, out string pfi360hash, out string ss360hash, out string ss360, out string ssver360)) - { - info.CommonDiscInfo.Comments += $"{Template.XBOXDMIHash}: {dmi360hash ?? ""}\n" + - $"{Template.XBOXPFIHash}: {pfi360hash ?? ""}\n" + - $"{Template.XBOXSSHash}: {ss360hash ?? ""}\n" + - $"{Template.XBOXSSVersion}: {ssver360 ?? ""}\n"; - info.Extras.SecuritySectorRanges = ss360 ?? ""; - } - - if (GetXbox360DMIInfo(Path.Combine(outputDirectory, "DMI.bin"), out string serial360, out string version360, out RedumpRegion? region360)) - { - info.CommonDiscInfo.Serial = serial360 ?? ""; - info.VersionAndEditions.Version = version360 ?? ""; - info.CommonDiscInfo.Region = region360; - } - break; - - case KnownSystem.NamcoSegaNintendoTriforce: - if (this.Type == MediaType.CDROM) - { - info.Extras.Header = GetSegaHeader(basePath + "_mainInfo.txt") ?? ""; - - // 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)); - - if (GetGDROMBuildInfo(info.Extras.Header, out string gdSerial, out string gdVersion, out string gdDate)) - { - info.CommonDiscInfo.Comments += $"Internal Serial: {gdSerial ?? ""}"; - info.VersionAndEditions.Version = gdVersion ?? ""; - info.CommonDiscInfo.EXEDateBuildDate = gdDate ?? ""; - } - } - - break; - - case KnownSystem.SegaCDMegaCD: - info.Extras.Header = GetSegaHeader(basePath + "_mainInfo.txt") ?? ""; - - // 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)); - - if (GetSegaCDBuildInfo(info.Extras.Header, out string scdSerial, out string fixedDate)) - { - info.CommonDiscInfo.Comments += $"Internal Serial: {scdSerial ?? ""}"; - info.CommonDiscInfo.EXEDateBuildDate = fixedDate ?? ""; - } - - break; - - case KnownSystem.SegaChihiro: - if (this.Type == MediaType.CDROM) - { - info.Extras.Header = GetSegaHeader(basePath + "_mainInfo.txt") ?? ""; - - // 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)); - - if (GetGDROMBuildInfo(info.Extras.Header, out string gdSerial, out string gdVersion, out string gdDate)) - { - info.CommonDiscInfo.Comments += $"Internal Serial: {gdSerial ?? ""}"; - info.VersionAndEditions.Version = gdVersion ?? ""; - info.CommonDiscInfo.EXEDateBuildDate = gdDate ?? ""; - } - } - - break; - - case KnownSystem.SegaDreamcast: - if (this.Type == MediaType.CDROM) - { - info.Extras.Header = GetSegaHeader(basePath + "_mainInfo.txt") ?? ""; - - // 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)); - - if (GetGDROMBuildInfo(info.Extras.Header, out string gdSerial, out string gdVersion, out string gdDate)) - { - info.CommonDiscInfo.Comments += $"Internal Serial: {gdSerial ?? ""}"; - info.VersionAndEditions.Version = gdVersion ?? ""; - info.CommonDiscInfo.EXEDateBuildDate = gdDate ?? ""; - } - } - - break; - - case KnownSystem.SegaNaomi: - if (this.Type == MediaType.CDROM) - { - info.Extras.Header = GetSegaHeader(basePath + "_mainInfo.txt") ?? ""; - - // 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)); - - if (GetGDROMBuildInfo(info.Extras.Header, out string gdSerial, out string gdVersion, out string gdDate)) - { - info.CommonDiscInfo.Comments += $"Internal Serial: {gdSerial ?? ""}"; - info.VersionAndEditions.Version = gdVersion ?? ""; - info.CommonDiscInfo.EXEDateBuildDate = gdDate ?? ""; - } - } - - break; - - case KnownSystem.SegaNaomi2: - if (this.Type == MediaType.CDROM) - { - info.Extras.Header = GetSegaHeader(basePath + "_mainInfo.txt") ?? ""; - - // 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)); - - if (GetGDROMBuildInfo(info.Extras.Header, out string gdSerial, out string gdVersion, out string gdDate)) - { - info.CommonDiscInfo.Comments += $"Internal Serial: {gdSerial ?? ""}"; - info.VersionAndEditions.Version = gdVersion ?? ""; - info.CommonDiscInfo.EXEDateBuildDate = gdDate ?? ""; - } - } - - break; - - case KnownSystem.SegaSaturn: - info.Extras.Header = GetSegaHeader(basePath + "_mainInfo.txt") ?? ""; - - // 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)); - - if (GetSaturnBuildInfo(info.Extras.Header, out string saturnSerial, out string saturnVersion, out string buildDate)) - { - info.CommonDiscInfo.Comments += $"Internal Serial: {saturnSerial ?? ""}"; - info.VersionAndEditions.Version = saturnVersion ?? ""; - info.CommonDiscInfo.EXEDateBuildDate = buildDate ?? ""; - } - - break; - - case KnownSystem.SonyPlayStation: - if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationSerial, out RedumpRegion? playstationRegion, out string playstationDate)) - { - info.CommonDiscInfo.Comments += $"Internal Serial: {playstationSerial ?? ""}\n"; - 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"); - - if (psEdcStatus == true) - info.EDC.EDC = YesNo.Yes; - else if (psEdcStatus == false) - info.EDC.EDC = YesNo.No; - else - info.EDC.EDC = YesNo.NULL; - - info.CopyProtection.AntiModchip = GetPlayStationAntiModchipDetected(basePath + "_disc.txt") ? YesNo.Yes : YesNo.No; - - bool? psLibCryptStatus = GetLibCryptDetected(basePath + ".sub"); - if (psLibCryptStatus == true) - { - // Guard against false positives - if (File.Exists(basePath + "_subIntention.txt")) - { - string libCryptData = GetFullFile(basePath + "_subIntention.txt") ?? ""; - if (string.IsNullOrEmpty(libCryptData)) - { - info.CopyProtection.LibCrypt = YesNo.No; - } - else - { - info.CopyProtection.LibCrypt = YesNo.Yes; - info.CopyProtection.LibCryptData = libCryptData; - } - } - else - { - info.CopyProtection.LibCrypt = YesNo.No; - } - } - else if (psLibCryptStatus == false) - { - info.CopyProtection.LibCrypt = YesNo.No; - } - else - { - info.CopyProtection.LibCrypt = YesNo.NULL; - info.CopyProtection.LibCryptData = "LibCrypt could not be detected because subchannel file is missing"; - } - - break; - - case KnownSystem.SonyPlayStation2: - if (GetPlayStationExecutableInfo(drive?.Letter, out string playstationTwoSerial, out RedumpRegion? playstationTwoRegion, out string playstationTwoDate)) - { - info.CommonDiscInfo.Comments += $"Internal Disc Serial: {playstationTwoSerial}\n"; - info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationTwoRegion; - info.CommonDiscInfo.EXEDateBuildDate = playstationTwoDate; - } - - info.VersionAndEditions.Version = GetPlayStation2Version(drive?.Letter) ?? ""; - break; - - case KnownSystem.SonyPlayStation4: - info.VersionAndEditions.Version = GetPlayStation4Version(drive?.Letter) ?? ""; - break; - - case KnownSystem.SonyPlayStation5: - info.VersionAndEditions.Version = GetPlayStation5Version(drive?.Letter) ?? ""; - break; - } - - // Fill in any artifacts that exist, Base64-encoded - //if (File.Exists(basePath + ".c2")) - // info.Artifacts["c2"] = Convert.ToBase64String(File.ReadAllBytes(basePath + ".c2")); - if (File.Exists(basePath + "_c2Error.txt")) - info.Artifacts["c2Error"] = GetBase64(GetFullFile(basePath + "_c2Error.txt")); - if (File.Exists(basePath + ".ccd")) - info.Artifacts["ccd"] = GetBase64(GetFullFile(basePath + ".ccd")); - 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")); - if (File.Exists(basePath + ".cue")) - info.Artifacts["cue"] = GetBase64(GetFullFile(basePath + ".cue")); - if (File.Exists(basePath + ".dat")) - info.Artifacts["dat"] = GetBase64(GetFullFile(basePath + ".dat")); - if (File.Exists(basePath + "_disc.txt")) - info.Artifacts["disc"] = GetBase64(GetFullFile(basePath + "_disc.txt")); - //if (File.Exists(Path.Combine(outputDirectory, "DMI.bin"))) - // info.Artifacts["dmi"] = Convert.ToBase64String(File.ReadAllBytes(Path.Combine(outputDirectory, "DMI.bin"))); - if (File.Exists(basePath + "_drive.txt")) - info.Artifacts["drive"] = GetBase64(GetFullFile(basePath + "_drive.txt")); - if (File.Exists(basePath + "_img.cue")) - info.Artifacts["img_cue"] = GetBase64(GetFullFile(basePath + "_img.cue")); - if (File.Exists(basePath + ".img_EdcEcc.txt")) - info.Artifacts["img_EdcEcc"] = GetBase64(GetFullFile(basePath + ".img_EdcEcc.txt")); - if (File.Exists(basePath + ".img_EccEdc.txt")) - info.Artifacts["img_EdcEcc"] = GetBase64(GetFullFile(basePath + ".img_EccEdc.txt")); - if (File.Exists(basePath + "_mainError.txt")) - info.Artifacts["mainError"] = GetBase64(GetFullFile(basePath + "_mainError.txt")); - if (File.Exists(basePath + "_mainInfo.txt")) - info.Artifacts["mainInfo"] = GetBase64(GetFullFile(basePath + "_mainInfo.txt")); - //if (File.Exists(Path.Combine(outputDirectory, "PFI.bin"))) - // info.Artifacts["pfi"] = Convert.ToBase64String(File.ReadAllBytes(Path.Combine(outputDirectory, "PFI.bin"))); - //if (File.Exists(Path.Combine(outputDirectory, "SS.bin"))) - // info.Artifacts["ss"] = Convert.ToBase64String(File.ReadAllBytes(Path.Combine(outputDirectory, "SS.bin"))); - if (File.Exists(basePath + ".sub")) - info.Artifacts["sub"] = Convert.ToBase64String(File.ReadAllBytes(basePath + ".sub")); - if (File.Exists(basePath + "_subError.txt")) - info.Artifacts["subError"] = GetBase64(GetFullFile(basePath + "_subError.txt")); - if (File.Exists(basePath + "_subInfo.txt")) - info.Artifacts["subInfo"] = GetBase64(GetFullFile(basePath + "_subInfo.txt")); - if (File.Exists(basePath + "_subIntention.txt")) - info.Artifacts["subIntention"] = GetBase64(GetFullFile(basePath + "_subIntention.txt")); - //if (File.Exists(basePath + "_sub.txt")) - // info.Artifacts["subReadable"] = GetBase64(GetFullFile(basePath + "_sub.txt")); - //if (File.Exists(basePath + "_subReadable.txt")) - // info.Artifacts["subReadable"] = GetBase64(GetFullFile(basePath + "_subReadable.txt")); - if (File.Exists(basePath + "_volDesc.txt")) - info.Artifacts["volDesc"] = GetBase64(GetFullFile(basePath + "_volDesc.txt")); - } + #region Private Extra Methods /// /// Get the list of commands that use a given flag @@ -2455,6 +2474,8 @@ namespace MPF.DiscImageCreator } } + #endregion + #region Information Extraction Methods /// diff --git a/MPF.Library/UmdImageCreator/Parameters.cs b/MPF.Library/UmdImageCreator/Parameters.cs index fba33394..bfc15154 100644 --- a/MPF.Library/UmdImageCreator/Parameters.cs +++ b/MPF.Library/UmdImageCreator/Parameters.cs @@ -12,20 +12,24 @@ namespace MPF.UmdImageCreator /// public class Parameters : BaseParameters { + #region Metadata + /// - public Parameters(string parameters) - : base(parameters) - { - this.InternalProgram = InternalProgram.UmdImageCreator; - } + public override InternalProgram InternalProgram => InternalProgram.UmdImageCreator; + + #endregion + + /// + public Parameters(string parameters) : base(parameters) { } /// public Parameters(KnownSystem? system, MediaType? type, char driveLetter, string filename, int? driveSpeed, Options options) : base(system, type, driveLetter, filename, driveSpeed, options) { - this.InternalProgram = InternalProgram.UmdImageCreator; } + #region BaseParameters Implementations + /// public override (bool, List) CheckAllOutputFilesExist(string basePath) { @@ -93,6 +97,8 @@ namespace MPF.UmdImageCreator info.Artifacts["volDesc"] = GetBase64(GetFullFile(basePath + "_volDesc.txt")); } + #endregion + #region Information Extraction Methods /// diff --git a/MPF.Library/Utilities/DumpEnvironment.cs b/MPF.Library/Utilities/DumpEnvironment.cs index dad3bf1a..49e85949 100644 --- a/MPF.Library/Utilities/DumpEnvironment.cs +++ b/MPF.Library/Utilities/DumpEnvironment.cs @@ -24,12 +24,12 @@ namespace MPF.Utilities /// /// Base output directory to write files to /// - public string OutputDirectory { get; set; } + public string OutputDirectory { get; private set; } /// - /// Base output filename for DiscImageCreator + /// Base output filename for output /// - public string OutputFilename { get; set; } + public string OutputFilename { get; private set; } #endregion @@ -38,27 +38,27 @@ namespace MPF.Utilities /// /// Drive object representing the current drive /// - public Drive Drive { get; set; } + public Drive Drive { get; private set; } /// /// Currently selected system /// - public KnownSystem? System { get; set; } + public KnownSystem? System { get; private set; } /// /// Currently selected media type /// - public MediaType? Type { get; set; } + public MediaType? Type { get; private set; } /// /// Options object representing user-defined options /// - public Options Options { get; set; } + public Options Options { get; private set; } /// /// Parameters object representing what to send to the internal program /// - public BaseParameters Parameters { get; set; } + public BaseParameters Parameters { get; private set; } #endregion @@ -102,17 +102,15 @@ namespace MPF.Utilities this.Options = options; // Output paths - this.OutputDirectory = outputDirectory; - this.OutputFilename = outputFilename; + (this.OutputDirectory, this.OutputFilename) = NormalizeOutputPaths(outputDirectory, outputFilename); // UI information this.Drive = drive; - this.System = system; - this.Type = type; - + this.System = system ?? options.DefaultSystem; + this.Type = type ?? MediaType.NONE; + + // Dumping program SetParameters(parameters); - this.Parameters.System = system; - this.Parameters.Type = type; } #region Public Functionality @@ -163,6 +161,10 @@ namespace MPF.Utilities this.Parameters.ExecutablePath = Options.DiscImageCreatorPath; break; } + + // Set system and type + this.Parameters.System = this.System; + this.Parameters.Type = this.Type; } /// @@ -202,64 +204,6 @@ namespace MPF.Utilities await ExecuteInternalProgram(parameters); } - /// - /// Fix output paths to strip out any invalid characters - /// - public void FixOutputPaths() - { - try - { - // Cache if we had a directory separator or not - bool endedWithDirectorySeparator = OutputDirectory.EndsWith(Path.DirectorySeparatorChar.ToString()) - || OutputDirectory.EndsWith(Path.AltDirectorySeparatorChar.ToString()); - bool endedWithSpace = OutputDirectory.EndsWith(" "); - - // Combine the path to make things separate easier - string combinedPath = Path.Combine(OutputDirectory, OutputFilename); - - // If we have have a blank path, just return - if (string.IsNullOrWhiteSpace(combinedPath)) - return; - - // Now get the normalized paths - OutputDirectory = Path.GetDirectoryName(combinedPath); - OutputFilename = Path.GetFileName(combinedPath); - - // Take care of extra path characters - OutputDirectory = new StringBuilder(OutputDirectory) - .Replace(':', '_', 0, OutputDirectory.LastIndexOf(':') == -1 ? 0 : OutputDirectory.LastIndexOf(':')).ToString(); - - // Sanitize everything else - foreach (char c in Path.GetInvalidPathChars()) - OutputDirectory = OutputDirectory.Replace(c, '_'); - foreach (char c in Path.GetInvalidFileNameChars()) - OutputFilename = OutputFilename.Replace(c, '_'); - - // If we had a space at the end before, add it again - if (endedWithSpace) - OutputDirectory += " "; - - // If we had a directory separator at the end before, add it again - if (endedWithDirectorySeparator) - OutputDirectory += Path.DirectorySeparatorChar; - - // If we have a root directory, sanitize - if (Directory.Exists(OutputDirectory)) - { - var possibleRootDir = new DirectoryInfo(OutputDirectory); - if (possibleRootDir.Parent == null) - { - OutputDirectory = OutputDirectory.Replace($"{Path.DirectorySeparatorChar}{Path.DirectorySeparatorChar}", $"{Path.DirectorySeparatorChar}"); - } - } - } - catch - { - // We don't care what the error was - return; - } - } - /// /// Ensures that all required output files have been created /// @@ -277,30 +221,6 @@ namespace MPF.Utilities return Parameters.CheckAllOutputFilesExist(basePath); } - /// - /// Get the extension for a given media type and internal program - /// - /// - /// - public string GetExtension(MediaType? mediaType) - { - switch (Options.InternalProgram) - { - case InternalProgram.Aaru: - return Aaru.Converters.Extension(mediaType); - - case InternalProgram.DD: - return DD.Converters.Extension(mediaType); - - case InternalProgram.DiscImageCreator: - return DiscImageCreator.Converters.Extension(mediaType); - - // This should never happen, but it needs a fallback - default: - return DiscImageCreator.Converters.Extension(mediaType); - } - } - /// /// Get the full parameter string for either DiscImageCreator or Aaru /// @@ -344,6 +264,62 @@ namespace MPF.Utilities return null; } + /// + /// Normalize a split set of paths + /// + /// Directory name to normalize + /// Filename to normalize + public static (string, string) NormalizeOutputPaths(string directory, string filename) + { + try + { + // Cache if we had a directory separator or not + bool endedWithDirectorySeparator = directory.EndsWith(Path.DirectorySeparatorChar.ToString()) + || directory.EndsWith(Path.AltDirectorySeparatorChar.ToString()); + bool endedWithSpace = directory.EndsWith(" "); + + // Combine the path to make things separate easier + string combinedPath = Path.Combine(directory, filename); + + // If we have have a blank path, just return + if (string.IsNullOrWhiteSpace(combinedPath)) + return (directory, filename); + + // Now get the normalized paths + directory = Path.GetDirectoryName(combinedPath); + filename = Path.GetFileName(combinedPath); + + // Take care of extra path characters + directory = new StringBuilder(directory) + .Replace(':', '_', 0, directory.LastIndexOf(':') == -1 ? 0 : directory.LastIndexOf(':')).ToString(); + + // Sanitize everything else + foreach (char c in Path.GetInvalidPathChars()) + directory = directory.Replace(c, '_'); + foreach (char c in Path.GetInvalidFileNameChars()) + filename = filename.Replace(c, '_'); + + // If we had a space at the end before, add it again + if (endedWithSpace) + directory += " "; + + // If we had a directory separator at the end before, add it again + if (endedWithDirectorySeparator) + directory += Path.DirectorySeparatorChar; + + // If we have a root directory, sanitize + if (Directory.Exists(directory)) + { + var possibleRootDir = new DirectoryInfo(directory); + if (possibleRootDir.Parent == null) + directory = directory.Replace($"{Path.DirectorySeparatorChar}{Path.DirectorySeparatorChar}", $"{Path.DirectorySeparatorChar}"); + } + } + catch { } + + return (directory, filename); + } + /// /// Reset the current drive using DiscImageCreator /// @@ -1266,13 +1242,21 @@ namespace MPF.Utilities return Result.Failure("Error! Current configuration is not supported!"); // Fix the output paths, just in case - FixOutputPaths(); + (OutputDirectory, OutputFilename) = NormalizeOutputPaths(OutputDirectory, OutputFilename); + + // Validate that the output path isn't on the dumping drive + string fullOutputPath = Path.GetFullPath(Path.Combine(OutputDirectory, OutputFilename)); + if (fullOutputPath[0] == Drive.Letter) + return Result.Failure($"Error! Cannot output to same drive that is being dumped!"); // Validate that the required program exists if (!File.Exists(Parameters.ExecutablePath)) return Result.Failure($"Error! {Parameters.ExecutablePath} does not exist!"); - // TODO: Ensure output path not the same as input drive OR executable location + // Validate that the dumping drive doesn't contain the executable + string fullExecutablePath = Path.GetFullPath(Parameters.ExecutablePath); + if (fullExecutablePath[0] == Drive.Letter) + return Result.Failure("$Error! Cannot dump same drive that executable resides on!"); // Validate that the current configuration is supported return Validators.GetSupportStatus(System, Type); diff --git a/MPF.Test/Utilities/DumpEnvironmentTest.cs b/MPF.Test/Utilities/DumpEnvironmentTest.cs index 5c2e54b3..b1a59b70 100644 --- a/MPF.Test/Utilities/DumpEnvironmentTest.cs +++ b/MPF.Test/Utilities/DumpEnvironmentTest.cs @@ -38,12 +38,9 @@ namespace MPF.Test [InlineData("superhero", "blah&foo.bin", "superhero", "blah&foo.bin")] public void FixOutputPathsTest(string outputDirectory, string outputFilename, string expectedOutputDirectory, string expectedOutputFilename) { - var options = new Options() { InternalProgram = InternalProgram.DiscImageCreator }; - var env = new DumpEnvironment(options, outputDirectory, outputFilename, null, KnownSystem.IBMPCCompatible, MediaType.CDROM, string.Empty); - - env.FixOutputPaths(); - Assert.Equal(expectedOutputDirectory, env.OutputDirectory); - Assert.Equal(expectedOutputFilename, env.OutputFilename); + (string actualOutputDirectory, string actualOutputFilename) = DumpEnvironment.NormalizeOutputPaths(outputDirectory, outputFilename); + Assert.Equal(expectedOutputDirectory, actualOutputDirectory); + Assert.Equal(expectedOutputFilename, actualOutputFilename); } [Fact] diff --git a/MPF/Windows/MainWindow.xaml.cs b/MPF/Windows/MainWindow.xaml.cs index 7150062f..06c6d818 100644 --- a/MPF/Windows/MainWindow.xaml.cs +++ b/MPF/Windows/MainWindow.xaml.cs @@ -389,12 +389,6 @@ namespace MPF.Windows // Get the current environment information Env = DetermineEnvironment(); - // Take care of null cases - if (Env.System == null) - Env.System = UIOptions.Options.DefaultSystem; - if (Env.Type == null) - Env.Type = MediaType.NONE; - // Get the status to write out Result result = Validators.GetSupportStatus(Env.System, Env.Type); StatusLabel.Content = result.Message; @@ -431,7 +425,7 @@ namespace MPF.Windows OutputDirectoryTextBox.Text = Path.Combine(UIOptions.Options.DefaultOutputPath, drive?.VolumeLabel ?? string.Empty); // Get the extension for the file for the next two statements - string extension = Env.GetExtension(mediaType); + string extension = Env.Parameters?.GetDefaultExtension(mediaType); // Set the output filename, if we changed drives or it's not already if (driveChanged || string.IsNullOrEmpty(OutputFilenameTextBox.Text)) @@ -451,19 +445,20 @@ namespace MPF.Windows if (Env.Parameters == null) return; - int driveIndex = Drives.Select(d => d.Letter).ToList().IndexOf(Env.Parameters.InputPath()[0]); + int driveIndex = Drives.Select(d => d.Letter).ToList().IndexOf(Env.Parameters.InputPath[0]); if (driveIndex > -1) DriveLetterComboBox.SelectedIndex = driveIndex; - int driveSpeed = Env.Parameters.GetSpeed() ?? -1; + int driveSpeed = Env.Parameters.Speed ?? -1; if (driveSpeed > 0) DriveSpeedComboBox.SelectedValue = driveSpeed; else - Env.Parameters.SetSpeed((int?)DriveSpeedComboBox.SelectedValue); + Env.Parameters.Speed = DriveSpeedComboBox.SelectedValue as int?; - string trimmedPath = Env.Parameters.OutputPath()?.Trim('"') ?? string.Empty; + string trimmedPath = Env.Parameters.OutputPath?.Trim('"') ?? string.Empty; string outputDirectory = Path.GetDirectoryName(trimmedPath); string outputFilename = Path.GetFileName(trimmedPath); + (outputDirectory, outputFilename) = DumpEnvironment.NormalizeOutputPaths(outputDirectory, outputFilename); if (!string.IsNullOrWhiteSpace(outputDirectory)) OutputDirectoryTextBox.Text = outputDirectory; else @@ -592,9 +587,6 @@ namespace MPF.Windows // If "No", then we continue with the current known environment } - // Fix the output paths - Env.FixOutputPaths(); - try { // Validate that the user explicitly wants an inactive drive to be considered for dumping