mirror of
https://github.com/SabreTools/MPF.git
synced 2026-07-02 17:24:48 +00:00
Better common methods
This commit is contained in:
@@ -1396,7 +1396,38 @@ namespace DICUI.Aaru
|
||||
|
||||
switch (system)
|
||||
{
|
||||
case KnownSystem.KonamiPython2:
|
||||
if (GetPlaystationExecutableInfo(drive?.Letter, out Region? pythonTwoRegion, out string pythonTwoDate))
|
||||
{
|
||||
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 Region? playstationRegion, out string playstationDate))
|
||||
{
|
||||
info.CommonDiscInfo.Region = info.CommonDiscInfo.Region ?? playstationRegion;
|
||||
info.CommonDiscInfo.EXEDateBuildDate = playstationDate;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case KnownSystem.SonyPlayStation2:
|
||||
if (GetPlaystationExecutableInfo(drive?.Letter, out Region? playstationTwoRegion, out string playstationTwoDate))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -224,6 +224,8 @@ namespace DICUI.Data
|
||||
{ }
|
||||
}
|
||||
|
||||
#region Parameter Parsing
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether or not the selected item exists
|
||||
/// </summary>
|
||||
@@ -378,5 +380,261 @@ namespace DICUI.Data
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Common Information Extraction
|
||||
|
||||
/// <summary>
|
||||
/// Get the EXE date from a PlayStation disc, if possible
|
||||
/// </summary>
|
||||
/// <param name="driveLetter">Drive letter to use to check</param>
|
||||
/// <param name="region">Output region, if possible</param>
|
||||
/// <param name="date">Output EXE date in "yyyy-mm-dd" format if possible, null on error</param>
|
||||
/// <returns></returns>
|
||||
protected static bool GetPlaystationExecutableInfo(char? driveLetter, out Region? region, out string date)
|
||||
{
|
||||
region = null; date = null;
|
||||
|
||||
// If there's no drive letter, we can't do this part
|
||||
if (driveLetter == null)
|
||||
return false;
|
||||
|
||||
// If the folder no longer exists, we can't do this part
|
||||
string drivePath = driveLetter + ":\\";
|
||||
if (!Directory.Exists(drivePath))
|
||||
return false;
|
||||
|
||||
// Get the two paths that we will need to check
|
||||
string psxExePath = Path.Combine(drivePath, "PSX.EXE");
|
||||
string systemCnfPath = Path.Combine(drivePath, "SYSTEM.CNF");
|
||||
|
||||
// Try both of the common paths that contain information
|
||||
string exeName = null;
|
||||
|
||||
// Read the CNF file as an INI file
|
||||
var systemCnf = new IniFile(systemCnfPath);
|
||||
string bootValue = string.Empty;
|
||||
|
||||
// PlayStation uses "BOOT" as the key
|
||||
if (systemCnf.ContainsKey("BOOT"))
|
||||
bootValue = systemCnf["BOOT"];
|
||||
|
||||
// PlayStation 2 uses "BOOT2" as the key
|
||||
if (systemCnf.ContainsKey("BOOT2"))
|
||||
bootValue = systemCnf["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)
|
||||
{
|
||||
exeName = match.Groups[1].Value;
|
||||
exeName = exeName.Split(';')[0];
|
||||
}
|
||||
}
|
||||
|
||||
// If the SYSTEM.CNF value can't be found, try PSX.EXE
|
||||
if (string.IsNullOrWhiteSpace(exeName) && File.Exists(psxExePath))
|
||||
exeName = "PSX.EXE";
|
||||
|
||||
// If neither can be found, we return false
|
||||
if (string.IsNullOrWhiteSpace(exeName))
|
||||
return false;
|
||||
|
||||
// Get the region, if possible
|
||||
region = GetPlayStationRegion(exeName);
|
||||
|
||||
// Now that we have the EXE name, try to get the fileinfo for it
|
||||
string exePath = Path.Combine(drivePath, exeName);
|
||||
if (!File.Exists(exePath))
|
||||
return false;
|
||||
|
||||
// Fix the Y2K timestamp issue
|
||||
FileInfo fi = new FileInfo(exePath);
|
||||
DateTime dt = new DateTime(fi.LastWriteTimeUtc.Year >= 1900 && fi.LastWriteTimeUtc.Year < 1920 ? 2000 + fi.LastWriteTimeUtc.Year % 100 : fi.LastWriteTimeUtc.Year,
|
||||
fi.LastWriteTimeUtc.Month, fi.LastWriteTimeUtc.Day);
|
||||
date = dt.ToString("yyyy-MM-dd");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the version from a PlayStation 2 disc, if possible
|
||||
/// </summary>
|
||||
/// <param name="driveLetter">Drive letter to use to check</param>
|
||||
/// <returns>Game version if possible, null on error</returns>
|
||||
protected static string GetPlayStation2Version(char? driveLetter)
|
||||
{
|
||||
// If there's no drive letter, we can't do this part
|
||||
if (driveLetter == null)
|
||||
return null;
|
||||
|
||||
// If the folder no longer exists, we can't do this part
|
||||
string drivePath = driveLetter + ":\\";
|
||||
if (!Directory.Exists(drivePath))
|
||||
return null;
|
||||
|
||||
// Get the SYSTEM.CNF path to check
|
||||
string systemCnfPath = Path.Combine(drivePath, "SYSTEM.CNF");
|
||||
|
||||
// Try to parse the SYSTEM.CNF file
|
||||
var systemCnf = new IniFile(systemCnfPath);
|
||||
if (systemCnf.ContainsKey("VER"))
|
||||
return systemCnf["VER"];
|
||||
|
||||
// If "VER" can't be found, we can't do much
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the version from a PlayStation 4 disc, if possible
|
||||
/// </summary>
|
||||
/// <param name="driveLetter">Drive letter to use to check</param>
|
||||
/// <returns>Game version if possible, null on error</returns>
|
||||
protected static string GetPlayStation4Version(char? driveLetter)
|
||||
{
|
||||
// If there's no drive letter, we can't do this part
|
||||
if (driveLetter == null)
|
||||
return null;
|
||||
|
||||
// If the folder no longer exists, we can't do this part
|
||||
string drivePath = driveLetter + ":\\";
|
||||
if (!Directory.Exists(drivePath))
|
||||
return null;
|
||||
|
||||
// If we can't find param.sfo, we don't have a PlayStation 4 disc
|
||||
string paramSfoPath = Path.Combine(drivePath, "bd", "param.sfo");
|
||||
if (!File.Exists(paramSfoPath))
|
||||
return null;
|
||||
|
||||
// Let's try reading param.sfo to find the version at the end of the file
|
||||
try
|
||||
{
|
||||
using (BinaryReader br = new BinaryReader(File.OpenRead(paramSfoPath)))
|
||||
{
|
||||
br.BaseStream.Seek(-0x08, SeekOrigin.End);
|
||||
return new string(br.ReadChars(5));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error was
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Category Extraction
|
||||
|
||||
/// <summary>
|
||||
/// Determine the category based on the UMDImageCreator string
|
||||
/// </summary>
|
||||
/// <param name="region">String representing the category</param>
|
||||
/// <returns>Category, if possible</returns>
|
||||
protected static Category? GetUMDCategory(string category)
|
||||
{
|
||||
switch (category)
|
||||
{
|
||||
case "GAME":
|
||||
return Category.Games;
|
||||
case "VIDEO":
|
||||
return Category.Video;
|
||||
case "AUDIO":
|
||||
return Category.Audio;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Region Extraction
|
||||
|
||||
/// <summary>
|
||||
/// Determine the region based on the PlayStation serial code
|
||||
/// </summary>
|
||||
/// <param name="serial">PlayStation serial code</param>
|
||||
/// <returns>Region mapped from name, if possible</returns>
|
||||
protected static Region? GetPlayStationRegion(string serial)
|
||||
{
|
||||
// Standardized "S" serials
|
||||
if (serial.StartsWith("S"))
|
||||
{
|
||||
// string publisher = serial[0] + serial[1];
|
||||
// char secondRegion = serial[3];
|
||||
switch (serial[2])
|
||||
{
|
||||
case 'A':
|
||||
return Region.Asia;
|
||||
case 'C':
|
||||
return Region.China;
|
||||
case 'E':
|
||||
return Region.Europe;
|
||||
case 'J':
|
||||
return Region.JapanKorea;
|
||||
case 'K':
|
||||
return Region.Korea;
|
||||
case 'P':
|
||||
return Region.Japan;
|
||||
case 'U':
|
||||
return Region.USA;
|
||||
}
|
||||
}
|
||||
|
||||
// Japan-only special serial
|
||||
else if (serial.StartsWith("PAPX"))
|
||||
return Region.Japan;
|
||||
|
||||
// Region appears entirely random
|
||||
else if (serial.StartsWith("PABX"))
|
||||
return null;
|
||||
|
||||
// Japan-only special serial
|
||||
else if (serial.StartsWith("PCBX"))
|
||||
return Region.Japan;
|
||||
|
||||
// Single disc known, Japan
|
||||
else if (serial.StartsWith("PDBX"))
|
||||
return Region.Japan;
|
||||
|
||||
// Single disc known, Europe
|
||||
else if (serial.StartsWith("PEBX"))
|
||||
return Region.Europe;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine the region based on the XGD serial character
|
||||
/// </summary>
|
||||
/// <param name="region">Character denoting the region</param>
|
||||
/// <returns>Region, if possible</returns>
|
||||
protected static Region? GetXgdRegion(char region)
|
||||
{
|
||||
switch (region)
|
||||
{
|
||||
case 'W':
|
||||
return Region.World;
|
||||
case 'A':
|
||||
return Region.USA;
|
||||
case 'J':
|
||||
return Region.JapanAsia;
|
||||
case 'E':
|
||||
return Region.Europe;
|
||||
case 'K':
|
||||
return Region.USAJapan;
|
||||
case 'L':
|
||||
return Region.USAEurope;
|
||||
case 'H':
|
||||
return Region.JapanEurope;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1653,7 +1653,7 @@ namespace DICUI.DiscImageCreator
|
||||
break;
|
||||
|
||||
case KnownSystem.MicrosoftXBOX:
|
||||
if (GetXBOXAuxInfo(basePath + "_disc.txt", out string dmihash, out string pfihash, out string sshash, out string ss, out string ssver))
|
||||
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" +
|
||||
@@ -1662,7 +1662,7 @@ namespace DICUI.DiscImageCreator
|
||||
info.Extras.SecuritySectorRanges = ss ?? "";
|
||||
}
|
||||
|
||||
if (GetXBOXDMIInfo(Path.Combine(outputDirectory, "DMI.bin"), out string serial, out string version, out Region? region))
|
||||
if (GetXboxDMIInfo(Path.Combine(outputDirectory, "DMI.bin"), out string serial, out string version, out Region? region))
|
||||
{
|
||||
info.CommonDiscInfo.Serial = serial ?? "";
|
||||
info.VersionAndEditions.Version = version ?? "";
|
||||
@@ -1672,7 +1672,7 @@ namespace DICUI.DiscImageCreator
|
||||
break;
|
||||
|
||||
case KnownSystem.MicrosoftXBOX360:
|
||||
if (GetXBOXAuxInfo(basePath + "_disc.txt", out string dmi360hash, out string pfi360hash, out string ss360hash, out string ss360, out string ssver360))
|
||||
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" +
|
||||
@@ -1681,7 +1681,7 @@ namespace DICUI.DiscImageCreator
|
||||
info.Extras.SecuritySectorRanges = ss360 ?? "";
|
||||
}
|
||||
|
||||
if (GetXBOX360DMIInfo(Path.Combine(outputDirectory, "DMI.bin"), out string serial360, out string version360, out Region? region360))
|
||||
if (GetXbox360DMIInfo(Path.Combine(outputDirectory, "DMI.bin"), out string serial360, out string version360, out Region? region360))
|
||||
{
|
||||
info.CommonDiscInfo.Serial = serial360 ?? "";
|
||||
info.VersionAndEditions.Version = version360 ?? "";
|
||||
@@ -1970,7 +1970,7 @@ namespace DICUI.DiscImageCreator
|
||||
private void SetBaseCommand(KnownSystem? system, MediaType? type)
|
||||
{
|
||||
// If we have an invalid combination, we should BaseCommand = null
|
||||
if (!Utilities.Validators.GetValidMediaTypes(system).Contains(type))
|
||||
if (!Validators.GetValidMediaTypes(system).Contains(type))
|
||||
{
|
||||
BaseCommand = Command.NONE;
|
||||
return;
|
||||
@@ -2410,195 +2410,6 @@ namespace DICUI.DiscImageCreator
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the EXE date from a PlayStation disc, if possible
|
||||
/// </summary>
|
||||
/// <param name="driveLetter">Drive letter to use to check</param>
|
||||
/// <param name="region">Output region, if possible</param>
|
||||
/// <param name="date">Output EXE date in "yyyy-mm-dd" format if possible, null on error</param>
|
||||
/// <returns></returns>
|
||||
private static bool GetPlaystationExecutableInfo(char? driveLetter, out Region? region, out string date)
|
||||
{
|
||||
region = null; date = null;
|
||||
|
||||
// If there's no drive letter, we can't do this part
|
||||
if (driveLetter == null)
|
||||
return false;
|
||||
|
||||
// If the folder no longer exists, we can't do this part
|
||||
string drivePath = driveLetter + ":\\";
|
||||
if (!Directory.Exists(drivePath))
|
||||
return false;
|
||||
|
||||
// Get the two paths that we will need to check
|
||||
string psxExePath = Path.Combine(drivePath, "PSX.EXE");
|
||||
string systemCnfPath = Path.Combine(drivePath, "SYSTEM.CNF");
|
||||
|
||||
// Try both of the common paths that contain information
|
||||
string exeName = null;
|
||||
|
||||
// Read the CNF file as an INI file
|
||||
var keyValuePairs = IniParse.ParseIniFile(systemCnfPath);
|
||||
string bootValue = string.Empty;
|
||||
|
||||
// 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)
|
||||
{
|
||||
exeName = match.Groups[1].Value;
|
||||
exeName = exeName.Split(';')[0];
|
||||
}
|
||||
}
|
||||
|
||||
// If the SYSTEM.CNF value can't be found, try PSX.EXE
|
||||
if (string.IsNullOrWhiteSpace(exeName) && File.Exists(psxExePath))
|
||||
exeName = "PSX.EXE";
|
||||
|
||||
// If neither can be found, we return false
|
||||
if (string.IsNullOrWhiteSpace(exeName))
|
||||
return false;
|
||||
|
||||
// Standardized "S" serials
|
||||
if (exeName.StartsWith("S"))
|
||||
{
|
||||
// string publisher = exeName[0] + exeName[1];
|
||||
// char secondRegion = exeName[3];
|
||||
switch (exeName[2])
|
||||
{
|
||||
case 'A':
|
||||
region = Region.Asia;
|
||||
break;
|
||||
case 'C':
|
||||
region = Region.China;
|
||||
break;
|
||||
case 'E':
|
||||
region = Region.Europe;
|
||||
break;
|
||||
case 'J':
|
||||
region = Region.JapanKorea;
|
||||
break;
|
||||
case 'K':
|
||||
region = Region.Korea;
|
||||
break;
|
||||
case 'P':
|
||||
region = Region.Japan;
|
||||
break;
|
||||
case 'U':
|
||||
region = Region.USA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Special cases
|
||||
else if (exeName.StartsWith("PAPX"))
|
||||
{
|
||||
region = Region.Japan;
|
||||
}
|
||||
else if (exeName.StartsWith("PABX"))
|
||||
{
|
||||
// Region appears entirely random
|
||||
}
|
||||
else if (exeName.StartsWith("PCBX"))
|
||||
{
|
||||
region = Region.Japan;
|
||||
}
|
||||
else if (exeName.StartsWith("PDBX"))
|
||||
{
|
||||
// Single disc known, Japan
|
||||
}
|
||||
else if (exeName.StartsWith("PEBX"))
|
||||
{
|
||||
// Single disc known, Europe
|
||||
}
|
||||
|
||||
// Now that we have the EXE name, try to get the fileinfo for it
|
||||
string exePath = Path.Combine(drivePath, exeName);
|
||||
if (!File.Exists(exePath))
|
||||
return false;
|
||||
|
||||
// Fix the Y2K timestamp issue
|
||||
FileInfo fi = new FileInfo(exePath);
|
||||
DateTime dt = new DateTime(fi.LastWriteTimeUtc.Year >= 1900 && fi.LastWriteTimeUtc.Year < 1920 ? 2000 + fi.LastWriteTimeUtc.Year % 100 : fi.LastWriteTimeUtc.Year,
|
||||
fi.LastWriteTimeUtc.Month, fi.LastWriteTimeUtc.Day);
|
||||
date = dt.ToString("yyyy-MM-dd");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the version from a PlayStation 2 disc, if possible
|
||||
/// </summary>
|
||||
/// <param name="driveLetter">Drive letter to use to check</param>
|
||||
/// <returns>Game version if possible, null on error</returns>
|
||||
private static string GetPlayStation2Version(char? driveLetter)
|
||||
{
|
||||
// If there's no drive letter, we can't do this part
|
||||
if (driveLetter == null)
|
||||
return null;
|
||||
|
||||
// If the folder no longer exists, we can't do this part
|
||||
string drivePath = driveLetter + ":\\";
|
||||
if (!Directory.Exists(drivePath))
|
||||
return null;
|
||||
|
||||
// Get the SYSTEM.CNF path to check
|
||||
string systemCnfPath = Path.Combine(drivePath, "SYSTEM.CNF");
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the version from a PlayStation 4 disc, if possible
|
||||
/// </summary>
|
||||
/// <param name="driveLetter">Drive letter to use to check</param>
|
||||
/// <returns>Game version if possible, null on error</returns>
|
||||
private static string GetPlayStation4Version(char? driveLetter)
|
||||
{
|
||||
// If there's no drive letter, we can't do this part
|
||||
if (driveLetter == null)
|
||||
return null;
|
||||
|
||||
// If the folder no longer exists, we can't do this part
|
||||
string drivePath = driveLetter + ":\\";
|
||||
if (!Directory.Exists(drivePath))
|
||||
return null;
|
||||
|
||||
// If we can't find param.sfo, we don't have a PlayStation 4 disc
|
||||
string paramSfoPath = Path.Combine(drivePath, "bd", "param.sfo");
|
||||
if (!File.Exists(paramSfoPath))
|
||||
return null;
|
||||
|
||||
// Let's try reading param.sfo to find the version at the end of the file
|
||||
try
|
||||
{
|
||||
using (BinaryReader br = new BinaryReader(File.OpenRead(paramSfoPath)))
|
||||
{
|
||||
br.BaseStream.Seek(-0x08, SeekOrigin.End);
|
||||
return new string(br.ReadChars(5));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error was
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the PVD from the input file, if possible
|
||||
/// </summary>
|
||||
@@ -2835,26 +2646,6 @@ namespace DICUI.DiscImageCreator
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine the category based on the UMDImageCreator string
|
||||
/// </summary>
|
||||
/// <param name="region">String representing the category</param>
|
||||
/// <returns>Category, if possible</returns>
|
||||
private static Category? GetUMDCategory(string category)
|
||||
{
|
||||
switch (category)
|
||||
{
|
||||
case "GAME":
|
||||
return Category.Games;
|
||||
case "VIDEO":
|
||||
return Category.Video;
|
||||
case "AUDIO":
|
||||
return Category.Audio;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the write offset from the input file, if possible
|
||||
/// </summary>
|
||||
@@ -2864,9 +2655,7 @@ namespace DICUI.DiscImageCreator
|
||||
{
|
||||
// If the file doesn't exist, we can't get info from it
|
||||
if (!File.Exists(disc))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
using (StreamReader sr = File.OpenText(disc))
|
||||
{
|
||||
@@ -2890,11 +2679,11 @@ namespace DICUI.DiscImageCreator
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the XBOX/360 auxiliary info from the outputted files, if possible
|
||||
/// Get the XGD auxiliary info from the outputted files, if possible
|
||||
/// </summary>
|
||||
/// <param name="disc">_disc.txt file location</param>
|
||||
/// <returns>True on successful extraction of info, false otherwise</returns>
|
||||
private static bool GetXBOXAuxInfo(string disc, out string dmihash, out string pfihash, out string sshash, out string ss, out string ssver)
|
||||
private static bool GetXgdAuxInfo(string disc, out string dmihash, out string pfihash, out string sshash, out string ss, out string ssver)
|
||||
{
|
||||
dmihash = null; pfihash = null; sshash = null; ss = null; ssver = null;
|
||||
|
||||
@@ -2906,46 +2695,45 @@ namespace DICUI.DiscImageCreator
|
||||
{
|
||||
try
|
||||
{
|
||||
// Fast forward to the Security Sector version and read it
|
||||
while (!sr.ReadLine().Trim().StartsWith("CPR_MAI Key")) ;
|
||||
ssver = sr.ReadLine().Trim().Split(' ')[4]; // "Version of challenge table: <VER>"
|
||||
|
||||
// Fast forward to the Security Sector Ranges
|
||||
while (!sr.ReadLine().Trim().StartsWith("Number of security sector ranges:")) ;
|
||||
|
||||
// Now that we're at the ranges, read each line in and concatenate
|
||||
Regex layerRegex = new Regex(@"Layer [01].*, startLBA-endLBA:\s*(\d+)-\s*(\d+)");
|
||||
string line = sr.ReadLine().Trim();
|
||||
while (!line.StartsWith("========== Unlock 2 state(wxripper) =========="))
|
||||
while(!sr.EndOfStream)
|
||||
{
|
||||
// If we have a recognized line format, parse it
|
||||
if (line.StartsWith("Layer "))
|
||||
string line = sr.ReadLine().Trim();
|
||||
|
||||
// Security Sector version
|
||||
if (line.StartsWith("Version of challenge table"))
|
||||
{
|
||||
var match = layerRegex.Match(line);
|
||||
ss += $"{match.Groups[1]}-{match.Groups[2]}\n";
|
||||
ssver = line.Split(' ')[4]; // "Version of challenge table: <VER>"
|
||||
}
|
||||
|
||||
line = sr.ReadLine().Trim();
|
||||
}
|
||||
// Security Sector ranges
|
||||
else if (line.StartsWith("Number of security sector ranges:"))
|
||||
{
|
||||
Regex layerRegex = new Regex(@"Layer [01].*, startLBA-endLBA:\s*(\d+)-\s*(\d+)");
|
||||
|
||||
// Fast forward to the aux hashes
|
||||
while (!line.StartsWith("<rom"))
|
||||
line = sr.ReadLine().Trim();
|
||||
line = sr.ReadLine().Trim();
|
||||
while (!line.StartsWith("========== Unlock 2 state(wxripper) =========="))
|
||||
{
|
||||
// If we have a recognized line format, parse it
|
||||
if (line.StartsWith("Layer "))
|
||||
{
|
||||
var match = layerRegex.Match(line);
|
||||
ss += $"{match.Groups[1]}-{match.Groups[2]}\n";
|
||||
}
|
||||
|
||||
// Read in the hashes to the proper parts
|
||||
while (line.StartsWith("<rom"))
|
||||
{
|
||||
if (line.Contains("SS.bin"))
|
||||
sshash = line;
|
||||
else if (line.Contains("PFI.bin"))
|
||||
pfihash = line;
|
||||
else if (line.Contains("DMI.bin"))
|
||||
dmihash = line;
|
||||
line = sr.ReadLine().Trim();
|
||||
}
|
||||
}
|
||||
|
||||
if (sr.EndOfStream)
|
||||
break;
|
||||
|
||||
line = sr.ReadLine().Trim();
|
||||
// Special File Hashes
|
||||
else if (line.StartsWith("<rom"))
|
||||
{
|
||||
if (line.Contains("SS.bin"))
|
||||
sshash = line;
|
||||
else if (line.Contains("PFI.bin"))
|
||||
pfihash = line;
|
||||
else if (line.Contains("DMI.bin"))
|
||||
dmihash = line;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -2959,11 +2747,11 @@ namespace DICUI.DiscImageCreator
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the XOX serial info from the DMI.bin file, if possible
|
||||
/// Get the Xbox serial info from the DMI.bin file, if possible
|
||||
/// </summary>
|
||||
/// <param name="dmi">DMI.bin file location</param>
|
||||
/// <returns>True on successful extraction of info, false otherwise</returns>
|
||||
private static bool GetXBOXDMIInfo(string dmi, out string serial, out string version, out Region? region)
|
||||
private static bool GetXboxDMIInfo(string dmi, out string serial, out string version, out Region? region)
|
||||
{
|
||||
serial = null; version = null; region = Region.World;
|
||||
|
||||
@@ -2979,7 +2767,7 @@ namespace DICUI.DiscImageCreator
|
||||
|
||||
serial = $"{str[0]}{str[1]}-{str[2]}{str[3]}{str[4]}";
|
||||
version = $"1.{str[5]}{str[6]}";
|
||||
region = GetXBOXRegion(str[7]);
|
||||
region = GetXgdRegion(str[7]);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
@@ -2990,13 +2778,13 @@ namespace DICUI.DiscImageCreator
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the XBOX 360 serial info from the DMI.bin file, if possible
|
||||
/// Get the Xbox 360 serial info from the DMI.bin file, if possible
|
||||
/// </summary>
|
||||
/// <param name="dmi">DMI.bin file location</param>
|
||||
/// <returns>True on successful extraction of info, false otherwise</returns>
|
||||
private static bool GetXBOX360DMIInfo(string dmi, out string serial, out string version, out Region? region)
|
||||
private static bool GetXbox360DMIInfo(string dmi, out string serial, out string version, out Region? region)
|
||||
{
|
||||
serial = null; version = null; region = null;
|
||||
serial = null; version = null; region = Region.World;
|
||||
|
||||
if (!File.Exists(dmi))
|
||||
return false;
|
||||
@@ -3010,7 +2798,7 @@ namespace DICUI.DiscImageCreator
|
||||
|
||||
serial = $"{str[0]}{str[1]}-{str[2]}{str[3]}{str[4]}{str[5]}";
|
||||
version = $"1.{str[6]}{str[7]}";
|
||||
region = GetXBOXRegion(str[8]);
|
||||
region = GetXgdRegion(str[8]);
|
||||
// str[9], str[10], str[11] - unknown purpose
|
||||
// str[12], str[13] - disc <12> of <13>
|
||||
return true;
|
||||
@@ -3022,34 +2810,6 @@ namespace DICUI.DiscImageCreator
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine the region based on the XBOX serial character
|
||||
/// </summary>
|
||||
/// <param name="region">Character denoting the region</param>
|
||||
/// <returns>Region, if possible</returns>
|
||||
private static Region? GetXBOXRegion(char region)
|
||||
{
|
||||
switch (region)
|
||||
{
|
||||
case 'W':
|
||||
return Region.World;
|
||||
case 'A':
|
||||
return Region.USA;
|
||||
case 'J':
|
||||
return Region.JapanAsia;
|
||||
case 'E':
|
||||
return Region.Europe;
|
||||
case 'K':
|
||||
return Region.USAJapan;
|
||||
case 'L':
|
||||
return Region.USAEurope;
|
||||
case 'H':
|
||||
return Region.JapanEurope;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
234
DICUI.Library/Utilities/IniFile.cs
Normal file
234
DICUI.Library/Utilities/IniFile.cs
Normal file
@@ -0,0 +1,234 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace DICUI.Utilities
|
||||
{
|
||||
public class IniFile
|
||||
{
|
||||
private Dictionary<string, string> _keyValuePairs;
|
||||
|
||||
public string this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_keyValuePairs == null)
|
||||
_keyValuePairs = new Dictionary<string, string>();
|
||||
|
||||
key = key.ToLowerInvariant();
|
||||
if (_keyValuePairs.ContainsKey(key))
|
||||
return _keyValuePairs[key];
|
||||
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_keyValuePairs == null)
|
||||
_keyValuePairs = new Dictionary<string, string>();
|
||||
|
||||
key = key.ToLowerInvariant();
|
||||
_keyValuePairs[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an empty INI file
|
||||
/// </summary>
|
||||
public IniFile()
|
||||
{
|
||||
_keyValuePairs = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populate an INI file from path
|
||||
/// </summary>
|
||||
public IniFile(string path)
|
||||
{
|
||||
this.Parse(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populate an INI file from stream
|
||||
/// </summary>
|
||||
public IniFile(Stream stream)
|
||||
{
|
||||
this.Parse(stream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the key exists in the INI file
|
||||
/// </summary>
|
||||
public bool ContainsKey(string key)
|
||||
{
|
||||
return _keyValuePairs.ContainsKey(key.ToLowerInvariant());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add or update a key and value to the INI file
|
||||
/// </summary>
|
||||
public void AddOrUpdate(string key, string value)
|
||||
{
|
||||
_keyValuePairs[key.ToLowerInvariant()] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a key from the INI file
|
||||
/// </summary>
|
||||
public void Remove(string key)
|
||||
{
|
||||
_keyValuePairs.Remove(key.ToLowerInvariant());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an INI file based on the path
|
||||
/// </summary>
|
||||
public bool Parse(string path)
|
||||
{
|
||||
// If we don't have a file, we can't read it
|
||||
if (!File.Exists(path))
|
||||
return false;
|
||||
|
||||
using (var fileStream = File.OpenRead(path))
|
||||
{
|
||||
return Parse(fileStream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an INI file from a stream
|
||||
/// </summary>
|
||||
public bool Parse(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 false;
|
||||
|
||||
// Keys are case-insensitive by default
|
||||
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 false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an INI file to a path
|
||||
/// </summary>
|
||||
public bool Write(string path)
|
||||
{
|
||||
// If we don't have a valid dictionary with values, we can't write out
|
||||
if (_keyValuePairs == null || _keyValuePairs.Count == 0)
|
||||
return false;
|
||||
|
||||
using (var fileStream = File.OpenWrite(path))
|
||||
{
|
||||
return Write(fileStream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an INI file to a stream
|
||||
/// </summary>
|
||||
public bool Write(Stream stream)
|
||||
{
|
||||
// If we don't have a valid dictionary with values, we can't write out
|
||||
if (_keyValuePairs == null || _keyValuePairs.Count == 0)
|
||||
return false;
|
||||
|
||||
// If the stream is invalid or unwritable, we can't output to it
|
||||
if (stream == null || !stream.CanWrite || stream.Position >= stream.Length - 1)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
using (StreamWriter sw = new StreamWriter(stream))
|
||||
{
|
||||
// Order the dictionary by keys to link sections together
|
||||
var orderedKeyValuePairs = _keyValuePairs.OrderBy(kvp => kvp.Key);
|
||||
|
||||
string section = string.Empty;
|
||||
foreach (var keyValuePair in orderedKeyValuePairs)
|
||||
{
|
||||
// Extract the key and value
|
||||
string key = keyValuePair.Key;
|
||||
string value = keyValuePair.Value;
|
||||
|
||||
// We assume '.' is a section name separator
|
||||
if (key.Contains('.'))
|
||||
{
|
||||
// Split the key by '.'
|
||||
string[] data = keyValuePair.Key.Split('.');
|
||||
|
||||
// If the key contains an '.', we need to put them back in
|
||||
string newSection = data[0].Trim();
|
||||
key = string.Join(".", data.Skip(1)).Trim();
|
||||
|
||||
// If we have a new section, write it out
|
||||
if (!string.Equals(newSection, section, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
sw.WriteLine($"[{newSection}]");
|
||||
section = newSection;
|
||||
}
|
||||
}
|
||||
|
||||
// Now write out the key and value in a standardized way
|
||||
sw.WriteLine($"{key}={value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error was, just catch and return
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace DICUI.Utilities
|
||||
{
|
||||
public static class IniParse
|
||||
{
|
||||
/// <summary>
|
||||
/// Read an INI file based on the path
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<string, string> ParseIniFile(string path)
|
||||
{
|
||||
// If we don't have a file, we can't read it
|
||||
if (!File.Exists(path))
|
||||
return new Dictionary<string, string>();
|
||||
|
||||
using (var fileStream = File.OpenRead(path))
|
||||
{
|
||||
return ParseIniFile(fileStream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an INI file from a stream
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<string, string> 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<string, string>();
|
||||
|
||||
// Keys are case-insensitive by default
|
||||
var keyValuePairs = new Dictionary<string, string>();
|
||||
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<string, string>();
|
||||
}
|
||||
|
||||
return keyValuePairs;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -918,22 +918,19 @@ namespace DICUI.Utilities
|
||||
}
|
||||
|
||||
// Sony PlayStation and Sony PlayStation 2
|
||||
if (File.Exists(Path.Combine(drivePath, "SYSTEM.CNF")))
|
||||
string psxExePath = Path.Combine(drivePath, "PSX.EXE");
|
||||
string systemCnfPath = Path.Combine(drivePath, "SYSTEM.CNF");
|
||||
if (File.Exists(systemCnfPath))
|
||||
{
|
||||
// Check for either BOOT or BOOT2
|
||||
using (StreamReader reader = File.OpenText(Path.Combine(drivePath, "SYSTEM.CNF")))
|
||||
{
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
string line = reader.ReadLine();
|
||||
if (line.Contains("BOOT2"))
|
||||
return KnownSystem.SonyPlayStation2;
|
||||
else if (line.Contains("BOOT"))
|
||||
return KnownSystem.SonyPlayStation;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a weird disc, just assume PS1
|
||||
var systemCnf = new IniFile(systemCnfPath);
|
||||
if (systemCnf.ContainsKey("BOOT"))
|
||||
return KnownSystem.SonyPlayStation;
|
||||
else if (systemCnf.ContainsKey("BOOT2"))
|
||||
return KnownSystem.SonyPlayStation2;
|
||||
}
|
||||
else if (File.Exists(psxExePath))
|
||||
{
|
||||
return KnownSystem.SonyPlayStation;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user