From 5f3558fd51a0920966e5341101c4233a02c98307 Mon Sep 17 00:00:00 2001
From: Xpl0itR <xpl0itr@outlook.com>
Date: Sun, 3 May 2020 00:43:22 +0100
Subject: [PATCH] catch key errors (#1157)

---
 Ryujinx/Ui/ApplicationLibrary.cs | 45 ++++++++++++++-------
 Ryujinx/Ui/TitleUpdateWindow.cs  | 67 ++++++++++++++++++++++----------
 2 files changed, 77 insertions(+), 35 deletions(-)

diff --git a/Ryujinx/Ui/ApplicationLibrary.cs b/Ryujinx/Ui/ApplicationLibrary.cs
index b4700300a8..02b6541f95 100644
--- a/Ryujinx/Ui/ApplicationLibrary.cs
+++ b/Ryujinx/Ui/ApplicationLibrary.cs
@@ -84,7 +84,7 @@ namespace Ryujinx.Ui
         public static void ReadControlData(IFileSystem controlFs, Span<byte> outProperty)
         {
             controlFs.OpenFile(out IFile controlFile, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
-            controlFile.Read(out long _, 0, outProperty, ReadOption.None).ThrowIfFailure();
+            controlFile.Read(out _, 0, outProperty, ReadOption.None).ThrowIfFailure();
         }
 
         public static void LoadApplications(List<string> appDirs, VirtualFileSystem virtualFileSystem, Language desiredTitleLanguage)
@@ -677,24 +677,41 @@ namespace Ryujinx.Ui
                     {
                         nsp.OpenFile(out IFile ncaFile, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
 
-                        Nca nca = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage());
-
-                        if ($"{nca.Header.TitleId.ToString("x16")[..^3]}000" != titleId)
+                        try
                         {
+                            Nca nca = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage());
+
+                            if ($"{nca.Header.TitleId.ToString("x16")[..^3]}000" != titleId)
+                            {
+                                break;
+                            }
+
+                            if (nca.Header.ContentType == NcaContentType.Control)
+                            {
+                                ApplicationControlProperty controlData = new ApplicationControlProperty();
+
+                                nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(out IFile nacpFile, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
+
+                                nacpFile.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
+
+                                version = controlData.DisplayVersion.ToString();
+
+                                return true;
+                            }
+                        }
+                        catch (InvalidDataException)
+                        {
+                            Logger.PrintWarning(LogClass.Application,
+                                $"The header key is incorrect or missing and therefore the NCA header content type check has failed. Errored File: {updatePath}");
+
                             break;
                         }
-
-                        if (nca.Header.ContentType == NcaContentType.Control)
+                        catch (MissingKeyException exception)
                         {
-                            ApplicationControlProperty controlData = new ApplicationControlProperty();
+                            Logger.PrintWarning(LogClass.Application,
+                                $"Your key set is missing a key with the name: {exception.Name}. Errored File: {updatePath}");
 
-                            nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(out IFile nacpFile, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
-
-                            nacpFile.Read(out long _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
-
-                            version = controlData.DisplayVersion.ToString();
-
-                            return true;
+                            break;
                         }
                     }
                 }
diff --git a/Ryujinx/Ui/TitleUpdateWindow.cs b/Ryujinx/Ui/TitleUpdateWindow.cs
index a6d64a793f..6808b4da62 100644
--- a/Ryujinx/Ui/TitleUpdateWindow.cs
+++ b/Ryujinx/Ui/TitleUpdateWindow.cs
@@ -7,6 +7,7 @@ using LibHac.FsSystem.NcaUtils;
 using LibHac.Ns;
 using LibHac.Spl;
 using Ryujinx.Common.Configuration;
+using Ryujinx.Common.Logging;
 using Ryujinx.HLE.FileSystem;
 using System;
 using System.Collections.Generic;
@@ -25,13 +26,11 @@ namespace Ryujinx.Ui
         private TitleUpdateMetadata _titleUpdateWindowData;
         private Dictionary<RadioButton, string> _radioButtonToPathDictionary = new Dictionary<RadioButton, string>();
 
-#pragma warning disable CS0649
-#pragma warning disable IDE0044
+#pragma warning disable CS0649, IDE0044
         [GUI] Label       _baseTitleInfoLabel;
         [GUI] Box         _availableUpdatesBox;
         [GUI] RadioButton _noUpdateRadioButton;
-#pragma warning restore CS0649
-#pragma warning restore IDE0044
+#pragma warning restore CS0649, IDE0044
 
         public TitleUpdateWindow(string titleId, string titleName, VirtualFileSystem virtualFileSystem) : this(new Builder("Ryujinx.Ui.TitleUpdateWindow.glade"), titleId, titleName, virtualFileSystem) { }
 
@@ -61,7 +60,7 @@ namespace Ryujinx.Ui
 
             foreach (string path in _titleUpdateWindowData.Paths)
             {
-                AddUpdate(path);
+                AddUpdate(path, false);
             }
 
             _noUpdateRadioButton.Active = true;
@@ -74,7 +73,7 @@ namespace Ryujinx.Ui
             }
         }
 
-        private void AddUpdate(string path)
+        private void AddUpdate(string path, bool showErrorDialog = true)
         {
             if (File.Exists(path))
             {
@@ -98,30 +97,56 @@ namespace Ryujinx.Ui
                     {
                         nsp.OpenFile(out IFile ncaFile, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
 
-                        Nca nca = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage());
-
-                        if ($"{nca.Header.TitleId.ToString("x16")[..^3]}000" == _titleId)
+                        try
                         {
-                            if (nca.Header.ContentType == NcaContentType.Control)
+                            Nca nca = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage());
+
+                            if ($"{nca.Header.TitleId.ToString("x16")[..^3]}000" == _titleId)
                             {
-                                ApplicationControlProperty controlData = new ApplicationControlProperty();
+                                if (nca.Header.ContentType == NcaContentType.Control)
+                                {
+                                    ApplicationControlProperty controlData = new ApplicationControlProperty();
 
-                                nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(out IFile nacpFile, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
-                                nacpFile.Read(out long _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
+                                    nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(out IFile nacpFile, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
+                                    nacpFile.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
 
-                                RadioButton radioButton = new RadioButton($"Version {controlData.DisplayVersion.ToString()} - {path}");
-                                radioButton.JoinGroup(_noUpdateRadioButton);
+                                    RadioButton radioButton = new RadioButton($"Version {controlData.DisplayVersion.ToString()} - {path}");
+                                    radioButton.JoinGroup(_noUpdateRadioButton);
 
-                                _availableUpdatesBox.Add(radioButton);
-                                _radioButtonToPathDictionary.Add(radioButton, path);
+                                    _availableUpdatesBox.Add(radioButton);
+                                    _radioButtonToPathDictionary.Add(radioButton, path);
 
-                                radioButton.Show();
-                                radioButton.Active = true;
+                                    radioButton.Show();
+                                    radioButton.Active = true;
+                                }
+                            }
+                            else
+                            {
+                                GtkDialog.CreateErrorDialog("The specified file does not contain an update for the selected title!");
+                                
+                                break;
                             }
                         }
-                        else
+                        catch (InvalidDataException exception)
                         {
-                            GtkDialog.CreateErrorDialog("The specified file does not contain an update for the selected title!");
+                            Logger.PrintError(LogClass.Application, $"{exception.Message}. Errored File: {path}");
+
+                            if (showErrorDialog)
+                            {
+                                GtkDialog.CreateDialog("Ryujinx - Error", "Add Update Failed!", "The NCA header content type check has failed. This is usually because the header key is incorrect or missing.");
+                            }
+                            
+                            break;
+                        }
+                        catch (MissingKeyException exception)
+                        {
+                            Logger.PrintError(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}. Errored File: {path}");
+
+                            if (showErrorDialog)
+                            {
+                                GtkDialog.CreateDialog("Ryujinx - Error", "Add Update Failed!", $"Your key set is missing a key with the name: {exception.Name}");
+                            }
+
                             break;
                         }
                     }