From c00e4bdebbc6258de786e245ed9c45318b7b8df8 Mon Sep 17 00:00:00 2001 From: TSR Berry <20988865+TSRBerry@users.noreply.github.com> Date: Thu, 18 Jul 2024 05:29:15 +0200 Subject: [PATCH] Make sure TryGetApplicationsFromFile() doesn't throw exceptions anymore --- .../App/ApplicationLibrary.cs | 272 ++++++++---------- 1 file changed, 125 insertions(+), 147 deletions(-) diff --git a/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs b/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs index 9a548138c7..f1dd83e35a 100644 --- a/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs +++ b/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs @@ -86,29 +86,22 @@ namespace Ryujinx.UI.App.Common using UniqueRef 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)) - { - Npdm npdm = new(npdmFile.Get.AsStream()); - - data.Name = npdm.TitleName; - data.Id = npdm.Aci0.TitleId; - } - - return data; + data.Name = npdm.TitleName; + data.Id = npdm.Aci0.TitleId; } - 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; } /// The configured key set is missing a key. + /// The NCA header could not be decrypted. + /// The NCA version is not supported. /// An error occured while reading PFS data. /// The npdm file doesn't contain valid data. /// The FsAccessHeader.ContentOwnerId section is not implemented. @@ -182,99 +175,88 @@ namespace Ryujinx.UI.App.Common return null; } + /// The configured key set is missing a key. + /// The NCA header could not be decrypted. + /// The NCA version is not supported. + /// An error occured while reading PFS data. private List GetApplicationsFromPfs(IFileSystem pfs, string filePath) { var applications = new List(); 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 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 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, - Path = filePath, - }; + if (entry.Name == "control.nacp") + { + continue; + } - Nca mainNca = content.GetNcaByType(_virtualFileSystem.KeySet, ContentType.Program); - Nca controlNca = content.GetNcaByType(_virtualFileSystem.KeySet, ContentType.Control); + using var icon = new UniqueRef(); - BlitStruct 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 icon = new(); - - controlFs.OpenFile(ref icon.Ref, $"/icon_{_desiredTitleLanguage}.dat".ToU8Span(), OpenMode.Read).ThrowIfFailure(); + controlFs.OpenFile(ref icon.Ref, entry.FullPath.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("/", "*")) + + if (applicationData.Icon != null) { - if (entry.Name == "control.nacp") - { - continue; - } - - using var icon = new UniqueRef(); - - 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; - } + break; } - - applicationData.Icon ??= extension == ".xci" ? _xciIcon : _nspIcon; } - applicationData.ControlHolder = controlHolder; - - applications.Add(applicationData); + applicationData.Icon ??= extension == ".xci" ? _xciIcon : _nspIcon; } - } - catch (MissingKeyException exception) - { - Logger.Warning?.Print(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}"); - } - 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}"); + + applicationData.ControlHolder = controlHolder; + + applications.Add(applicationData); } return applications; @@ -331,52 +313,43 @@ namespace Ryujinx.UI.App.Common BinaryReader reader = new(file); 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); - - 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); + application.Icon = Read(assetOffset + iconOffset, (int)iconSize); } else { application.Icon = _nroIcon; - application.Name = Path.GetFileNameWithoutExtension(applicationPath); } - application.ControlHolder = controlHolder; - applications.Add(application); - } - catch - { - Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. Errored File: {applicationPath}"); + // Read the NACP data + Read(assetOffset + (int)nacpOffset, (int)nacpSize).AsSpan().CopyTo(controlHolder.ByteSpan); - return false; + GetApplicationInformation(ref controlHolder.Value, ref application); } + else + { + application.Icon = _nroIcon; + application.Name = Path.GetFileNameWithoutExtension(applicationPath); + } + + application.ControlHolder = controlHolder; + applications.Add(application); break; @@ -389,34 +362,21 @@ namespace Ryujinx.UI.App.Common } 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; } + application.Icon = _ncaIcon; + application.Name = Path.GetFileNameWithoutExtension(applicationPath); + application.ControlHolder = controlHolder; + + applications.Add(application); + break; } // 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) { Logger.Warning?.Print(LogClass.Application, exception.Message); 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) {