Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
298 changes: 298 additions & 0 deletions MPF.Frontend/Tools/PhysicalTool.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
Expand Down Expand Up @@ -155,6 +156,303 @@
}
}

#endregion

#region Computer

/// <summary>
/// Get info for discs containing Steam2 (sis/sim/sid) depots
/// </summary>
/// <param name="drive">Drive to extract information from</param>
/// <returns>Steam2 information on success, null otherwise</returns>
public static string? GetSteamSimSidInfo(Drive? drive)
{
// If there's no drive path, we can't get any sis files
if (string.IsNullOrEmpty(drive?.Name))
return null;

// If the folder no longer exists, we can't get any information
if (!Directory.Exists(drive!.Name))
return null;

try
{
string? steamInfo = "";
var steamDepotIdList = new List<string>();

// ? needed due to note in note in https://learn.microsoft.com/en-us/dotnet/api/system.io.directory.getfiles
#if NETFRAMEWORK
string[] sisPaths = Directory.GetFiles(drive.Name, "?*.sis", SearchOption.AllDirectories);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any non-annoying way to recurse in netframework?

#else
var options = new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive, RecurseSubdirectories = true };
string[] sisPaths = Directory.GetFiles(drive.Name, "?*.sis", options);
#endif

foreach (string sis in sisPaths)
{
if (!File.Exists(sis))
continue;

string filename = Path.GetFileName(sis);

// Skips csm/csd sku sis files
if (filename.ToLower() == "sku.sis")
continue;

long sisSize = new FileInfo(sis).Length;

// Arbitrary filesize cap, a disc would need over 100x the normal amount of depots to go over this.
if (sisSize > 10000)
continue;

// Read the sku sis file
using var fileStream = new FileStream(sis, FileMode.Open, FileAccess.Read);
var skuSisDeserializer = new SabreTools.Serialization.Readers.SkuSis();

Check failure on line 210 in MPF.Frontend/Tools/PhysicalTool.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'SkuSis' does not exist in the namespace 'SabreTools.Serialization.Readers' (are you missing an assembly reference?)

Check failure on line 210 in MPF.Frontend/Tools/PhysicalTool.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'SkuSis' does not exist in the namespace 'SabreTools.Serialization.Readers' (are you missing an assembly reference?)

Check failure on line 210 in MPF.Frontend/Tools/PhysicalTool.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'SkuSis' does not exist in the namespace 'SabreTools.Serialization.Readers' (are you missing an assembly reference?)

Check failure on line 210 in MPF.Frontend/Tools/PhysicalTool.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'SkuSis' does not exist in the namespace 'SabreTools.Serialization.Readers' (are you missing an assembly reference?)

Check failure on line 210 in MPF.Frontend/Tools/PhysicalTool.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'SkuSis' does not exist in the namespace 'SabreTools.Serialization.Readers' (are you missing an assembly reference?)

Check failure on line 210 in MPF.Frontend/Tools/PhysicalTool.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'SkuSis' does not exist in the namespace 'SabreTools.Serialization.Readers' (are you missing an assembly reference?)
var skuSis = skuSisDeserializer.Deserialize(fileStream);

if (skuSis != null && skuSis.VDFObject != null)
{
JToken? upper = null;

// One single case is known where this isn't true, RID 70147. As of writing, the page claims
// it's .sis/.csm/.csd, this isn't true, it's .sis/.sim/.sid. It's one of the latest
// .sis/.sim/.sim discs, if not the latest, and the only one currently known to use "sku" instead
// of "SKU". It's most likely safe to remove this, but to err on the side of caution, this should
// remain to avoid any risk of double-filling info until a much larger amount of testing is done.
if (skuSis.VDFObject.TryGetValue("SKU", out var steamSimSidValue))
upper = steamSimSidValue;

if (upper == null)
continue;

if (upper["depots"] == null)
continue;

var depotArr = upper["depots"]?.ToObject<Dictionary<string, string>>();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have any idea why I still need to use conditional access on upper["depots"] even though I did upper["depots"] == null just above?


if (depotArr == null)
continue;

steamDepotIdList.AddRange(depotArr.Values.ToList());
}
}

var sortedArray = steamDepotIdList.Select(long.Parse).ToArray();
Array.Sort(sortedArray);

#if NET20 || NET35
var compatibilitySortedArray = sortedArray.Select(x => x.ToString()).ToArray();
steamInfo = string.Join("\n", compatibilitySortedArray);
#else
steamInfo = string.Join("\n", sortedArray);
#endif

if (steamInfo == "")
return null;
else
return steamInfo;
}
catch
{
// Absorb the exception
return null;
}
}

