mirror of
https://github.com/SabreTools/MPF.git
synced 2026-02-04 05:35:52 +00:00
1084 lines
54 KiB
C#
1084 lines
54 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
#if NET35_OR_GREATER || NETCOREAPP
|
|
using System.Linq;
|
|
#endif
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using BinaryObjectScanner;
|
|
using MPF.Processors;
|
|
using SabreTools.RedumpLib;
|
|
using SabreTools.RedumpLib.Data;
|
|
using SabreTools.RedumpLib.Web;
|
|
|
|
namespace MPF.Frontend.Tools
|
|
{
|
|
/// <summary>
|
|
/// Generator for SubmissionInfo objects
|
|
/// </summary>
|
|
internal static class SubmissionGenerator
|
|
{
|
|
#region Constants
|
|
|
|
private const string RequiredValue = "(REQUIRED)";
|
|
private const string RequiredIfExistsValue = "(REQUIRED, IF EXISTS)";
|
|
private const string OptionalValue = "(OPTIONAL)";
|
|
|
|
#endregion
|
|
|
|
#region Extraction and Filling
|
|
|
|
/// <summary>
|
|
/// Extract all of the possible information from a given input combination
|
|
/// </summary>
|
|
/// <param name="outputPath">Output path to write to</param>
|
|
/// <param name="drive">Drive object representing the current drive</param>
|
|
/// <param name="system">Currently selected system</param>
|
|
/// <param name="mediaType">Currently selected media type</param>
|
|
/// <param name="options">Options object representing user-defined options</param>
|
|
/// <param name="processor">Processor object representing how to process the outputs</param>
|
|
/// <param name="resultProgress">Optional result progress callback</param>
|
|
/// <param name="protectionProgress">Optional protection progress callback</param>
|
|
/// <returns>SubmissionInfo populated based on outputs, null on error</returns>
|
|
public static async Task<SubmissionInfo?> ExtractOutputInformation(
|
|
string outputPath,
|
|
Drive? drive,
|
|
RedumpSystem? system,
|
|
MediaType? mediaType,
|
|
Options options,
|
|
BaseProcessor processor,
|
|
IProgress<ResultEventArgs>? resultProgress = null,
|
|
IProgress<ProtectionProgress>? protectionProgress = null)
|
|
{
|
|
// Split the output path for easier use
|
|
var outputDirectory = Path.GetDirectoryName(outputPath);
|
|
string outputFilename = Path.GetFileName(outputPath);
|
|
|
|
// Check that all of the relevant files are there
|
|
List<string> missingFiles = processor.FoundAllFiles(mediaType, outputDirectory, outputFilename);
|
|
if (missingFiles.Count > 0)
|
|
{
|
|
resultProgress?.Report(ResultEventArgs.Failure($"There were files missing from the output:\n{string.Join("\n", [.. missingFiles])}"));
|
|
resultProgress?.Report(ResultEventArgs.Failure($"This may indicate an issue with the hardware or media, including unsupported devices.\nPlease see dumping program documentation for more details."));
|
|
return null;
|
|
}
|
|
|
|
// Assemble a base path
|
|
string basePath = Path.GetFileNameWithoutExtension(outputFilename);
|
|
if (!string.IsNullOrEmpty(outputDirectory))
|
|
basePath = Path.Combine(outputDirectory, basePath);
|
|
|
|
// Create the default submission info
|
|
SubmissionInfo info = CreateDefaultSubmissionInfo(processor, system, mediaType, options.AddPlaceholders);
|
|
|
|
// Get specific tool output handling
|
|
processor.GenerateSubmissionInfo(info, mediaType, basePath, options.EnableRedumpCompatibility);
|
|
if (options.IncludeArtifacts)
|
|
info.Artifacts = processor.GenerateArtifacts(mediaType, outputDirectory, outputFilename);
|
|
|
|
// Add a placeholder for the logs link
|
|
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.LogsLink] = "[Please provide a link to your logs here]";
|
|
|
|
// Get a list of matching IDs for each line in the DAT
|
|
if (!string.IsNullOrEmpty(info.TracksAndWriteOffsets!.ClrMameProData))
|
|
_ = await FillFromRedump(options, info, resultProgress);
|
|
|
|
// If we have both ClrMamePro and Size and Checksums data, remove the ClrMamePro
|
|
if (!string.IsNullOrEmpty(info.SizeAndChecksums?.CRC32))
|
|
info.TracksAndWriteOffsets.ClrMameProData = null;
|
|
|
|
// Add the volume label to comments, if possible or necessary
|
|
string? volLabels = FormatVolumeLabels(drive?.VolumeLabel, processor.VolumeLabels);
|
|
if (volLabels != null)
|
|
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.VolumeLabel] = volLabels;
|
|
|
|
// Extract info based generically on MediaType
|
|
ProcessMediaType(info, mediaType, options.AddPlaceholders);
|
|
|
|
// Extract info based specifically on RedumpSystem
|
|
ProcessSystem(info, system, drive, options.AddPlaceholders, processor is DiscImageCreator, basePath);
|
|
|
|
// Run anti-modchip check, if necessary
|
|
if (drive != null && system.SupportsAntiModchipScans() && info.CopyProtection!.AntiModchip == YesNo.NULL)
|
|
{
|
|
resultProgress?.Report(ResultEventArgs.Success("Checking for anti-modchip strings... this might take a while!"));
|
|
info.CopyProtection.AntiModchip = await ProtectionTool.GetPlayStationAntiModchipDetected(drive?.Name) ? YesNo.Yes : YesNo.No;
|
|
resultProgress?.Report(ResultEventArgs.Success("Anti-modchip string scan complete!"));
|
|
}
|
|
|
|
// Run copy protection, if possible or necessary
|
|
if (system.SupportsCopyProtectionScans())
|
|
{
|
|
resultProgress?.Report(ResultEventArgs.Success("Running copy protection scan... this might take a while!"));
|
|
|
|
Dictionary<string, List<string>>? protections = null;
|
|
try
|
|
{
|
|
if (options.ScanForProtection && drive?.Name != null)
|
|
protections = await ProtectionTool.RunProtectionScanOnPath(drive.Name, options, protectionProgress);
|
|
|
|
var protectionString = ProtectionTool.FormatProtections(protections);
|
|
|
|
info.CopyProtection!.Protection += protectionString;
|
|
info.CopyProtection.FullProtections = ReformatProtectionDictionary(protections);
|
|
resultProgress?.Report(ResultEventArgs.Success("Copy protection scan complete!"));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
resultProgress?.Report(ResultEventArgs.Failure(ex.ToString()));
|
|
}
|
|
}
|
|
|
|
// Set fields that may have automatic filling otherwise
|
|
info.CommonDiscInfo!.Category ??= DiscCategory.Games;
|
|
info.VersionAndEditions!.Version ??= options.AddPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
|
|
// Comments and contents have odd handling
|
|
if (string.IsNullOrEmpty(info.CommonDiscInfo.Comments))
|
|
info.CommonDiscInfo.Comments = options.AddPlaceholders ? OptionalValue : string.Empty;
|
|
if (string.IsNullOrEmpty(info.CommonDiscInfo.Contents))
|
|
info.CommonDiscInfo.Contents = options.AddPlaceholders ? OptionalValue : string.Empty;
|
|
|
|
// Normalize the disc type with all current information
|
|
Validator.NormalizeDiscType(info);
|
|
|
|
return info;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fill in a SubmissionInfo object from Redump, if possible
|
|
/// </summary>
|
|
/// <param name="options">Options object representing user-defined options</param>
|
|
/// <param name="info">Existing SubmissionInfo object to fill</param>
|
|
/// <param name="resultProgress">Optional result progress callback</param>
|
|
public async static Task<bool> FillFromRedump(Options options,
|
|
SubmissionInfo info,
|
|
IProgress<ResultEventArgs>? resultProgress = null)
|
|
{
|
|
// If information should not be pulled at all
|
|
if (!options.RetrieveMatchInformation)
|
|
return false;
|
|
|
|
// Set the current dumper based on username
|
|
info.DumpersAndStatus ??= new DumpersAndStatusSection();
|
|
info.DumpersAndStatus.Dumpers = [options.RedumpUsername ?? "Anonymous User"];
|
|
info.PartiallyMatchedIDs = [];
|
|
|
|
// Login to Redump, if possible
|
|
var wc = new RedumpClient();
|
|
if (!string.IsNullOrEmpty(options.RedumpUsername) && !string.IsNullOrEmpty(options.RedumpPassword))
|
|
{
|
|
bool? loggedIn = await wc.Login(options.RedumpUsername!, options.RedumpPassword!);
|
|
if (loggedIn == null)
|
|
{
|
|
resultProgress?.Report(ResultEventArgs.Failure("There was an unknown error connecting to Redump, skipping..."));
|
|
return false;
|
|
}
|
|
else if (loggedIn == false)
|
|
{
|
|
resultProgress?.Report(ResultEventArgs.Failure("Provided Redump credentials were invalid, not using..."));
|
|
}
|
|
}
|
|
|
|
// Setup the checks
|
|
bool allFound = true;
|
|
List<int[]> foundIdSets = [];
|
|
|
|
// Loop through all of the hashdata to find matching IDs
|
|
resultProgress?.Report(ResultEventArgs.Success("Finding disc matches on Redump..."));
|
|
var splitData = info.TracksAndWriteOffsets?.ClrMameProData?.TrimEnd('\n')?.Split('\n');
|
|
int trackCount = splitData?.Length ?? 0;
|
|
foreach (string hashData in splitData ?? [])
|
|
{
|
|
// Catch any errant blank lines
|
|
if (string.IsNullOrEmpty(hashData))
|
|
{
|
|
trackCount--;
|
|
resultProgress?.Report(ResultEventArgs.Success("Blank line found, skipping!"));
|
|
continue;
|
|
}
|
|
|
|
// If the line ends in a known extra track names, skip them for checking
|
|
// TODO: Smarter method to ignore all tracks that start with 0. 00. A. or AA.
|
|
if (hashData.Contains(".dmi")
|
|
|| hashData.Contains(".pfi")
|
|
|| hashData.Contains(".ss")
|
|
|| hashData.Contains("(Track 0).bin")
|
|
|| hashData.Contains("(Track 0.1).bin")
|
|
|| hashData.Contains("(Track 0.2).bin")
|
|
|| hashData.Contains("(Track 0.3).bin")
|
|
|| hashData.Contains("(Track 0.4).bin")
|
|
|| hashData.Contains("(Track 0.5).bin")
|
|
|| hashData.Contains("(Track 00).bin")
|
|
|| hashData.Contains("(Track 00.1).bin")
|
|
|| hashData.Contains("(Track 00.2).bin")
|
|
|| hashData.Contains("(Track 00.3).bin")
|
|
|| hashData.Contains("(Track 00.4).bin")
|
|
|| hashData.Contains("(Track 00.5).bin")
|
|
|| hashData.Contains("(Track A).bin")
|
|
|| hashData.Contains("(Track A.1).bin")
|
|
|| hashData.Contains("(Track A.2).bin")
|
|
|| hashData.Contains("(Track A.3).bin")
|
|
|| hashData.Contains("(Track A.4).bin")
|
|
|| hashData.Contains("(Track A.5).bin")
|
|
|| hashData.Contains("(Track AA).bin")
|
|
|| hashData.Contains("(Track AA.1).bin")
|
|
|| hashData.Contains("(Track AA.2).bin")
|
|
|| hashData.Contains("(Track AA.3).bin")
|
|
|| hashData.Contains("(Track AA.4).bin")
|
|
|| hashData.Contains("(Track AA.5).bin"))
|
|
{
|
|
trackCount--;
|
|
resultProgress?.Report(ResultEventArgs.Success("Extra track found, skipping!"));
|
|
continue;
|
|
}
|
|
|
|
// Get the SHA-1 hash
|
|
if (!ProcessingTool.GetISOHashValues(hashData, out _, out _, out _, out string? sha1))
|
|
{
|
|
resultProgress?.Report(ResultEventArgs.Failure($"Line could not be parsed: {hashData}"));
|
|
continue;
|
|
}
|
|
|
|
var foundIds = await Validator.ValidateSingleTrack(wc, info, sha1);
|
|
if (foundIds != null && foundIds.Count == 1)
|
|
resultProgress?.Report(ResultEventArgs.Success($"Single match found for {sha1}"));
|
|
else if (foundIds != null && foundIds.Count != 1)
|
|
resultProgress?.Report(ResultEventArgs.Success($"Multiple matches found for {sha1}"));
|
|
else
|
|
resultProgress?.Report(ResultEventArgs.Failure($"No matches found for {sha1}"));
|
|
|
|
// Add the found IDs to the map
|
|
foundIdSets.Add(foundIds?.ToArray() ?? []);
|
|
|
|
// Ensure that all tracks are found
|
|
allFound &= (foundIds != null && foundIds.Count >= 1);
|
|
}
|
|
|
|
// If all tracks were found, check if there are any fully-matched IDs
|
|
HashSet<int>? fullyMatchedIdsSet = null;
|
|
if (allFound)
|
|
{
|
|
fullyMatchedIdsSet = null;
|
|
foreach (var set in foundIdSets)
|
|
{
|
|
// First track is always all IDs
|
|
if (fullyMatchedIdsSet == null)
|
|
{
|
|
fullyMatchedIdsSet = [.. set];
|
|
continue;
|
|
}
|
|
|
|
// Try to intersect with all known IDs
|
|
fullyMatchedIdsSet.IntersectWith(set);
|
|
if (fullyMatchedIdsSet.Count == 0)
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If we don't have any matches but we have a universal hash
|
|
if (info.PartiallyMatchedIDs.Count == 0 && info.CommonDiscInfo?.CommentsSpecialFields?.ContainsKey(SiteCode.UniversalHash) == true)
|
|
{
|
|
string sha1 = info.CommonDiscInfo.CommentsSpecialFields[SiteCode.UniversalHash];
|
|
var foundIds = await Validator.ValidateUniversalHash(wc, info);
|
|
if (foundIds != null && foundIds.Count == 1)
|
|
resultProgress?.Report(ResultEventArgs.Success($"Single match found for universal hash {sha1}"));
|
|
else if (foundIds != null && foundIds.Count != 1)
|
|
resultProgress?.Report(ResultEventArgs.Success($"Multiple matches found for universal hash {sha1}"));
|
|
else
|
|
resultProgress?.Report(ResultEventArgs.Failure($"No matches found for universal hash {sha1}"));
|
|
|
|
// Ensure that the hash is found
|
|
allFound = (foundIds != null && foundIds.Count == 1);
|
|
|
|
// If we found a match, then the disc is a match
|
|
if (foundIds != null && foundIds.Count == 1)
|
|
fullyMatchedIdsSet = [.. foundIds];
|
|
else
|
|
fullyMatchedIdsSet = [];
|
|
}
|
|
|
|
// Get a list version of the fully matched IDs
|
|
List<int> fullyMatchedIdsList = fullyMatchedIdsSet != null ? [.. fullyMatchedIdsSet] : [];
|
|
|
|
// Make sure we only have unique IDs
|
|
var partiallyMatchedIds = new HashSet<int>();
|
|
partiallyMatchedIds.IntersectWith(info.PartiallyMatchedIDs);
|
|
info.PartiallyMatchedIDs = [.. partiallyMatchedIds];
|
|
info.PartiallyMatchedIDs.Sort();
|
|
|
|
resultProgress?.Report(ResultEventArgs.Success("Match finding complete! " + (fullyMatchedIdsList != null && fullyMatchedIdsList.Count > 0
|
|
? "Fully Matched IDs: " + string.Join(",", [.. fullyMatchedIdsList.ConvertAll(i => i.ToString())])
|
|
: "No matches found")));
|
|
|
|
// Exit early if one failed or there are no matched IDs
|
|
if (!allFound || fullyMatchedIdsList == null || fullyMatchedIdsList.Count == 0)
|
|
return false;
|
|
|
|
// Find the first matched ID where the track count matches, we can grab a bunch of info from it
|
|
int totalMatchedIDsCount = fullyMatchedIdsList.Count;
|
|
for (int i = 0; i < totalMatchedIDsCount; i++)
|
|
{
|
|
// Skip if the track count doesn't match
|
|
if (!await Validator.ValidateTrackCount(wc, fullyMatchedIdsList[i], trackCount))
|
|
continue;
|
|
|
|
// Fill in the fields from the existing ID
|
|
resultProgress?.Report(ResultEventArgs.Success($"Filling fields from existing ID {fullyMatchedIdsList[i]}..."));
|
|
_ = await Builder.FillFromId(wc, info, fullyMatchedIdsList[i], options.PullAllInformation);
|
|
resultProgress?.Report(ResultEventArgs.Success("Information filling complete!"));
|
|
|
|
// Set the fully matched ID to the current
|
|
info.FullyMatchedID = fullyMatchedIdsList[i];
|
|
break;
|
|
}
|
|
|
|
// Clear out fully matched IDs from the partial list
|
|
if (info.FullyMatchedID.HasValue)
|
|
{
|
|
if (info.PartiallyMatchedIDs.Count == 1)
|
|
info.PartiallyMatchedIDs = null;
|
|
else
|
|
info.PartiallyMatchedIDs.Remove(info.FullyMatchedID.Value);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Helper Functions
|
|
|
|
/// <summary>
|
|
/// Creates a default SubmissionInfo object based on the current system and media type
|
|
/// </summary>
|
|
private static SubmissionInfo CreateDefaultSubmissionInfo(BaseProcessor processor, RedumpSystem? system, MediaType? mediaType, bool addPlaceholders)
|
|
{
|
|
// Create the template object
|
|
var info = new SubmissionInfo()
|
|
{
|
|
CommonDiscInfo = new CommonDiscInfoSection()
|
|
{
|
|
System = system,
|
|
Media = mediaType.ToDiscType(),
|
|
Title = addPlaceholders ? RequiredValue : string.Empty,
|
|
ForeignTitleNonLatin = addPlaceholders ? OptionalValue : string.Empty,
|
|
DiscNumberLetter = addPlaceholders ? OptionalValue : string.Empty,
|
|
DiscTitle = addPlaceholders ? OptionalValue : string.Empty,
|
|
Category = null,
|
|
Region = null,
|
|
Languages = null,
|
|
Serial = addPlaceholders ? RequiredIfExistsValue : string.Empty,
|
|
Barcode = addPlaceholders ? OptionalValue : string.Empty,
|
|
Contents = string.Empty,
|
|
},
|
|
VersionAndEditions = new VersionAndEditionsSection()
|
|
{
|
|
OtherEditions = addPlaceholders ? "(VERIFY THIS) Original" : string.Empty,
|
|
},
|
|
DumpingInfo = new DumpingInfoSection()
|
|
{
|
|
FrontendVersion = FrontendTool.GetCurrentVersion(),
|
|
DumpingProgram = GetDumpingProgramFromProcessor(processor),
|
|
},
|
|
};
|
|
|
|
// Ensure that required sections exist
|
|
info = Builder.EnsureAllSections(info);
|
|
return info;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the dumping program name from the processor
|
|
/// </summary>
|
|
/// <param name="processor"></param>
|
|
/// <returns></returns>
|
|
private static string? GetDumpingProgramFromProcessor(BaseProcessor processor)
|
|
{
|
|
// Map to the internal program
|
|
InternalProgram? internalProgram = processor switch
|
|
{
|
|
Processors.Aaru => InternalProgram.Aaru,
|
|
CleanRip => InternalProgram.CleanRip,
|
|
DiscImageCreator => InternalProgram.DiscImageCreator,
|
|
PS3CFW => InternalProgram.PS3CFW,
|
|
Redumper => InternalProgram.Redumper,
|
|
UmdImageCreator => InternalProgram.UmdImageCreator,
|
|
XboxBackupCreator => InternalProgram.XboxBackupCreator,
|
|
_ => null,
|
|
};
|
|
|
|
// Use the internal program to map to the name
|
|
return internalProgram.LongName();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Simplifies a volume label into uppercase alphanumeric only string
|
|
/// </summary>
|
|
/// <param name="labels">Volume label to simplify</param>
|
|
/// <returns>Simplified volume label, null if empty or invalid</returns>
|
|
private static string? SimplifyVolumeLabel(string? label)
|
|
{
|
|
// Ignore empty labels
|
|
if (label == null || label.Length == 0)
|
|
return null;
|
|
|
|
// Take only ASCII alphanumeric characters
|
|
var labelBuilder = new StringBuilder();
|
|
foreach (char c in label)
|
|
{
|
|
if (c >= '0' && c <= '9')
|
|
labelBuilder.Append(c);
|
|
else if (c >= 'A' && c <= 'Z')
|
|
labelBuilder.Append(c);
|
|
else if (c >= 'a' && c <= 'z')
|
|
labelBuilder.Append(char.ToUpper(c));
|
|
}
|
|
|
|
// Ignore non-ASCII labels
|
|
string? simpleLabel = labelBuilder.ToString();
|
|
if (simpleLabel == null || simpleLabel.Length == 0)
|
|
return null;
|
|
|
|
return simpleLabel;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Formats a list of volume labels and their corresponding filesystems
|
|
/// </summary>
|
|
/// <param name="labels">Dictionary of volume labels and their filesystems</param>
|
|
/// <returns>Formatted string of volume labels and their filesystems</returns>
|
|
private static string? FormatVolumeLabels(string? driveLabel, Dictionary<string, List<string>>? labels)
|
|
{
|
|
// Treat empty label as null
|
|
if (driveLabel != null && driveLabel.Length == 0)
|
|
driveLabel = null;
|
|
|
|
// Treat "path" labels as null -- Indicates a mounted path
|
|
// This can over-match if a label contains a directory separator somehow
|
|
if (driveLabel != null && (driveLabel.Contains("/") || driveLabel.Contains("\\")))
|
|
driveLabel = null;
|
|
|
|
// Must have at least one label to format
|
|
if (driveLabel == null && (labels == null || labels.Count == 0))
|
|
return null;
|
|
|
|
// If no labels given, use drive label
|
|
if (labels == null || labels.Count == 0)
|
|
{
|
|
// Ignore common volume labels
|
|
if (FrontendTool.GetRedumpSystemFromVolumeLabel(driveLabel) != null)
|
|
return null;
|
|
|
|
return driveLabel;
|
|
}
|
|
|
|
// Get the default label to compare against
|
|
// TODO: Full pairwise comparison of all labels, not just comparing against drive/UDF label.
|
|
string? defaultLabel = null;
|
|
if (driveLabel != null && driveLabel.Length != 0)
|
|
{
|
|
defaultLabel = SimplifyVolumeLabel(driveLabel);
|
|
}
|
|
#if NET35_OR_GREATER || NETCOREAPP
|
|
else
|
|
{
|
|
defaultLabel = labels
|
|
.Where(label => label.Value.Contains("UDF"))
|
|
.Select(label => label.Key)
|
|
.FirstOrDefault();
|
|
}
|
|
#endif
|
|
|
|
// Remove duplicate/useless volume labels
|
|
if (defaultLabel != null && defaultLabel.Length != 0)
|
|
{
|
|
List<string> keys = [.. labels.Keys];
|
|
foreach (var label in keys)
|
|
{
|
|
// Always remove "DVD_ROM" / "CD_ROM" labels
|
|
if (label == "DVD_ROM" || label == "CD_ROM")
|
|
{
|
|
labels.Remove(label);
|
|
continue;
|
|
}
|
|
|
|
// Get upper-case ASCII variant of the label
|
|
string? tempLabel = SimplifyVolumeLabel(label);
|
|
if (tempLabel == null)
|
|
continue;
|
|
|
|
// Remove duplicate volume labels
|
|
if (defaultLabel == tempLabel)
|
|
labels.Remove(label);
|
|
}
|
|
}
|
|
|
|
// If no labels are left, use drive label
|
|
if (labels == null || labels.Count == 0)
|
|
{
|
|
// Ignore common volume labels
|
|
if (FrontendTool.GetRedumpSystemFromVolumeLabel(driveLabel) != null)
|
|
return null;
|
|
|
|
return driveLabel;
|
|
}
|
|
|
|
// If only one unique label left, don't mention fs
|
|
#if NET20
|
|
string[] keyArr = [.. labels.Keys];
|
|
string firstLabel = keyArr[0];
|
|
#else
|
|
string firstLabel = labels.First().Key;
|
|
#endif
|
|
if (labels.Count == 1 && (firstLabel == driveLabel || driveLabel == null))
|
|
{
|
|
// Ignore common volume labels
|
|
if (FrontendTool.GetRedumpSystemFromVolumeLabel(firstLabel) != null)
|
|
return null;
|
|
|
|
return firstLabel;
|
|
}
|
|
|
|
// Otherwise, state filesystem for each label
|
|
List<string> volLabels = [];
|
|
|
|
// Begin formatted output with the label from Windows, if it is unique and not a common volume label
|
|
if (driveLabel != null && !labels.TryGetValue(driveLabel, out List<string>? value) && FrontendTool.GetRedumpSystemFromVolumeLabel(driveLabel) == null)
|
|
volLabels.Add(driveLabel);
|
|
|
|
// Add remaining labels with their corresponding filesystems
|
|
foreach (var kvp in labels)
|
|
{
|
|
// Ignore common volume labels
|
|
if (FrontendTool.GetRedumpSystemFromVolumeLabel(kvp.Key) == null)
|
|
volLabels.Add($"{kvp.Key} ({string.Join(", ", [.. kvp.Value])})");
|
|
}
|
|
|
|
// Ensure that no labels are empty
|
|
volLabels = volLabels.FindAll(label => !string.IsNullOrEmpty(label?.Trim()));
|
|
|
|
// Print each label separated by a comma and a space
|
|
if (volLabels.Count == 0)
|
|
return null;
|
|
|
|
return string.Join(", ", [.. volLabels]);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Processes default data based on media type
|
|
/// </summary>
|
|
private static bool ProcessMediaType(SubmissionInfo info, MediaType? mediaType, bool addPlaceholders)
|
|
{
|
|
switch (mediaType)
|
|
{
|
|
case MediaType.CDROM:
|
|
case MediaType.GDROM:
|
|
info.CommonDiscInfo!.Layer0MasteringRing = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0MasteringSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0ToolstampMasteringCode = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0MouldSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer1MouldSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0AdditionalMould = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
break;
|
|
|
|
case MediaType.DVD:
|
|
case MediaType.HDDVD:
|
|
case MediaType.BluRay:
|
|
|
|
// If we have a single-layer disc
|
|
if (info.SizeAndChecksums!.Layerbreak == default)
|
|
{
|
|
info.CommonDiscInfo!.Layer0MasteringRing = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0MasteringSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0ToolstampMasteringCode = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0MouldSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer1MouldSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0AdditionalMould = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
}
|
|
// If we have a dual-layer disc
|
|
else if (info.SizeAndChecksums!.Layerbreak2 == default)
|
|
{
|
|
info.CommonDiscInfo!.Layer0MasteringRing = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0MasteringSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0ToolstampMasteringCode = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0MouldSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0AdditionalMould = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
|
|
info.CommonDiscInfo.Layer1MasteringRing = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer1MasteringSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer1ToolstampMasteringCode = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer1MouldSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
}
|
|
// If we have a triple-layer disc
|
|
else if (info.SizeAndChecksums!.Layerbreak3 == default)
|
|
{
|
|
info.CommonDiscInfo!.Layer0MasteringRing = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0MasteringSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0ToolstampMasteringCode = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0MouldSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0AdditionalMould = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
|
|
info.CommonDiscInfo.Layer1MasteringRing = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer1MasteringSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer1ToolstampMasteringCode = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer1MouldSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
|
|
info.CommonDiscInfo.Layer2MasteringRing = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer2MasteringSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer2ToolstampMasteringCode = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
}
|
|
// If we have a quad-layer disc
|
|
else
|
|
{
|
|
info.CommonDiscInfo!.Layer0MasteringRing = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0MasteringSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0ToolstampMasteringCode = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0MouldSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0AdditionalMould = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
|
|
info.CommonDiscInfo.Layer1MasteringRing = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer1MasteringSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer1ToolstampMasteringCode = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer1MouldSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
|
|
info.CommonDiscInfo.Layer2MasteringRing = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer2MasteringSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer2ToolstampMasteringCode = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
|
|
info.CommonDiscInfo.Layer3MasteringRing = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer3MasteringSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer3ToolstampMasteringCode = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
}
|
|
|
|
break;
|
|
|
|
case MediaType.NintendoGameCubeGameDisc:
|
|
info.CommonDiscInfo!.Layer0MasteringRing = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0MasteringSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0ToolstampMasteringCode = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0MouldSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer1MouldSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0AdditionalMould = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.Extras!.BCA ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
break;
|
|
|
|
case MediaType.NintendoWiiOpticalDisc:
|
|
case MediaType.NintendoWiiUOpticalDisc:
|
|
|
|
// If we have a single-layer disc
|
|
if (info.SizeAndChecksums!.Layerbreak == default)
|
|
{
|
|
info.CommonDiscInfo!.Layer0MasteringRing = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0MasteringSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0ToolstampMasteringCode = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0MouldSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer1MouldSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0AdditionalMould = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
}
|
|
// If we have a dual-layer disc
|
|
else
|
|
{
|
|
info.CommonDiscInfo!.Layer0MasteringRing = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0MasteringSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0ToolstampMasteringCode = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0MouldSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0AdditionalMould = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
|
|
info.CommonDiscInfo.Layer1MasteringRing = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer1MasteringSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer1ToolstampMasteringCode = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer1MouldSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
}
|
|
|
|
info.Extras!.DiscKey = addPlaceholders ? RequiredValue : string.Empty;
|
|
info.Extras.BCA ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
|
|
break;
|
|
|
|
case MediaType.UMD:
|
|
// Both single- and dual-layer discs have two "layers" for the ring
|
|
info.CommonDiscInfo!.Layer0MasteringRing = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0MasteringSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0ToolstampMasteringCode = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer0MouldSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
|
|
info.CommonDiscInfo.Layer1MasteringRing = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer1MasteringSID = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
info.CommonDiscInfo.Layer1ToolstampMasteringCode = addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
|
|
info.SizeAndChecksums!.CRC32 ??= (addPlaceholders ? RequiredValue + " [Not automatically generated for UMD]" : string.Empty);
|
|
info.SizeAndChecksums.MD5 ??= (addPlaceholders ? RequiredValue + " [Not automatically generated for UMD]" : string.Empty);
|
|
info.SizeAndChecksums.SHA1 ??= (addPlaceholders ? RequiredValue + " [Not automatically generated for UMD]" : string.Empty);
|
|
info.TracksAndWriteOffsets!.ClrMameProData = null;
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Processes default data based on system type
|
|
/// </summary>
|
|
private static bool ProcessSystem(SubmissionInfo info, RedumpSystem? system, Drive? drive, bool addPlaceholders, bool isDiscImageCreator, string basePath)
|
|
{
|
|
// Extract info based specifically on RedumpSystem
|
|
switch (system)
|
|
{
|
|
case RedumpSystem.AcornArchimedes:
|
|
info.CommonDiscInfo!.Region ??= Region.UnitedKingdom;
|
|
break;
|
|
|
|
case RedumpSystem.AudioCD:
|
|
case RedumpSystem.DVDAudio:
|
|
case RedumpSystem.EnhancedCD:
|
|
case RedumpSystem.SuperAudioCD:
|
|
info.CommonDiscInfo!.Category ??= DiscCategory.Audio;
|
|
break;
|
|
|
|
case RedumpSystem.BandaiPlaydiaQuickInteractiveSystem:
|
|
info.CommonDiscInfo!.EXEDateBuildDate ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
info.CommonDiscInfo.Region ??= info.CommonDiscInfo.Region ?? Region.Japan;
|
|
break;
|
|
|
|
case RedumpSystem.BDVideo:
|
|
info.CommonDiscInfo!.Category ??= DiscCategory.Video;
|
|
bool bee = PhysicalTool.GetBusEncryptionEnabled(drive);
|
|
if (bee && string.IsNullOrEmpty(info.CopyProtection!.Protection))
|
|
info.CopyProtection.Protection = "Bus encryption enabled flag set";
|
|
else if (bee)
|
|
info.CopyProtection!.Protection += "\nBus encryption enabled flag set";
|
|
else
|
|
info.CopyProtection!.Protection ??= addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
|
|
break;
|
|
|
|
case RedumpSystem.DVDVideo:
|
|
case RedumpSystem.HDDVDVideo:
|
|
info.CommonDiscInfo!.Category ??= DiscCategory.Video;
|
|
info.CopyProtection!.Protection ??= addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
break;
|
|
|
|
case RedumpSystem.CommodoreAmigaCD:
|
|
info.CommonDiscInfo!.EXEDateBuildDate ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
break;
|
|
|
|
case RedumpSystem.CommodoreAmigaCD32:
|
|
info.CommonDiscInfo!.EXEDateBuildDate ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
info.CommonDiscInfo.Region ??= Region.Europe;
|
|
break;
|
|
|
|
case RedumpSystem.CommodoreAmigaCDTV:
|
|
info.CommonDiscInfo!.EXEDateBuildDate ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
info.CommonDiscInfo.Region ??= Region.Europe;
|
|
break;
|
|
|
|
case RedumpSystem.FujitsuFMTownsseries:
|
|
info.CommonDiscInfo!.EXEDateBuildDate ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
info.CommonDiscInfo.Region ??= Region.Japan;
|
|
break;
|
|
|
|
case RedumpSystem.FujitsuFMTownsMarty:
|
|
info.CommonDiscInfo!.Region ??= Region.Japan;
|
|
break;
|
|
|
|
case RedumpSystem.HasbroVideoNow:
|
|
case RedumpSystem.HasbroVideoNowColor:
|
|
case RedumpSystem.HasbroVideoNowJr:
|
|
case RedumpSystem.VideoCD:
|
|
info.CommonDiscInfo!.Category ??= DiscCategory.Video;
|
|
break;
|
|
|
|
case RedumpSystem.HasbroVideoNowXP:
|
|
case RedumpSystem.PhotoCD:
|
|
case RedumpSystem.SonyElectronicBook:
|
|
info.CommonDiscInfo!.Category ??= DiscCategory.Multimedia;
|
|
break;
|
|
|
|
case RedumpSystem.IncredibleTechnologiesEagle:
|
|
info.CommonDiscInfo!.EXEDateBuildDate ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
break;
|
|
|
|
case RedumpSystem.KonamieAmusement:
|
|
info.CommonDiscInfo!.EXEDateBuildDate ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
break;
|
|
|
|
case RedumpSystem.KonamiFireBeat:
|
|
info.CommonDiscInfo!.EXEDateBuildDate ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
break;
|
|
|
|
case RedumpSystem.KonamiPython2:
|
|
string? kp2Exe = PhysicalTool.GetPlayStationExecutableName(drive);
|
|
|
|
// TODO: Remove this hack when DIC supports build date output
|
|
if (isDiscImageCreator)
|
|
info.CommonDiscInfo!.EXEDateBuildDate = DiscImageCreator.GetPlayStationEXEDate($"{basePath}_volDesc.txt", kp2Exe);
|
|
|
|
SetCommentFieldIfNotExists(info, SiteCode.InternalSerialName, drive, PhysicalTool.GetPlayStationSerial);
|
|
info.CommonDiscInfo!.EXEDateBuildDate ??= PhysicalTool.GetFileDate(drive, kp2Exe, fixTwoDigitYear: true);
|
|
|
|
if (CommentFieldExists(info, SiteCode.InternalSerialName, out kp2Exe))
|
|
info.CommonDiscInfo!.Region = ProcessingTool.GetPlayStationRegion(kp2Exe);
|
|
|
|
SetVersionIfNotExists(info, drive, PhysicalTool.GetPlayStation2Version);
|
|
break;
|
|
|
|
case RedumpSystem.KonamiSystemGV:
|
|
info.CommonDiscInfo!.EXEDateBuildDate ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
break;
|
|
|
|
case RedumpSystem.KonamiSystem573:
|
|
info.CommonDiscInfo!.EXEDateBuildDate ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
break;
|
|
|
|
case RedumpSystem.KonamiTwinkle:
|
|
info.CommonDiscInfo!.EXEDateBuildDate ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
break;
|
|
|
|
case RedumpSystem.MattelHyperScan:
|
|
info.CommonDiscInfo!.EXEDateBuildDate ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
break;
|
|
|
|
case RedumpSystem.MicrosoftXboxOne:
|
|
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.Filename] = PhysicalTool.GetXboxFilenames(drive) ?? string.Empty;
|
|
break;
|
|
|
|
case RedumpSystem.MicrosoftXboxSeriesXS:
|
|
info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.Filename] = PhysicalTool.GetXboxFilenames(drive) ?? string.Empty;
|
|
break;
|
|
|
|
case RedumpSystem.NamcoSegaNintendoTriforce:
|
|
info.CommonDiscInfo!.EXEDateBuildDate ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
break;
|
|
|
|
case RedumpSystem.NavisoftNaviken21:
|
|
info.CommonDiscInfo!.EXEDateBuildDate = addPlaceholders ? RequiredValue : string.Empty;
|
|
info.CommonDiscInfo.Region ??= Region.Japan;
|
|
break;
|
|
|
|
case RedumpSystem.NECPC88series:
|
|
info.CommonDiscInfo!.Region ??= Region.Japan;
|
|
break;
|
|
|
|
case RedumpSystem.NECPC98series:
|
|
info.CommonDiscInfo!.EXEDateBuildDate = addPlaceholders ? RequiredValue : string.Empty;
|
|
info.CommonDiscInfo!.Region ??= Region.Japan;
|
|
break;
|
|
|
|
case RedumpSystem.NECPCFXPCFXGA:
|
|
info.CommonDiscInfo!.Region ??= Region.Japan;
|
|
break;
|
|
|
|
case RedumpSystem.SegaChihiro:
|
|
info.CommonDiscInfo!.EXEDateBuildDate ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
break;
|
|
|
|
case RedumpSystem.SegaDreamcast:
|
|
info.CommonDiscInfo!.EXEDateBuildDate ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
break;
|
|
|
|
case RedumpSystem.SegaNaomi:
|
|
info.CommonDiscInfo!.EXEDateBuildDate ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
break;
|
|
|
|
case RedumpSystem.SegaNaomi2:
|
|
info.CommonDiscInfo!.EXEDateBuildDate ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
break;
|
|
|
|
case RedumpSystem.SegaTitanVideo:
|
|
info.CommonDiscInfo!.EXEDateBuildDate ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
break;
|
|
|
|
case RedumpSystem.SharpX68000:
|
|
info.CommonDiscInfo!.Region ??= Region.Japan;
|
|
break;
|
|
|
|
case RedumpSystem.SNKNeoGeoCD:
|
|
info.CommonDiscInfo!.EXEDateBuildDate ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
break;
|
|
|
|
case RedumpSystem.SonyPlayStation:
|
|
string? ps1Exe = PhysicalTool.GetPlayStationExecutableName(drive);
|
|
|
|
// TODO: Remove this hack when DIC supports build date output
|
|
if (isDiscImageCreator)
|
|
info.CommonDiscInfo!.EXEDateBuildDate = DiscImageCreator.GetPlayStationEXEDate($"{basePath}_volDesc.txt", ps1Exe, psx: true);
|
|
|
|
SetCommentFieldIfNotExists(info, SiteCode.InternalSerialName, drive, PhysicalTool.GetPlayStationSerial);
|
|
info.CommonDiscInfo!.EXEDateBuildDate ??= PhysicalTool.GetFileDate(drive, ps1Exe, fixTwoDigitYear: true);
|
|
|
|
if (CommentFieldExists(info, SiteCode.InternalSerialName, out ps1Exe))
|
|
info.CommonDiscInfo!.Region = ProcessingTool.GetPlayStationRegion(ps1Exe);
|
|
|
|
break;
|
|
|
|
case RedumpSystem.SonyPlayStation2:
|
|
info.CommonDiscInfo!.LanguageSelection ??= [];
|
|
string? ps2Exe = PhysicalTool.GetPlayStationExecutableName(drive);
|
|
|
|
// TODO: Remove this hack when DIC supports build date output
|
|
if (isDiscImageCreator)
|
|
info.CommonDiscInfo!.EXEDateBuildDate = DiscImageCreator.GetPlayStationEXEDate($"{basePath}_volDesc.txt", ps2Exe);
|
|
|
|
SetCommentFieldIfNotExists(info, SiteCode.InternalSerialName, drive, PhysicalTool.GetPlayStationSerial);
|
|
info.CommonDiscInfo!.EXEDateBuildDate ??= PhysicalTool.GetFileDate(drive, ps2Exe, fixTwoDigitYear: true);
|
|
|
|
if (CommentFieldExists(info, SiteCode.InternalSerialName, out ps2Exe))
|
|
info.CommonDiscInfo.Region = ProcessingTool.GetPlayStationRegion(ps2Exe);
|
|
|
|
SetVersionIfNotExists(info, drive, PhysicalTool.GetPlayStation2Version);
|
|
break;
|
|
|
|
case RedumpSystem.SonyPlayStation3:
|
|
info.Extras!.DiscKey ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
info.Extras.DiscID ??= addPlaceholders ? RequiredValue : string.Empty;
|
|
|
|
SetCommentFieldIfNotExists(info, SiteCode.InternalSerialName, drive, PhysicalTool.GetPlayStation3Serial);
|
|
SetVersionIfNotExists(info, drive, PhysicalTool.GetPlayStation3Version);
|
|
SetContentFieldIfNotExists(info, SiteCode.Patches, drive, FormatPlayStation3FirmwareVersion);
|
|
break;
|
|
|
|
case RedumpSystem.SonyPlayStation4:
|
|
SetCommentFieldIfNotExists(info, SiteCode.InternalSerialName, drive, PhysicalTool.GetPlayStation4Serial);
|
|
SetVersionIfNotExists(info, drive, PhysicalTool.GetPlayStation4Version);
|
|
SetContentFieldIfNotExists(info, SiteCode.Games, drive, PhysicalTool.GetPlayStation4PkgInfo);
|
|
break;
|
|
|
|
case RedumpSystem.SonyPlayStation5:
|
|
SetCommentFieldIfNotExists(info, SiteCode.InternalSerialName, drive, PhysicalTool.GetPlayStation5Serial);
|
|
SetVersionIfNotExists(info, drive, PhysicalTool.GetPlayStation5Version);
|
|
SetContentFieldIfNotExists(info, SiteCode.Games, drive, PhysicalTool.GetPlayStation5PkgInfo);
|
|
break;
|
|
|
|
case RedumpSystem.TomyKissSite:
|
|
info.CommonDiscInfo!.Category ??= DiscCategory.Video;
|
|
info.CommonDiscInfo!.Region ??= Region.Japan;
|
|
break;
|
|
|
|
case RedumpSystem.ZAPiTGamesGameWaveFamilyEntertainmentSystem:
|
|
info.CopyProtection!.Protection ??= addPlaceholders ? RequiredIfExistsValue : string.Empty;
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a preformatted string for the PS3 firmware version, if possible
|
|
/// </summary>
|
|
private static string? FormatPlayStation3FirmwareVersion(Drive? drive)
|
|
{
|
|
string? firmwareVersion = PhysicalTool.GetPlayStation3FirmwareVersion(drive);
|
|
if (string.IsNullOrEmpty(firmwareVersion))
|
|
return string.Empty;
|
|
|
|
return $"PS3 Firmware {firmwareVersion}";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine if a comment field exists based on key
|
|
/// </summary>
|
|
private static bool CommentFieldExists(SubmissionInfo info, SiteCode key, out string? value)
|
|
{
|
|
// Ensure the comments fields exist
|
|
if (info.CommonDiscInfo!.CommentsSpecialFields == null)
|
|
info.CommonDiscInfo.CommentsSpecialFields = [];
|
|
|
|
// Check if the field exists
|
|
if (!info.CommonDiscInfo.CommentsSpecialFields.TryGetValue(key, out value))
|
|
return false;
|
|
if (string.IsNullOrEmpty(value))
|
|
return false;
|
|
|
|
// The value is valid
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set a comment field if it doesn't already have a value
|
|
/// </summary>
|
|
private static void SetCommentFieldIfNotExists(SubmissionInfo info, SiteCode key, Drive? drive, System.Func<Drive?, string?> valueFunc)
|
|
{
|
|
// If the field has a valid value, skip
|
|
if (CommentFieldExists(info, key, out _))
|
|
return;
|
|
|
|
// Set the value
|
|
string? value = valueFunc(drive);
|
|
if (value != null)
|
|
info.CommonDiscInfo!.CommentsSpecialFields![key] = value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine if a content field exists based on key
|
|
/// </summary>
|
|
private static bool ContentFieldExists(SubmissionInfo info, SiteCode key, out string? value)
|
|
{
|
|
// Ensure the contents fields exist
|
|
if (info.CommonDiscInfo!.ContentsSpecialFields == null)
|
|
info.CommonDiscInfo.ContentsSpecialFields = [];
|
|
|
|
// Check if the field exists
|
|
if (!info.CommonDiscInfo.ContentsSpecialFields.TryGetValue(key, out value))
|
|
return false;
|
|
if (string.IsNullOrEmpty(value))
|
|
return false;
|
|
|
|
// The value is valid
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set a content field if it doesn't already have a value
|
|
/// </summary>
|
|
private static void SetContentFieldIfNotExists(SubmissionInfo info, SiteCode key, Drive? drive, Func<Drive?, string?> valueFunc)
|
|
{
|
|
// If the field has a valid value, skip
|
|
if (ContentFieldExists(info, key, out _))
|
|
return;
|
|
|
|
// Set the value
|
|
string? value = valueFunc(drive);
|
|
if (value != null)
|
|
info.CommonDiscInfo!.ContentsSpecialFields![key] = value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the version if it doesn't already have a value
|
|
/// </summary>
|
|
private static void SetVersionIfNotExists(SubmissionInfo info, Drive? drive, Func<Drive?, string?> valueFunc)
|
|
{
|
|
// If the version already exists, skip
|
|
if (!string.IsNullOrEmpty(info.VersionAndEditions!.Version))
|
|
return;
|
|
|
|
// Set the version
|
|
info.VersionAndEditions.Version = valueFunc(drive) ?? string.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reformat a protection dictionary for submission info
|
|
/// </summary>
|
|
/// <param name="oldDict">ProtectionDictionary to format</param>
|
|
/// <returns>Reformatted dictionary on success, empty on error</returns>
|
|
private static Dictionary<string, List<string>?> ReformatProtectionDictionary(Dictionary<string, List<string>>? oldDict)
|
|
{
|
|
// Null or empty protections return empty
|
|
if (oldDict == null || oldDict.Count == 0)
|
|
return [];
|
|
|
|
// Reformat each set into a List
|
|
var newDict = new Dictionary<string, List<string>?>();
|
|
foreach (string key in oldDict.Keys)
|
|
{
|
|
newDict[key] = [.. oldDict[key]];
|
|
}
|
|
|
|
return newDict;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|