From 0732e9db7807c7f7d640bf23fbe8c9910cd43531 Mon Sep 17 00:00:00 2001
From: Deterous <138427222+Deterous@users.noreply.github.com>
Date: Tue, 16 Jan 2024 16:14:34 +1300
Subject: [PATCH] Retrieve volume label from logs (#627)
* Retrieve volume label from DIC and redumper logs
* Fix logic
* Remove unnecessary using
* Update changelog
* Sanitise label somewhat
* Refactor
---
CHANGELIST.md | 1 +
MPF.Core/Data/Drive.cs | 28 +++---
MPF.Core/Modules/BaseParameters.cs | 5 ++
.../Modules/DiscImageCreator/Parameters.cs | 87 +++++++++++++++++++
MPF.Core/Modules/Redumper/Parameters.cs | 66 +++++++++++++-
MPF.Core/SubmissionInfoTool.cs | 65 +++++++++++++-
6 files changed, 231 insertions(+), 21 deletions(-)
diff --git a/CHANGELIST.md b/CHANGELIST.md
index 08f07f4c..19d844f6 100644
--- a/CHANGELIST.md
+++ b/CHANGELIST.md
@@ -12,6 +12,7 @@
- Use PSX/PS2 serial as filename when Volume Label not present (Deterous)
- Allow variables in output path (Deterous)
- Check for presence of complete dump from other programs (Deterous)
+- Retrieve volume label from logs (Deterous)
### 3.0.3 (2023-12-04)
diff --git a/MPF.Core/Data/Drive.cs b/MPF.Core/Data/Drive.cs
index 54d4068a..2d7ac4df 100644
--- a/MPF.Core/Data/Drive.cs
+++ b/MPF.Core/Data/Drive.cs
@@ -277,7 +277,7 @@ namespace MPF.Core.Data
return RedumpSystem.IBMPCcompatible;
// Check volume labels first
- RedumpSystem? systemFromLabel = GetRedumpSystemFromVolumeLabel();
+ RedumpSystem? systemFromLabel = GetRedumpSystemFromVolumeLabel(this.VolumeLabel);
if (systemFromLabel != null)
return systemFromLabel;
@@ -512,48 +512,48 @@ namespace MPF.Core.Data
/// Get the current system from the drive volume label
///
/// The system based on volume label, null if none detected
- public RedumpSystem? GetRedumpSystemFromVolumeLabel()
+ public static RedumpSystem? GetRedumpSystemFromVolumeLabel(string? volumeLabel)
{
// If the volume label is empty, we can't do anything
- if (string.IsNullOrEmpty(this.VolumeLabel))
+ if (string.IsNullOrEmpty(volumeLabel))
return null;
// Audio CD
- if (this.VolumeLabel!.Equals("Audio CD", StringComparison.OrdinalIgnoreCase))
+ if (volumeLabel!.Equals("Audio CD", StringComparison.OrdinalIgnoreCase))
return RedumpSystem.AudioCD;
// Microsoft Xbox
- if (this.VolumeLabel.Equals("SEP13011042", StringComparison.OrdinalIgnoreCase))
+ if (volumeLabel.Equals("SEP13011042", StringComparison.OrdinalIgnoreCase))
return RedumpSystem.MicrosoftXbox;
- else if (this.VolumeLabel.Equals("SEP13011042072", StringComparison.OrdinalIgnoreCase))
+ else if (volumeLabel.Equals("SEP13011042072", StringComparison.OrdinalIgnoreCase))
return RedumpSystem.MicrosoftXbox;
// Microsoft Xbox 360
- if (this.VolumeLabel.Equals("XBOX360", StringComparison.OrdinalIgnoreCase))
+ if (volumeLabel.Equals("XBOX360", StringComparison.OrdinalIgnoreCase))
return RedumpSystem.MicrosoftXbox360;
- else if (this.VolumeLabel.Equals("XGD2DVD_NTSC", StringComparison.OrdinalIgnoreCase))
+ else if (volumeLabel.Equals("XGD2DVD_NTSC", StringComparison.OrdinalIgnoreCase))
return RedumpSystem.MicrosoftXbox360;
// Microsoft Xbox 360 - Too overly broad even if a lot of discs use this
- //if (this.VolumeLabel.Equals("CD_ROM", StringComparison.OrdinalIgnoreCase))
+ //if (volumeLabel.Equals("CD_ROM", StringComparison.OrdinalIgnoreCase))
// return RedumpSystem.MicrosoftXbox360; // Also for Xbox One?
- //if (this.VolumeLabel.Equals("DVD_ROM", StringComparison.OrdinalIgnoreCase))
+ //if (volumeLabel.Equals("DVD_ROM", StringComparison.OrdinalIgnoreCase))
// return RedumpSystem.MicrosoftXbox360;
// Sega Mega-CD / Sega-CD
- if (this.VolumeLabel.Equals("Sega_CD", StringComparison.OrdinalIgnoreCase))
+ if (volumeLabel.Equals("Sega_CD", StringComparison.OrdinalIgnoreCase))
return RedumpSystem.SegaMegaCDSegaCD;
// Sony PlayStation 3
- if (this.VolumeLabel.Equals("PS3VOLUME", StringComparison.OrdinalIgnoreCase))
+ if (volumeLabel.Equals("PS3VOLUME", StringComparison.OrdinalIgnoreCase))
return RedumpSystem.SonyPlayStation3;
// Sony PlayStation 4
- if (this.VolumeLabel.Equals("PS4VOLUME", StringComparison.OrdinalIgnoreCase))
+ if (volumeLabel.Equals("PS4VOLUME", StringComparison.OrdinalIgnoreCase))
return RedumpSystem.SonyPlayStation4;
// Sony PlayStation 5
- if (this.VolumeLabel.Equals("PS5VOLUME", StringComparison.OrdinalIgnoreCase))
+ if (volumeLabel.Equals("PS5VOLUME", StringComparison.OrdinalIgnoreCase))
return RedumpSystem.SonyPlayStation5;
return null;
diff --git a/MPF.Core/Modules/BaseParameters.cs b/MPF.Core/Modules/BaseParameters.cs
index 66f22710..dd96ba36 100644
--- a/MPF.Core/Modules/BaseParameters.cs
+++ b/MPF.Core/Modules/BaseParameters.cs
@@ -74,6 +74,11 @@ namespace MPF.Core.Modules
///
private Process? process;
+ ///
+ /// All found volume labels and their corresponding file systems
+ ///
+ public Dictionary>? VolumeLabels;
+
#endregion
#region Virtual Dumping Information
diff --git a/MPF.Core/Modules/DiscImageCreator/Parameters.cs b/MPF.Core/Modules/DiscImageCreator/Parameters.cs
index 2a0f9b12..62884976 100644
--- a/MPF.Core/Modules/DiscImageCreator/Parameters.cs
+++ b/MPF.Core/Modules/DiscImageCreator/Parameters.cs
@@ -409,6 +409,10 @@ namespace MPF.Core.Modules.DiscImageCreator
// Fill in the hash data
info.TracksAndWriteOffsets!.ClrMameProData = InfoTool.GenerateDatfile(datafile);
+ // Fill in the volume labels
+ if (GetVolumeLabels($"{basePath}_volDesc.txt", out var volLabels))
+ VolumeLabels = volLabels;
+
// Extract info based generically on MediaType
switch (this.Type)
{
@@ -2722,6 +2726,89 @@ namespace MPF.Core.Modules.DiscImageCreator
}
}
+ ///
+ /// Get all Volume Identifiers
+ ///
+ /// _volDesc.txt file location
+ /// Volume labels (by type), or null if none present
+ private static bool GetVolumeLabels(string volDesc, out Dictionary> volLabels)
+ {
+ // If the file doesn't exist, can't get the volume labels
+ volLabels = [];
+ if (!File.Exists(volDesc))
+ return false;
+
+ try
+ {
+ using var sr = File.OpenText(volDesc);
+ var line = sr.ReadLine();
+
+ string volType = "UNKNOWN";
+ string label;
+ while (line != null)
+ {
+ // Trim the line for later use
+ line = line.Trim();
+
+ // ISO9660 and extensions section
+ if (line.StartsWith("Volume Descriptor Type: "))
+ {
+ Int32.TryParse(line.Substring("Volume Descriptor Type: ".Length), out int volTypeInt);
+ volType = volTypeInt switch
+ {
+ // 0 => "Boot Record" // Should not not contain a Volume Identifier
+ 1 => "ISO", // ISO9660
+ 2 => "Joliet",
+ // 3 => "Volume Partition Descriptor" // Should not not contain a Volume Identifier
+ // 255 => "???" // Should not not contain a Volume Identifier
+ _ => "UNKNOWN" // Should not contain a Volume Identifier
+ };
+ }
+ // UDF section
+ else if (line.StartsWith("Primary Volume Descriptor Number:"))
+ {
+ volType = "UDF";
+ }
+ // Identifier
+ else if (line.StartsWith("Volume Identifier: "))
+ {
+ label = line.Substring("Volume Identifier: ".Length);
+
+ // Remove leading non-printable character (unsure why DIC outputs this)
+ if (Convert.ToUInt32(label[0]) == 0x7F || Convert.ToUInt32(label[0]) < 0x20)
+ label = label.Substring(1);
+
+ // Skip if label is blank
+ if (label == null || label.Length <= 0)
+ {
+ volType = "UNKNOWN";
+ line = sr.ReadLine();
+ continue;
+ }
+
+ if (volLabels.ContainsKey(label))
+ volLabels[label].Add(volType);
+ else
+ volLabels.Add(label, [volType]);
+
+ // Reset volume type
+ volType = "UNKNOWN";
+ }
+
+ line = sr.ReadLine();
+ }
+
+ // Return true if a volume label was found
+ return volLabels.Count > 0;
+ }
+ catch
+ {
+ // We don't care what the exception is right now
+ volLabels = [];
+ return false;
+ }
+ }
+
///
/// Get the DVD protection information, if possible
///
diff --git a/MPF.Core/Modules/Redumper/Parameters.cs b/MPF.Core/Modules/Redumper/Parameters.cs
index 93e0c1b1..b28af8c4 100644
--- a/MPF.Core/Modules/Redumper/Parameters.cs
+++ b/MPF.Core/Modules/Redumper/Parameters.cs
@@ -303,6 +303,10 @@ namespace MPF.Core.Modules.Redumper
if (GetDiscType($"{basePath}.log", out var discTypeOrBookType))
info.DumpingInfo.ReportedDiscType = discTypeOrBookType;
+ // Fill in the volume labels
+ if (GetVolumeLabels($"{basePath}.log", out var volLabels))
+ VolumeLabels = volLabels;
+
switch (this.Type)
{
case MediaType.CDROM:
@@ -1452,20 +1456,20 @@ namespace MPF.Core.Modules.Redumper
///
/// Get reported disc type information, if possible
///
- /// _disc.txt file location
+ /// Log file location
/// True if disc type info was set, false otherwise
- private static bool GetDiscType(string drive, out string? discTypeOrBookType)
+ private static bool GetDiscType(string log, out string? discTypeOrBookType)
{
// Set the default values
discTypeOrBookType = null;
// If the file doesn't exist, we can't get the info
- if (!File.Exists(drive))
+ if (!File.Exists(log))
return false;
try
{
- using var sr = File.OpenText(drive);
+ using var sr = File.OpenText(log);
var line = sr.ReadLine();
while (line != null)
{
@@ -1492,6 +1496,60 @@ namespace MPF.Core.Modules.Redumper
}
}
+ ///
+ /// Get all Volume Identifiers
+ ///
+ /// Log file location
+ /// Volume labels (by type), or null if none present
+ private static bool GetVolumeLabels(string log, out Dictionary> volLabels)
+ {
+ // If the file doesn't exist, can't get the volume labels
+ volLabels = [];
+ if (!File.Exists(log))
+ return false;
+
+ try
+ {
+ using var sr = File.OpenText(log);
+ var line = sr.ReadLine();
+
+ while (line != null)
+ {
+ // Trim the line for later use
+ line = line.Trim();
+
+ // ISO9660 Volume Identifier
+ if (line.StartsWith("volume identifier: "))
+ {
+ string label = line.Substring("volume identifier: ".Length);
+
+ // Skip if label is blank
+ if (label == null || label.Length <= 0)
+ break;
+
+ if (volLabels.ContainsKey(label))
+ volLabels[label].Add("ISO");
+ else
+ volLabels[label] = ["ISO"];
+
+ // Redumper log currently only outputs ISO9660 label, end here
+ break;
+ }
+
+ line = sr.ReadLine();
+ }
+
+ // Return true if a volume label was found
+ return volLabels.Count > 0;
+ }
+ catch
+ {
+ // We don't care what the exception is right now
+ volLabels = [];
+ return false;
+ }
+ }
+
///
/// Get the DVD protection information, if possible
///
diff --git a/MPF.Core/SubmissionInfoTool.cs b/MPF.Core/SubmissionInfoTool.cs
index 4333f100..6fb54ca9 100644
--- a/MPF.Core/SubmissionInfoTool.cs
+++ b/MPF.Core/SubmissionInfoTool.cs
@@ -110,8 +110,9 @@ namespace MPF.Core
info.TracksAndWriteOffsets.ClrMameProData = null;
// Add the volume label to comments, if possible or necessary
- if (drive?.VolumeLabel != null && drive.GetRedumpSystemFromVolumeLabel() == null)
- info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.VolumeLabel] = drive.VolumeLabel;
+ string? volLabels = FormatVolumeLabels(drive?.VolumeLabel, parameters?.VolumeLabels);
+ if (volLabels != null)
+ info.CommonDiscInfo!.CommentsSpecialFields![SiteCode.VolumeLabel] = volLabels;
// Extract info based generically on MediaType
switch (mediaType)
@@ -670,6 +671,64 @@ namespace MPF.Core
return true;
}
-#endregion
+ #endregion
+
+ #region Helper Functions
+
+ ///
+ /// Formats a list of volume labels and their corresponding filesystems
+ ///
+ /// Dictionary of volume labels and their filesystems
+ /// Formatted string of volume labels and their filesystems
+ private static string? FormatVolumeLabels(string? driveLabel, Dictionary>? labels)
+ {
+ // 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 (Drive.GetRedumpSystemFromVolumeLabel(driveLabel) != null)
+ return null;
+
+ return driveLabel;
+ }
+
+ // If only one label, don't mention fs
+ string firstLabel = labels.First().Key;
+ if (labels.Count == 1 && (firstLabel == driveLabel || driveLabel == null))
+ {
+ // Ignore common volume labels
+ if (Drive.GetRedumpSystemFromVolumeLabel(firstLabel) != null)
+ return null;
+
+ return firstLabel;
+ }
+
+ // Otherwise, state filesystem for each label
+ List 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? value) && Drive.GetRedumpSystemFromVolumeLabel(driveLabel) == null)
+ volLabels.Add(driveLabel);
+
+ // Add remaining labels with their corresponding filesystems
+ foreach (KeyValuePair> label in labels)
+ {
+ // Ignore common volume labels
+ if (Drive.GetRedumpSystemFromVolumeLabel(label.Key) == null)
+ volLabels.Add($"{label.Key} ({string.Join(", ", [.. label.Value])})");
+ }
+
+ // Print each label separated by a comma and a space
+ if (volLabels.Count == 0)
+ return null;
+
+ return string.Join(", ", [.. volLabels]);
+ }
+
+ #endregion
}
}