Make sure TryGetApplicationsFromFile() doesn't throw exceptions anymore

This commit is contained in:
TSR Berry 2024-07-18 05:29:15 +02:00
commit c00e4bdebb
No known key found for this signature in database
GPG key ID: 52353C0A4CCA15E2

View file

@ -86,29 +86,22 @@ namespace Ryujinx.UI.App.Common
using UniqueRef<IFile> npdmFile = new(); using UniqueRef<IFile> npdmFile = new();
try Result result = pfs.OpenFile(ref npdmFile.Ref, "/main.npdm".ToU8Span(), OpenMode.Read);
if (ResultFs.PathNotFound.Includes(result))
{ {
Result result = pfs.OpenFile(ref npdmFile.Ref, "/main.npdm".ToU8Span(), OpenMode.Read); Npdm npdm = new(npdmFile.Get.AsStream());
if (ResultFs.PathNotFound.Includes(result)) data.Name = npdm.TitleName;
{ data.Id = npdm.Aci0.TitleId;
Npdm npdm = new(npdmFile.Get.AsStream());
data.Name = npdm.TitleName;
data.Id = npdm.Aci0.TitleId;
}
return data;
} }
catch (Exception exception)
{
Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. File: '{filePath}' Error: {exception.Message}");
return null; return data;
}
} }
/// <exception cref="MissingKeyException">The configured key set is missing a key.</exception> /// <exception cref="MissingKeyException">The configured key set is missing a key.</exception>
/// <exception cref="InvalidDataException">The NCA header could not be decrypted.</exception>
/// <exception cref="NotSupportedException">The NCA version is not supported.</exception>
/// <exception cref="HorizonResultException">An error occured while reading PFS data.</exception> /// <exception cref="HorizonResultException">An error occured while reading PFS data.</exception>
/// <exception cref="Ryujinx.HLE.Exceptions.InvalidNpdmException">The npdm file doesn't contain valid data.</exception> /// <exception cref="Ryujinx.HLE.Exceptions.InvalidNpdmException">The npdm file doesn't contain valid data.</exception>
/// <exception cref="NotImplementedException">The FsAccessHeader.ContentOwnerId section is not implemented.</exception> /// <exception cref="NotImplementedException">The FsAccessHeader.ContentOwnerId section is not implemented.</exception>
@ -182,99 +175,88 @@ namespace Ryujinx.UI.App.Common
return null; return null;
} }
/// <exception cref="MissingKeyException">The configured key set is missing a key.</exception>
/// <exception cref="InvalidDataException">The NCA header could not be decrypted.</exception>
/// <exception cref="NotSupportedException">The NCA version is not supported.</exception>
/// <exception cref="HorizonResultException">An error occured while reading PFS data.</exception>
private List<ApplicationData> GetApplicationsFromPfs(IFileSystem pfs, string filePath) private List<ApplicationData> GetApplicationsFromPfs(IFileSystem pfs, string filePath)
{ {
var applications = new List<ApplicationData>(); var applications = new List<ApplicationData>();
string extension = Path.GetExtension(filePath).ToLower(); string extension = Path.GetExtension(filePath).ToLower();
try foreach ((ulong titleId, ContentMetaData content) in pfs.GetContentData(ContentMetaType.Application, _virtualFileSystem, _checkLevel))
{ {
foreach ((ulong titleId, ContentMetaData content) in pfs.GetContentData(ContentMetaType.Application, _virtualFileSystem, _checkLevel)) ApplicationData applicationData = new()
{ {
ApplicationData applicationData = new() Id = titleId,
Path = filePath,
};
Nca mainNca = content.GetNcaByType(_virtualFileSystem.KeySet, ContentType.Program);
Nca controlNca = content.GetNcaByType(_virtualFileSystem.KeySet, ContentType.Control);
BlitStruct<ApplicationControlProperty> controlHolder = new(1);
IFileSystem controlFs = controlNca?.OpenFileSystem(NcaSectionType.Data, _checkLevel);
// Check if there is an update available.
if (IsUpdateApplied(mainNca, out IFileSystem updatedControlFs))
{
// Replace the original ControlFs by the updated one.
controlFs = updatedControlFs;
}
if (controlFs == null)
{
continue;
}
ReadControlData(controlFs, controlHolder.ByteSpan);
GetApplicationInformation(ref controlHolder.Value, ref applicationData);
// Read the icon from the ControlFS and store it as a byte array
try
{
using UniqueRef<IFile> icon = new();
controlFs.OpenFile(ref icon.Ref, $"/icon_{_desiredTitleLanguage}.dat".ToU8Span(), OpenMode.Read).ThrowIfFailure();
using MemoryStream stream = new();
icon.Get.AsStream().CopyTo(stream);
applicationData.Icon = stream.ToArray();
}
catch (HorizonResultException)
{
foreach (DirectoryEntryEx entry in controlFs.EnumerateEntries("/", "*"))
{ {
Id = titleId, if (entry.Name == "control.nacp")
Path = filePath, {
}; continue;
}
Nca mainNca = content.GetNcaByType(_virtualFileSystem.KeySet, ContentType.Program); using var icon = new UniqueRef<IFile>();
Nca controlNca = content.GetNcaByType(_virtualFileSystem.KeySet, ContentType.Control);
BlitStruct<ApplicationControlProperty> controlHolder = new(1); controlFs.OpenFile(ref icon.Ref, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
IFileSystem controlFs = controlNca?.OpenFileSystem(NcaSectionType.Data, _checkLevel);
// Check if there is an update available.
if (IsUpdateApplied(mainNca, out IFileSystem updatedControlFs))
{
// Replace the original ControlFs by the updated one.
controlFs = updatedControlFs;
}
if (controlFs == null)
{
continue;
}
ReadControlData(controlFs, controlHolder.ByteSpan);
GetApplicationInformation(ref controlHolder.Value, ref applicationData);
// Read the icon from the ControlFS and store it as a byte array
try
{
using UniqueRef<IFile> icon = new();
controlFs.OpenFile(ref icon.Ref, $"/icon_{_desiredTitleLanguage}.dat".ToU8Span(), OpenMode.Read).ThrowIfFailure();
using MemoryStream stream = new(); using MemoryStream stream = new();
icon.Get.AsStream().CopyTo(stream); icon.Get.AsStream().CopyTo(stream);
applicationData.Icon = stream.ToArray(); applicationData.Icon = stream.ToArray();
}
catch (HorizonResultException) if (applicationData.Icon != null)
{
foreach (DirectoryEntryEx entry in controlFs.EnumerateEntries("/", "*"))
{ {
if (entry.Name == "control.nacp") break;
{
continue;
}
using var icon = new UniqueRef<IFile>();
controlFs.OpenFile(ref icon.Ref, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
using MemoryStream stream = new();
icon.Get.AsStream().CopyTo(stream);
applicationData.Icon = stream.ToArray();
if (applicationData.Icon != null)
{
break;
}
} }
applicationData.Icon ??= extension == ".xci" ? _xciIcon : _nspIcon;
} }
applicationData.ControlHolder = controlHolder; applicationData.Icon ??= extension == ".xci" ? _xciIcon : _nspIcon;
applications.Add(applicationData);
} }
}
catch (MissingKeyException exception) applicationData.ControlHolder = controlHolder;
{
Logger.Warning?.Print(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}"); applications.Add(applicationData);
}
catch (InvalidDataException)
{
Logger.Warning?.Print(LogClass.Application, $"The header key is incorrect or missing and therefore the NCA header content type check has failed. Errored File: {filePath}");
}
catch (Exception exception)
{
Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. File: '{filePath}' Error: {exception}");
} }
return applications; return applications;
@ -331,52 +313,43 @@ namespace Ryujinx.UI.App.Common
BinaryReader reader = new(file); BinaryReader reader = new(file);
ApplicationData application = new(); ApplicationData application = new();
try file.Seek(24, SeekOrigin.Begin);
int assetOffset = reader.ReadInt32();
if (Encoding.ASCII.GetString(Read(assetOffset, 4)) == "ASET")
{ {
file.Seek(24, SeekOrigin.Begin); byte[] iconSectionInfo = Read(assetOffset + 8, 0x10);
int assetOffset = reader.ReadInt32(); long iconOffset = BitConverter.ToInt64(iconSectionInfo, 0);
long iconSize = BitConverter.ToInt64(iconSectionInfo, 8);
if (Encoding.ASCII.GetString(Read(assetOffset, 4)) == "ASET") ulong nacpOffset = reader.ReadUInt64();
ulong nacpSize = reader.ReadUInt64();
// Reads and stores game icon as byte array
if (iconSize > 0)
{ {
byte[] iconSectionInfo = Read(assetOffset + 8, 0x10); application.Icon = Read(assetOffset + iconOffset, (int)iconSize);
long iconOffset = BitConverter.ToInt64(iconSectionInfo, 0);
long iconSize = BitConverter.ToInt64(iconSectionInfo, 8);
ulong nacpOffset = reader.ReadUInt64();
ulong nacpSize = reader.ReadUInt64();
// Reads and stores game icon as byte array
if (iconSize > 0)
{
application.Icon = Read(assetOffset + iconOffset, (int)iconSize);
}
else
{
application.Icon = _nroIcon;
}
// Read the NACP data
Read(assetOffset + (int)nacpOffset, (int)nacpSize).AsSpan().CopyTo(controlHolder.ByteSpan);
GetApplicationInformation(ref controlHolder.Value, ref application);
} }
else else
{ {
application.Icon = _nroIcon; application.Icon = _nroIcon;
application.Name = Path.GetFileNameWithoutExtension(applicationPath);
} }
application.ControlHolder = controlHolder; // Read the NACP data
applications.Add(application); Read(assetOffset + (int)nacpOffset, (int)nacpSize).AsSpan().CopyTo(controlHolder.ByteSpan);
}
catch
{
Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. Errored File: {applicationPath}");
return false; GetApplicationInformation(ref controlHolder.Value, ref application);
} }
else
{
application.Icon = _nroIcon;
application.Name = Path.GetFileNameWithoutExtension(applicationPath);
}
application.ControlHolder = controlHolder;
applications.Add(application);
break; break;
@ -389,34 +362,21 @@ namespace Ryujinx.UI.App.Common
} }
case ".nca": case ".nca":
{ {
try ApplicationData application = new();
Nca nca = new(_virtualFileSystem.KeySet, new FileStream(applicationPath, FileMode.Open, FileAccess.Read).AsStorage());
if (!nca.IsProgram() || nca.IsPatch())
{ {
ApplicationData application = new();
Nca nca = new(_virtualFileSystem.KeySet, new FileStream(applicationPath, FileMode.Open, FileAccess.Read).AsStorage());
if (!nca.IsProgram() || nca.IsPatch())
{
return false;
}
application.Icon = _ncaIcon;
application.Name = Path.GetFileNameWithoutExtension(applicationPath);
application.ControlHolder = controlHolder;
applications.Add(application);
}
catch (InvalidDataException)
{
Logger.Warning?.Print(LogClass.Application, $"The NCA header content type check has failed. This is usually because the header key is incorrect or missing. Errored File: {applicationPath}");
}
catch
{
Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. Errored File: {applicationPath}");
return false; return false;
} }
application.Icon = _ncaIcon;
application.Name = Path.GetFileNameWithoutExtension(applicationPath);
application.ControlHolder = controlHolder;
applications.Add(application);
break; break;
} }
// If its an NSO we just set defaults // If its an NSO we just set defaults
@ -434,12 +394,30 @@ namespace Ryujinx.UI.App.Common
} }
} }
} }
catch (MissingKeyException exception)
{
Logger.Warning?.Print(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}");
return false;
}
catch (InvalidDataException)
{
Logger.Warning?.Print(LogClass.Application, $"The header key is incorrect or missing and therefore the NCA header content type check has failed. Errored File: {applicationPath}");
return false;
}
catch (IOException exception) catch (IOException exception)
{ {
Logger.Warning?.Print(LogClass.Application, exception.Message); Logger.Warning?.Print(LogClass.Application, exception.Message);
return false; return false;
} }
catch (Exception exception)
{
Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. File: '{applicationPath}' Error: {exception}");
return false;
}
foreach (var data in applications) foreach (var data in applications)
{ {