/// <summary>
/// Get info for discs containing Steam3 (sis/csm/csd) depots
/// </summary>
/// <param name="drive">Drive to extract information from</param>
/// <returns>Steam Csm/Csd information on success, null otherwise</returns>
public static string? GetSteamCsmCsdInfo(Drive? drive)
{
// If there's no drive path, we can't get exe name
if (string.IsNullOrEmpty(drive?.Name))
return null;

// If the folder no longer exists, we can't get any information
if (!Directory.Exists(drive!.Name))
return null;

try
{
string? steamInfo = "";
var steamDepotIdDict = new SortedDictionary<long, long>();

// ? needed due to note in note in https://learn.microsoft.com/en-us/dotnet/api/system.io.directory.getfiles
#if NETFRAMEWORK
string[] sisPaths = Directory.GetFiles(drive.Name, "?*.sis", SearchOption.AllDirectories);
#else
var options = new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive, RecurseSubdirectories = true };
string[] sisPaths = Directory.GetFiles(drive.Name, "?*.sis", options);
#endif

foreach (string sis in sisPaths)
{
if (!File.Exists(sis))
continue;

string filename = Path.GetFileName(sis);

// Skips steam2 sku sis files
if (filename.ToLower() != "sku.sis")
continue;

long sisSize = new FileInfo(sis).Length;

// Arbitrary filesize cap, a disc would need over 100x the normal amount of depots to go over this.
if (sisSize > 10000)
continue;

// Read the sku sis file
using var fileStream = new FileStream(sis, FileMode.Open, FileAccess.Read);
var skuSisDeserializer = new SabreTools.Serialization.Readers.SkuSis();

Check failure on line 309 in MPF.Frontend/Tools/PhysicalTool.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'SkuSis' does not exist in the namespace 'SabreTools.Serialization.Readers' (are you missing an assembly reference?)

Check failure on line 309 in MPF.Frontend/Tools/PhysicalTool.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'SkuSis' does not exist in the namespace 'SabreTools.Serialization.Readers' (are you missing an assembly reference?)

Check failure on line 309 in MPF.Frontend/Tools/PhysicalTool.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'SkuSis' does not exist in the namespace 'SabreTools.Serialization.Readers' (are you missing an assembly reference?)

Check failure on line 309 in MPF.Frontend/Tools/PhysicalTool.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'SkuSis' does not exist in the namespace 'SabreTools.Serialization.Readers' (are you missing an assembly reference?)

Check failure on line 309 in MPF.Frontend/Tools/PhysicalTool.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'SkuSis' does not exist in the namespace 'SabreTools.Serialization.Readers' (are you missing an assembly reference?)
var skuSis = skuSisDeserializer.Deserialize(fileStream);

if (skuSis != null && skuSis.VDFObject != null)
{
JToken? upper = null;

if (skuSis.VDFObject.TryGetValue("sku", out var steamCsmCsdValue))
upper = steamCsmCsdValue;

if (upper == null)
continue;

if (upper["manifests"] == null)
continue;

var depotArr = upper["manifests"]?.ToObject<Dictionary<long, long>>();

if (depotArr == null)
continue;

foreach (var depot in depotArr)
#if NETFRAMEWORK
steamDepotIdDict.Add(depot.Key, depot.Value); // Always fine in practice.
#else
steamDepotIdDict.TryAdd(depot.Key, depot.Value); // Mainly here to allow easier bulk testing.
#endif
}
}

foreach (var depot in steamDepotIdDict)
{
steamInfo += $"{depot.Key} ({depot.Value})\n";
}

if (steamInfo == "")
return null;
else
return steamInfo;
}
catch
{
// Absorb the exception
return null;
}
}

