diff --git a/DICUI.Library/DiscImageCreator/Parameters.cs b/DICUI.Library/DiscImageCreator/Parameters.cs
index 1290a5e5..819641b4 100644
--- a/DICUI.Library/DiscImageCreator/Parameters.cs
+++ b/DICUI.Library/DiscImageCreator/Parameters.cs
@@ -2417,7 +2417,7 @@ namespace DICUI.DiscImageCreator
/// Output region, if possible
/// Output EXE date in "yyyy-mm-dd" format if possible, null on error
///
- private static bool GetPlaystationExecutableInfo(char? driveLetter, out Region? region, out string date)
+ public static bool GetPlaystationExecutableInfo(char? driveLetter, out Region? region, out string date)
{
region = null; date = null;
@@ -2437,31 +2437,26 @@ namespace DICUI.DiscImageCreator
// Try both of the common paths that contain information
string exeName = null;
- // Try reading SYSTEM.CNF to find the "BOOT" value
- if (File.Exists(systemCnfPath))
- {
- try
- {
- using (StreamReader sr = File.OpenText(systemCnfPath))
- {
- // Not assuming any ordering, just in case
- string line = sr.ReadLine();
- while (!line.StartsWith("BOOT"))
- line = sr.ReadLine();
+ // Read the CNF file as an INI file
+ var keyValuePairs = IniParse.ParseIniFile(systemCnfPath);
+ string bootValue = string.Empty;
- // Once it finds the "BOOT" line, extract the name, if possible
- var match = Regex.Match(line, @"BOOT.*?=\s*cdrom.?:\\?(.*?)");
- if (match != null && match.Groups.Count > 1)
- {
- exeName = match.Groups[1].Value;
- exeName = exeName.Split(';')[0];
- }
- }
- }
- catch
+ // PlayStation uses "BOOT" as the key
+ if (keyValuePairs.ContainsKey("boot"))
+ bootValue = keyValuePairs["boot"];
+
+ // PlayStation 2 uses "BOOT2" as the key
+ if (keyValuePairs.ContainsKey("boot2"))
+ bootValue = keyValuePairs["boot2"];
+
+ // If we had any boot value, parse it and get the executable name
+ if (!string.IsNullOrEmpty(bootValue))
+ {
+ var match = Regex.Match(bootValue, @"cdrom.?:\\?(.*)");
+ if (match != null && match.Groups.Count > 1)
{
- // We don't care what the error was
- return false;
+ exeName = match.Groups[1].Value;
+ exeName = exeName.Split(';')[0];
}
}
@@ -2555,34 +2550,16 @@ namespace DICUI.DiscImageCreator
if (!Directory.Exists(drivePath))
return null;
- // If we can't find SYSTEM.CNF, we don't have a PlayStation 2 disc
+ // Get the SYSTEM.CNF path to check
string systemCnfPath = Path.Combine(drivePath, "SYSTEM.CNF");
- if (!File.Exists(systemCnfPath))
- return null;
- // Try reading SYSTEM.CNF to find the "VER" value
- try
- {
- using (StreamReader sr = File.OpenText(systemCnfPath))
- {
- // Not assuming proper ordering, just in case
- string line = sr.ReadLine();
- while (!line.StartsWith("VER"))
- line = sr.ReadLine();
-
- // Once it finds the "VER" line, extract the version
- var match = Regex.Match(line, @"VER\s*=\s*(.*)");
- if (match != null && match.Groups.Count > 1)
- return match.Groups[1].Value;
-
- return null;
- }
- }
- catch
- {
- // We don't care what the error was
- return null;
- }
+ // Try to parse the SYSTEM.CNF file
+ var keyValuePairs = IniParse.ParseIniFile(systemCnfPath);
+ if (keyValuePairs.ContainsKey("ver"))
+ return keyValuePairs["ver"];
+
+ // If "VER" can't be found, we can't do much
+ return null;
}
///
diff --git a/DICUI.Library/Utilities/IniParse.cs b/DICUI.Library/Utilities/IniParse.cs
new file mode 100644
index 00000000..66c69ce5
--- /dev/null
+++ b/DICUI.Library/Utilities/IniParse.cs
@@ -0,0 +1,91 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace DICUI.Utilities
+{
+ public static class IniParse
+ {
+ ///
+ /// Read an INI file based on the path
+ ///
+ ///
+ ///
+ public static Dictionary ParseIniFile(string path)
+ {
+ // If we don't have a file, we can't read it
+ if (!File.Exists(path))
+ return new Dictionary();
+
+ using (var fileStream = File.OpenRead(path))
+ {
+ return ParseIniFile(fileStream);
+ }
+ }
+
+ ///
+ /// Read an INI file from a stream
+ ///
+ ///
+ ///
+ public static Dictionary ParseIniFile(Stream stream)
+ {
+ // If the stream is invalid or unreadable, we can't process it
+ if (stream == null || !stream.CanRead || stream.Position >= stream.Length - 1)
+ return new Dictionary();
+
+ // Keys are case-insensitive by default
+ var keyValuePairs = new Dictionary();
+ try
+ {
+ using (StreamReader sr = new StreamReader(stream))
+ {
+ string section = string.Empty;
+ while (!sr.EndOfStream)
+ {
+ string line = sr.ReadLine().Trim();
+
+ // Comments start with ';'
+ if (line.StartsWith(";"))
+ {
+ // No-op, we don't process comments
+ }
+
+ // Section titles are surrounded by square brackets
+ else if (line.StartsWith("["))
+ {
+ section = line.TrimStart('[').TrimEnd(']');
+ }
+
+ // Valid INI lines are in the format key=value
+ else if (line.Contains("="))
+ {
+ // Split the line by '=' for key-value pairs
+ string[] data = line.Split('=');
+
+ // If the value field contains an '=', we need to put them back in
+ string key = data[0].Trim();
+ string value = string.Join("=", data.Skip(1)).Trim();
+
+ // Section names are prepended to the key with a '.' separating
+ if (!string.IsNullOrEmpty(section))
+ key = $"{section}.{key}";
+
+ // Set or overwrite keys in the returned dictionary
+ keyValuePairs[key.ToLowerInvariant()] = value;
+ }
+
+ // All other lines are ignored
+ }
+ }
+ }
+ catch
+ {
+ // We don't care what the error was, just catch and return
+ return new Dictionary();
+ }
+
+ return keyValuePairs;
+ }
+ }
+}