Fix issue where an ExeFS as a NSP didn't show up in the application list

This commit is contained in:
Xpl0itR 2019-11-15 18:51:29 +00:00 committed by unknown
commit 3b45fcdcc6
No known key found for this signature in database
GPG key ID: 91798184109676AD
7 changed files with 104 additions and 122 deletions

View file

@ -3,7 +3,7 @@ using System.IO;
namespace Ryujinx.HLE.Loaders.Npdm namespace Ryujinx.HLE.Loaders.Npdm
{ {
class Aci0 public class Aci0
{ {
private const int Aci0Magic = 'A' << 0 | 'C' << 8 | 'I' << 16 | '0' << 24; private const int Aci0Magic = 'A' << 0 | 'C' << 8 | 'I' << 16 | '0' << 24;

View file

@ -3,7 +3,7 @@ using System.IO;
namespace Ryujinx.HLE.Loaders.Npdm namespace Ryujinx.HLE.Loaders.Npdm
{ {
class Acid public class Acid
{ {
private const int AcidMagic = 'A' << 0 | 'C' << 8 | 'I' << 16 | 'D' << 24; private const int AcidMagic = 'A' << 0 | 'C' << 8 | 'I' << 16 | 'D' << 24;

View file

@ -2,7 +2,7 @@
namespace Ryujinx.HLE.Loaders.Npdm namespace Ryujinx.HLE.Loaders.Npdm
{ {
class FsAccessControl public class FsAccessControl
{ {
public int Version { get; private set; } public int Version { get; private set; }
public ulong PermissionsBitmask { get; private set; } public ulong PermissionsBitmask { get; private set; }

View file

@ -2,7 +2,7 @@
namespace Ryujinx.HLE.Loaders.Npdm namespace Ryujinx.HLE.Loaders.Npdm
{ {
class KernelAccessControl public class KernelAccessControl
{ {
public int[] Capabilities { get; private set; } public int[] Capabilities { get; private set; }

View file

@ -7,7 +7,7 @@ namespace Ryujinx.HLE.Loaders.Npdm
// https://github.com/SciresM/hactool/blob/master/npdm.c // https://github.com/SciresM/hactool/blob/master/npdm.c
// https://github.com/SciresM/hactool/blob/master/npdm.h // https://github.com/SciresM/hactool/blob/master/npdm.h
// http://switchbrew.org/index.php?title=NPDM // http://switchbrew.org/index.php?title=NPDM
class Npdm public class Npdm
{ {
private const int MetaMagic = 'M' << 0 | 'E' << 8 | 'T' << 16 | 'A' << 24; private const int MetaMagic = 'M' << 0 | 'E' << 8 | 'T' << 16 | 'A' << 24;

View file

@ -5,7 +5,7 @@ using System.Text;
namespace Ryujinx.HLE.Loaders.Npdm namespace Ryujinx.HLE.Loaders.Npdm
{ {
class ServiceAccessControl public class ServiceAccessControl
{ {
public IReadOnlyDictionary<string, bool> Services { get; private set; } public IReadOnlyDictionary<string, bool> Services { get; private set; }

View file

@ -6,6 +6,7 @@ using LibHac.FsSystem.NcaUtils;
using LibHac.Spl; using LibHac.Spl;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.Loaders.Npdm;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -80,7 +81,8 @@ namespace Ryujinx.UI
{ {
if ((Path.GetExtension(app) == ".xci") || if ((Path.GetExtension(app) == ".xci") ||
(Path.GetExtension(app) == ".nro") || (Path.GetExtension(app) == ".nro") ||
(Path.GetExtension(app) == ".nso")) (Path.GetExtension(app) == ".nso") ||
(Path.GetFileName(app) == "hbl.nsp"))
{ {
applications.Add(app); applications.Add(app);
numApplicationsFound++; numApplicationsFound++;
@ -141,10 +143,10 @@ namespace Ryujinx.UI
foreach (string applicationPath in applications) foreach (string applicationPath in applications)
{ {
double fileSize = new FileInfo(applicationPath).Length * 0.000000000931; double fileSize = new FileInfo(applicationPath).Length * 0.000000000931;
string titleName = null; string titleName = "Unknown";
string titleId = null; string titleId = "0000000000000000";
string developer = null; string developer = "Unknown";
string version = null; string version = "?";
byte[] applicationIcon = null; byte[] applicationIcon = null;
using (FileStream file = new FileStream(applicationPath, FileMode.Open, FileAccess.Read)) using (FileStream file = new FileStream(applicationPath, FileMode.Open, FileAccess.Read))
@ -155,20 +157,39 @@ namespace Ryujinx.UI
{ {
try try
{ {
IFileSystem controlFs; PartitionFileSystem pfs;
// Store the ControlFS in variable called controlFs
if (Path.GetExtension(applicationPath) == ".xci") if (Path.GetExtension(applicationPath) == ".xci")
{ {
Xci xci = new Xci(_keySet, file.AsStorage()); Xci xci = new Xci(_keySet, file.AsStorage());
controlFs = GetControlFs(xci.OpenPartition(XciPartitionType.Secure)); pfs = xci.OpenPartition(XciPartitionType.Secure);
} }
else else
{ {
controlFs = GetControlFs(new PartitionFileSystem(file.AsStorage())); pfs = new PartitionFileSystem(file.AsStorage());
} }
// Store the ControlFS in variable called controlFs
IFileSystem controlFs = GetControlFs(pfs);
// If this is null then this is probably not a normal NSP, it's probably an ExeFS as an NSP
if (controlFs == null)
{
applicationIcon = _ryujinxNspIcon;
Result result = pfs.OpenFile(out IFile npdmFile, "/main.npdm", OpenMode.Read);
if (result != ResultFs.PathNotFound)
{
Npdm npdm = new Npdm(npdmFile.AsStream());
titleName = npdm.TitleName;
titleId = npdm.Aci0.TitleId.ToString("x16");
}
}
else
{
// Creates NACP class from the NACP file // Creates NACP class from the NACP file
controlFs.OpenFile(out IFile controlNacpFile, "/control.nacp", OpenMode.Read).ThrowIfFailure(); controlFs.OpenFile(out IFile controlNacpFile, "/control.nacp", OpenMode.Read).ThrowIfFailure();
@ -208,10 +229,12 @@ namespace Ryujinx.UI
{ {
controlFs.OpenFile(out IFile icon, $"/icon_{_desiredTitleLanguage}.dat", OpenMode.Read).ThrowIfFailure(); controlFs.OpenFile(out IFile icon, $"/icon_{_desiredTitleLanguage}.dat", OpenMode.Read).ThrowIfFailure();
using MemoryStream stream = new MemoryStream(); using (MemoryStream stream = new MemoryStream())
{
icon.AsStream().CopyTo(stream); icon.AsStream().CopyTo(stream);
applicationIcon = stream.ToArray(); applicationIcon = stream.ToArray();
} }
}
catch (HorizonResultException) catch (HorizonResultException)
{ {
foreach (DirectoryEntryEx entry in controlFs.EnumerateEntries("/", "*")) foreach (DirectoryEntryEx entry in controlFs.EnumerateEntries("/", "*"))
@ -237,27 +260,20 @@ namespace Ryujinx.UI
if (applicationIcon == null) if (applicationIcon == null)
{ {
applicationIcon = NspOrXciIcon(applicationPath); applicationIcon = Path.GetExtension(applicationPath) == ".xci" ? _ryujinxXciIcon : _ryujinxNspIcon;
}
} }
} }
} }
catch (MissingKeyException exception) catch (MissingKeyException exception)
{ {
titleName = "Unknown"; applicationIcon = Path.GetExtension(applicationPath) == ".xci" ? _ryujinxXciIcon : _ryujinxNspIcon;
titleId = "Unknown";
developer = "Unknown";
version = "?";
applicationIcon = NspOrXciIcon(applicationPath);
Logger.PrintWarning(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}"); Logger.PrintWarning(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}");
} }
catch (InvalidDataException) catch (InvalidDataException)
{ {
titleName = "Unknown"; applicationIcon = Path.GetExtension(applicationPath) == ".xci" ? _ryujinxXciIcon : _ryujinxNspIcon;
titleId = "Unknown";
developer = "Unknown";
version = "?";
applicationIcon = NspOrXciIcon(applicationPath);
Logger.PrintWarning(LogClass.Application, $"The header key is incorrect or missing and therefore the NCA header content type check has failed. Errored File: {applicationPath}"); Logger.PrintWarning(LogClass.Application, $"The header key is incorrect or missing and therefore the NCA header content type check has failed. Errored File: {applicationPath}");
} }
@ -326,50 +342,28 @@ namespace Ryujinx.UI
else else
{ {
applicationIcon = _ryujinxNroIcon; applicationIcon = _ryujinxNroIcon;
titleName = "Application";
titleId = "0000000000000000";
developer = "Unknown";
version = "?";
} }
} }
// If its an NCA or NSO we just set defaults // If its an NCA or NSO we just set defaults
else if ((Path.GetExtension(applicationPath) == ".nca") || (Path.GetExtension(applicationPath) == ".nso")) else if ((Path.GetExtension(applicationPath) == ".nca") || (Path.GetExtension(applicationPath) == ".nso"))
{ {
if (Path.GetExtension(applicationPath) == ".nca") applicationIcon = Path.GetExtension(applicationPath) == ".nca" ? _ryujinxNcaIcon : _ryujinxNsoIcon;
{ titleName = Path.GetFileNameWithoutExtension(applicationPath);
applicationIcon = _ryujinxNcaIcon;
}
else if (Path.GetExtension(applicationPath) == ".nso")
{
applicationIcon = _ryujinxNsoIcon;
}
string fileName = Path.GetFileName(applicationPath);
string fileExt = Path.GetExtension(applicationPath);
StringBuilder titlename = new StringBuilder();
titlename.Append(fileName);
titlename.Remove(fileName.Length - fileExt.Length, fileExt.Length);
titleName = titlename.ToString();
titleId = "0000000000000000";
version = "?";
developer = "Unknown";
} }
} }
(bool fav, string timePlayed, string lastPlayed) metaData = GetMetadata(titleId); (bool fav, string timePlayed, string lastPlayed) = GetMetadata(titleId);
ApplicationData data = new ApplicationData() ApplicationData data = new ApplicationData()
{ {
Favorite = metaData.fav, Favorite = fav,
Icon = applicationIcon, Icon = applicationIcon,
TitleName = titleName, TitleName = titleName,
TitleId = titleId, TitleId = titleId,
Developer = developer, Developer = developer,
Version = version, Version = version,
TimePlayed = metaData.timePlayed, TimePlayed = timePlayed,
LastPlayed = metaData.lastPlayed, LastPlayed = lastPlayed,
FileExtension = Path.GetExtension(applicationPath).ToUpper().Remove(0 ,1), FileExtension = Path.GetExtension(applicationPath).ToUpper().Remove(0 ,1),
FileSize = (fileSize < 1) ? (fileSize * 1024).ToString("0.##") + "MB" : fileSize.ToString("0.##") + "GB", FileSize = (fileSize < 1) ? (fileSize * 1024).ToString("0.##") + "MB" : fileSize.ToString("0.##") + "GB",
Path = applicationPath, Path = applicationPath,
@ -432,7 +426,7 @@ namespace Ryujinx.UI
} }
// Return the ControlFS // Return the ControlFS
return controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None); return controlNca?.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None);
} }
private static (bool fav, string timePlayed, string lastPlayed) GetMetadata(string titleId) private static (bool fav, string timePlayed, string lastPlayed) GetMetadata(string titleId)
@ -465,18 +459,6 @@ namespace Ryujinx.UI
return (_appMetadata.Favorite, ConvertSecondsToReadableString(_appMetadata.TimePlayed), _appMetadata.LastPlayed); return (_appMetadata.Favorite, ConvertSecondsToReadableString(_appMetadata.TimePlayed), _appMetadata.LastPlayed);
} }
private static byte[] NspOrXciIcon(string applicationPath)
{
if (Path.GetExtension(applicationPath) == ".xci")
{
return _ryujinxXciIcon;
}
else
{
return _ryujinxNspIcon;
}
}
private static string ConvertSecondsToReadableString(double seconds) private static string ConvertSecondsToReadableString(double seconds)
{ {
const int secondsPerMinute = 60; const int secondsPerMinute = 60;