/// <summary>
/// Get info for discs containing Steam2 (sis/sim/sid) depots
/// </summary>
/// <param name="drive">Drive to extract information from</param>
/// <returns>Steam2 information on success, null otherwise</returns>
public static string? GetSteamAppInfo(Drive? drive)
{
// If there's no drive path, we can't get exe name
if (string.IsNullOrEmpty(drive?.Name))
return null;

// If the folder no longer exists, we can't get any information
if (!Directory.Exists(drive!.Name))
return null;

try
{
string? steamInfo = "";
var steamAppIdList = new List<string>();

// ? needed due to note in note in https://learn.microsoft.com/en-us/dotnet/api/system.io.directory.getfiles
#if NETFRAMEWORK
string[] sisPaths = Directory.GetFiles(drive.Name, "?*.sis", SearchOption.AllDirectories);
#else
var options = new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive, RecurseSubdirectories = true };
string[] sisPaths = Directory.GetFiles(drive.Name, "?*.sis", options);
#endif

// Looping needed in case i.e. this is a coverdisc with multiple steam game installers on it.
foreach (string sis in sisPaths)
{
if (!File.Exists(sis))
continue;

string filename = Path.GetFileName(sis);

long sisSize = new FileInfo(sis).Length;

// Arbitrary filesize cap, a disc would need over 100x the normal amount of depots to go over this.
if (sisSize > 10000)
continue;

// Read the sku sis file
using var fileStream = new FileStream(sis, FileMode.Open, FileAccess.Read);
var skuSisDeserializer = new SabreTools.Serialization.Readers.SkuSis();

Check failure on line 400 in MPF.Frontend/Tools/PhysicalTool.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'SkuSis' does not exist in the namespace 'SabreTools.Serialization.Readers' (are you missing an assembly reference?)

Check failure on line 400 in MPF.Frontend/Tools/PhysicalTool.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'SkuSis' does not exist in the namespace 'SabreTools.Serialization.Readers' (are you missing an assembly reference?)

Check failure on line 400 in MPF.Frontend/Tools/PhysicalTool.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'SkuSis' does not exist in the namespace 'SabreTools.Serialization.Readers' (are you missing an assembly reference?)

Check failure on line 400 in MPF.Frontend/Tools/PhysicalTool.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'SkuSis' does not exist in the namespace 'SabreTools.Serialization.Readers' (are you missing an assembly reference?)

Check failure on line 400 in MPF.Frontend/Tools/PhysicalTool.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'SkuSis' does not exist in the namespace 'SabreTools.Serialization.Readers' (are you missing an assembly reference?)
var skuSis = skuSisDeserializer.Deserialize(fileStream);

if (skuSis != null && skuSis.VDFObject != null)
{
JToken? upper = null;

if (skuSis.VDFObject.TryGetValue("SKU", out var steamSimSidValue))
upper = steamSimSidValue;
else if (skuSis.VDFObject.TryGetValue("sku", out var steamCsmCsdValue))
upper = steamCsmCsdValue;

if (upper == null)
continue;

string? appsString = null;

// Some newer Steam3 discs (RID 114373 & 114374, 126740) use Apps instead of apps.
if (upper["apps"] != null)
appsString = "apps";
else if (upper["Apps"] != null)
appsString = "Apps";
else
continue;

var appArr = upper[appsString]?.ToObject<Dictionary<string, string>>();

if (appArr == null)
continue;

steamAppIdList.AddRange(appArr.Values.ToList());
}
}

var sortedArray = steamAppIdList.Select(long.Parse).ToArray();
Array.Sort(sortedArray);

#if NET20 || NET35
var compatibilitySortedArray = sortedArray.Select(x => x.ToString()).ToArray();
steamInfo = string.Join(", ", compatibilitySortedArray);
#else
steamInfo = string.Join(", ", sortedArray);
#endif

if (steamInfo == "")
return null;
else
return steamInfo;
}
catch
{
// Absorb the exception
return null;
}
}

#endregion

#region PlayStation
Expand Down
7 changes: 7 additions & 0 deletions MPF.Frontend/Tools/SubmissionGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,13 @@
case RedumpSystem.SonyElectronicBook:
info.CommonDiscInfo.Category ??= DiscCategory.Multimedia;
break;

case RedumpSystem.IBMPCcompatible:
case RedumpSystem.AppleMacintosh:
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.SteamAppID] = PhysicalTool.GetSteamAppInfo(drive) ?? string.Empty;

Check failure on line 823 in MPF.Frontend/Tools/SubmissionGenerator.cs

View workflow job for this annotation

GitHub Actions / build

'SiteCode' does not contain a definition for 'SteamAppID'

Check failure on line 823 in MPF.Frontend/Tools/SubmissionGenerator.cs

View workflow job for this annotation

GitHub Actions / build

'SiteCode' does not contain a definition for 'SteamAppID'
info.CommonDiscInfo.ContentsSpecialFields[SiteCode.SteamSimSidDepotID] = PhysicalTool.GetSteamSimSidInfo(drive) ?? string.Empty;

Check failure on line 824 in MPF.Frontend/Tools/SubmissionGenerator.cs

View workflow job for this annotation

GitHub Actions / build

'SiteCode' does not contain a definition for 'SteamSimSidDepotID'
info.CommonDiscInfo.ContentsSpecialFields[SiteCode.SteamCsmCsdDepotID] = PhysicalTool.GetSteamCsmCsdInfo(drive) ?? string.Empty;

Check failure on line 825 in MPF.Frontend/Tools/SubmissionGenerator.cs

View workflow job for this annotation

GitHub Actions / build

'SiteCode' does not contain a definition for 'SteamCsmCsdDepotID'
break;

case RedumpSystem.IncredibleTechnologiesEagle:
info.CommonDiscInfo.EXEDateBuildDate ??= addPlaceholders ? RequiredValue : string.Empty;
Expand Down