diff --git a/src/Ryujinx.HLE/Loaders/Npdm/ACI0.cs b/src/Ryujinx.HLE/Loaders/Npdm/ACI0.cs
index 9a5b6b0a..8d828e8e 100644
--- a/src/Ryujinx.HLE/Loaders/Npdm/ACI0.cs
+++ b/src/Ryujinx.HLE/Loaders/Npdm/ACI0.cs
@@ -15,6 +15,12 @@ namespace Ryujinx.HLE.Loaders.Npdm
public ServiceAccessControl ServiceAccessControl { get; private set; }
public KernelAccessControl KernelAccessControl { get; private set; }
+ /// The stream doesn't contain valid ACI0 data.
+ /// The stream does not support reading, is , or is already closed.
+ /// The end of the stream is reached.
+ /// The stream is closed.
+ /// An I/O error occurred.
+ /// The FsAccessHeader.ContentOwnerId section is not implemented.
public Aci0(Stream stream, int offset)
{
stream.Seek(offset, SeekOrigin.Begin);
diff --git a/src/Ryujinx.HLE/Loaders/Npdm/ACID.cs b/src/Ryujinx.HLE/Loaders/Npdm/ACID.cs
index ab30b40c..57d0ee27 100644
--- a/src/Ryujinx.HLE/Loaders/Npdm/ACID.cs
+++ b/src/Ryujinx.HLE/Loaders/Npdm/ACID.cs
@@ -19,6 +19,11 @@ namespace Ryujinx.HLE.Loaders.Npdm
public ServiceAccessControl ServiceAccessControl { get; private set; }
public KernelAccessControl KernelAccessControl { get; private set; }
+ /// The stream doesn't contain valid ACID data.
+ /// The stream does not support reading, is , or is already closed.
+ /// The end of the stream is reached.
+ /// The stream is closed.
+ /// An I/O error occurred.
public Acid(Stream stream, int offset)
{
stream.Seek(offset, SeekOrigin.Begin);
diff --git a/src/Ryujinx.HLE/Loaders/Npdm/FsAccessControl.cs b/src/Ryujinx.HLE/Loaders/Npdm/FsAccessControl.cs
index f17ca348..a369f9f2 100644
--- a/src/Ryujinx.HLE/Loaders/Npdm/FsAccessControl.cs
+++ b/src/Ryujinx.HLE/Loaders/Npdm/FsAccessControl.cs
@@ -11,6 +11,10 @@ namespace Ryujinx.HLE.Loaders.Npdm
public int Unknown3 { get; private set; }
public int Unknown4 { get; private set; }
+ /// The stream does not support reading, is , or is already closed.
+ /// The end of the stream is reached.
+ /// The stream is closed.
+ /// An I/O error occurred.
public FsAccessControl(Stream stream, int offset, int size)
{
stream.Seek(offset, SeekOrigin.Begin);
diff --git a/src/Ryujinx.HLE/Loaders/Npdm/FsAccessHeader.cs b/src/Ryujinx.HLE/Loaders/Npdm/FsAccessHeader.cs
index 5987be0e..249f8dd9 100644
--- a/src/Ryujinx.HLE/Loaders/Npdm/FsAccessHeader.cs
+++ b/src/Ryujinx.HLE/Loaders/Npdm/FsAccessHeader.cs
@@ -9,6 +9,12 @@ namespace Ryujinx.HLE.Loaders.Npdm
public int Version { get; private set; }
public ulong PermissionsBitmask { get; private set; }
+ /// The stream contains invalid data.
+ /// The ContentOwnerId section is not implemented.
+ /// The stream does not support reading, is , or is already closed.
+ /// The end of the stream is reached.
+ /// The stream is closed.
+ /// An I/O error occurred.
public FsAccessHeader(Stream stream, int offset, int size)
{
stream.Seek(offset, SeekOrigin.Begin);
diff --git a/src/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs b/src/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs
index 17124379..979c6f66 100644
--- a/src/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs
+++ b/src/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs
@@ -6,6 +6,10 @@ namespace Ryujinx.HLE.Loaders.Npdm
{
public int[] Capabilities { get; private set; }
+ /// The stream does not support reading, is , or is already closed.
+ /// The end of the stream is reached.
+ /// The stream is closed.
+ /// An I/O error occurred.
public KernelAccessControl(Stream stream, int offset, int size)
{
stream.Seek(offset, SeekOrigin.Begin);
diff --git a/src/Ryujinx.HLE/Loaders/Npdm/Npdm.cs b/src/Ryujinx.HLE/Loaders/Npdm/Npdm.cs
index 622d7ee0..4a99de98 100644
--- a/src/Ryujinx.HLE/Loaders/Npdm/Npdm.cs
+++ b/src/Ryujinx.HLE/Loaders/Npdm/Npdm.cs
@@ -24,6 +24,13 @@ namespace Ryujinx.HLE.Loaders.Npdm
public Aci0 Aci0 { get; private set; }
public Acid Acid { get; private set; }
+ /// The stream doesn't contain valid NPDM data.
+ /// The FsAccessHeader.ContentOwnerId section is not implemented.
+ /// The stream does not support reading, is , or is already closed.
+ /// An error occured while reading bytes from the stream.
+ /// The end of the stream is reached.
+ /// The stream is closed.
+ /// An I/O error occurred.
public Npdm(Stream stream)
{
BinaryReader reader = new(stream);
diff --git a/src/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs b/src/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs
index bb6df27f..b6bc6492 100644
--- a/src/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs
+++ b/src/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs
@@ -9,6 +9,11 @@ namespace Ryujinx.HLE.Loaders.Npdm
{
public IReadOnlyDictionary Services { get; private set; }
+ /// The stream does not support reading, is , or is already closed.
+ /// An error occured while reading bytes from the stream.
+ /// The end of the stream is reached.
+ /// The stream is closed.
+ /// An I/O error occurred.
public ServiceAccessControl(Stream stream, int offset, int size)
{
stream.Seek(offset, SeekOrigin.Begin);
diff --git a/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs b/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs
index 2baf0608..e7c48162 100644
--- a/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs
+++ b/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs
@@ -72,37 +72,43 @@ namespace Ryujinx.UI.App.Common
return resourceByteArray;
}
+ /// The npdm file doesn't contain valid data.
+ /// The FsAccessHeader.ContentOwnerId section is not implemented.
+ /// An error occured while reading bytes from the stream.
+ /// The end of the stream is reached.
+ /// An I/O error occurred.
private ApplicationData GetApplicationFromExeFs(PartitionFileSystem pfs, string filePath)
{
ApplicationData data = new()
{
Icon = _nspIcon,
+ Path = filePath,
};
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.
+ /// An error occured while reading bytes from the stream.
+ /// The end of the stream is reached.
+ /// An I/O error occurred.
private ApplicationData GetApplicationFromNsp(PartitionFileSystem pfs, string filePath)
{
bool isExeFs = false;
@@ -170,99 +176,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;
@@ -319,52 +314,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;
@@ -377,34 +363,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
@@ -417,16 +390,35 @@ namespace Ryujinx.UI.App.Common
};
applications.Add(application);
+
break;
}
}
}
+ 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)
{