diff --git a/src/Ryujinx.HLE/FileSystem/ContentManager.cs b/src/Ryujinx.HLE/FileSystem/ContentManager.cs index fc8def9d2..51f6058fc 100644 --- a/src/Ryujinx.HLE/FileSystem/ContentManager.cs +++ b/src/Ryujinx.HLE/FileSystem/ContentManager.cs @@ -21,6 +21,7 @@ using System.IO; using System.IO.Compression; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using Path = System.IO.Path; namespace Ryujinx.HLE.FileSystem @@ -474,6 +475,74 @@ namespace Ryujinx.HLE.FileSystem FinishInstallation(temporaryDirectory, registeredDirectory); } + public void InstallKeys(string keysSource, string installDirectory) + { + if (Directory.Exists(keysSource)) + { + foreach (var filePath in Directory.EnumerateFiles(keysSource, "*.keys")) + { + VerifyKeysFile(filePath); + File.Copy(filePath, Path.Combine(installDirectory, Path.GetFileName(filePath)), true); + } + + return; + } + + if (!File.Exists(keysSource)) + { + throw new FileNotFoundException("Keys file does not exist."); + } + + FileInfo info = new(keysSource); + + using FileStream file = File.OpenRead(keysSource); + + switch (info.Extension) + { + case ".zip": + using (ZipArchive archive = ZipFile.OpenRead(keysSource)) + { + InstallKeysFromZip(archive, installDirectory); + } + break; + case ".keys": + VerifyKeysFile(keysSource); + File.Copy(keysSource, Path.Combine(installDirectory, info.Name), true); + break; + default: + throw new InvalidFirmwarePackageException("Input file is not a valid key package"); + } + } + + private void InstallKeysFromZip(ZipArchive archive, string installDirectory) + { + string temporaryDirectory = Path.Combine(installDirectory, "temp"); + if (Directory.Exists(temporaryDirectory)) + { + Directory.Delete(temporaryDirectory, true); + } + Directory.CreateDirectory(temporaryDirectory); + foreach (var entry in archive.Entries) + { + if (Path.GetExtension(entry.FullName).Equals(".keys", StringComparison.OrdinalIgnoreCase)) + { + string extractDestination = Path.Combine(temporaryDirectory, entry.Name); + entry.ExtractToFile(extractDestination, overwrite: true); + try + { + VerifyKeysFile(extractDestination); + File.Move(extractDestination, Path.Combine(installDirectory, entry.Name), true); + } + catch (Exception) + { + Directory.Delete(temporaryDirectory, true); + throw; + } + } + } + Directory.Delete(temporaryDirectory, true); + } + private void FinishInstallation(string temporaryDirectory, string registeredDirectory) { if (Directory.Exists(registeredDirectory)) @@ -947,5 +1016,70 @@ namespace Ryujinx.HLE.FileSystem return null; } + + public void VerifyKeysFile(string filePath) + { + // Verify the keys file format refers to https://github.com/Thealexbarney/LibHac/blob/master/KEYS.md + string genericPattern = @"^[a-z0-9_]+ = [a-z0-9]+$"; + string titlePattern = @"^[a-z0-9]{32} = [a-z0-9]{32}$"; + + if (File.Exists(filePath)) + { + // Read all lines from the file + string fileName = Path.GetFileName(filePath); + string[] lines = File.ReadAllLines(filePath); + + bool verified = false; + switch (fileName) + { + case "prod.keys": + verified = verifyKeys(lines, genericPattern); + break; + case "title.keys": + verified = verifyKeys(lines, titlePattern); + break; + case "console.keys": + verified = verifyKeys(lines, genericPattern); + break; + case "dev.keys": + verified = verifyKeys(lines, genericPattern); + break; + default: + throw new FormatException($"Keys file name \"{fileName}\" not supported. Only \"prod.keys\", \"title.keys\", \"console.keys\", \"dev.keys\" are supported."); + } + if (!verified) + { + throw new FormatException($"Invalid \"{filePath}\" file format."); + } + } else + { + throw new FileNotFoundException($"Keys file not found at \"{filePath}\"."); + } + } + + private bool verifyKeys(string[] lines, string regex) + { + foreach (string line in lines) + { + if (!Regex.IsMatch(line, regex)) + { + return false; + } + } + return true; + } + + public bool AreKeysAlredyPresent(string pathToCheck) + { + string[] fileNames = { "prod.keys", "title.keys", "console.keys", "dev.keys" }; + foreach (var file in fileNames) + { + if (File.Exists(Path.Combine(pathToCheck, file))) + { + return true; + } + } + return false; + } } } diff --git a/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs b/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs index 39c544eac..ef9c493a8 100644 --- a/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs +++ b/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs @@ -223,9 +223,10 @@ namespace Ryujinx.HLE.FileSystem { KeySet ??= KeySet.CreateDefaultKeySet(); - string keyFile = null; + string prodKeyFile = null; string titleKeyFile = null; string consoleKeyFile = null; + string devKeyFile = null; if (AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile) { @@ -236,13 +237,14 @@ namespace Ryujinx.HLE.FileSystem void LoadSetAtPath(string basePath) { - string localKeyFile = Path.Combine(basePath, "prod.keys"); + string localProdKeyFile = Path.Combine(basePath, "prod.keys"); string localTitleKeyFile = Path.Combine(basePath, "title.keys"); string localConsoleKeyFile = Path.Combine(basePath, "console.keys"); + string localDevKeyFile = Path.Combine(basePath, "dev.keys"); - if (File.Exists(localKeyFile)) + if (File.Exists(localProdKeyFile)) { - keyFile = localKeyFile; + prodKeyFile = localProdKeyFile; } if (File.Exists(localTitleKeyFile)) @@ -254,9 +256,14 @@ namespace Ryujinx.HLE.FileSystem { consoleKeyFile = localConsoleKeyFile; } + + if (File.Exists(localDevKeyFile)) + { + devKeyFile = localDevKeyFile; + } } - ExternalKeyReader.ReadKeyFile(KeySet, keyFile, titleKeyFile, consoleKeyFile, null); + ExternalKeyReader.ReadKeyFile(KeySet, prodKeyFile, devKeyFile, titleKeyFile, consoleKeyFile, null); } public void ImportTickets(IFileSystem fs) diff --git a/src/Ryujinx/Assets/Locales/ar_SA.json b/src/Ryujinx/Assets/Locales/ar_SA.json index 62992ff34..34b4f7212 100644 --- a/src/Ryujinx/Assets/Locales/ar_SA.json +++ b/src/Ryujinx/Assets/Locales/ar_SA.json @@ -31,6 +31,9 @@ "MenuBarToolsInstallFirmware": "تثبيت البرنامج الثابت", "MenuBarFileToolsInstallFirmwareFromFile": "تثبيت برنامج ثابت من XCI أو ZIP", "MenuBarFileToolsInstallFirmwareFromDirectory": "تثبيت برنامج ثابت من مجلد", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "إدارة أنواع الملفات", "MenuBarToolsInstallFileTypes": "تثبيت أنواع الملفات", "MenuBarToolsUninstallFileTypes": "إزالة أنواع الملفات", @@ -506,6 +509,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\nهل تريد المتابعة؟", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "تثبيت البرنامج الثابت...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "تم تثبيت إصدار النظام {0} بنجاح.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "لن تكون هناك ملفات الشخصية أخرى لفتحها إذا تم حذف الملف الشخصي المحدد", "DialogUserProfileDeletionConfirmMessage": "هل تريد حذف الملف الشخصي المحدد", "DialogUserProfileUnsavedChangesTitle": "تحذير - التغييرات غير محفوظة", diff --git a/src/Ryujinx/Assets/Locales/de_DE.json b/src/Ryujinx/Assets/Locales/de_DE.json index 91141b7af..013120738 100644 --- a/src/Ryujinx/Assets/Locales/de_DE.json +++ b/src/Ryujinx/Assets/Locales/de_DE.json @@ -31,6 +31,9 @@ "MenuBarToolsInstallFirmware": "Firmware installieren", "MenuBarFileToolsInstallFirmwareFromFile": "Firmware von einer XCI- oder einer ZIP-Datei installieren", "MenuBarFileToolsInstallFirmwareFromDirectory": "Firmware aus einem Verzeichnis installieren", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "Dateitypen verwalten", "MenuBarToolsInstallFileTypes": "Dateitypen installieren", "MenuBarToolsUninstallFileTypes": "Dateitypen deinstallieren", @@ -506,6 +509,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nMöchtest du fortfahren?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Firmware wird installiert...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Systemversion {0} wurde erfolgreich installiert.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "Es können keine anderen Profile geöffnet werden, wenn das ausgewählte Profil gelöscht wird.", "DialogUserProfileDeletionConfirmMessage": "Möchtest du das ausgewählte Profil löschen?", "DialogUserProfileUnsavedChangesTitle": "Warnung - Nicht gespeicherte Änderungen", diff --git a/src/Ryujinx/Assets/Locales/el_GR.json b/src/Ryujinx/Assets/Locales/el_GR.json index a589d31ad..c5d6a60e6 100644 --- a/src/Ryujinx/Assets/Locales/el_GR.json +++ b/src/Ryujinx/Assets/Locales/el_GR.json @@ -31,6 +31,9 @@ "MenuBarToolsInstallFirmware": "Εγκατάσταση Firmware", "MenuBarFileToolsInstallFirmwareFromFile": "Εγκατάσταση Firmware από XCI ή ZIP", "MenuBarFileToolsInstallFirmwareFromDirectory": "Εγκατάσταση Firmware από τοποθεσία", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "Διαχείριση τύπων αρχείων", "MenuBarToolsInstallFileTypes": "Εγκαταστήσετε τύπους αρχείων.", "MenuBarToolsUninstallFileTypes": "Απεγκαταστήσετε τύπους αρχείων", @@ -506,6 +509,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nΘέλετε να συνεχίσετε;", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Εγκατάσταση Firmware...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Η έκδοση συστήματος {0} εγκαταστάθηκε με επιτυχία.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "Δεν θα υπάρχουν άλλα προφίλ εάν διαγραφεί το επιλεγμένο", "DialogUserProfileDeletionConfirmMessage": "Θέλετε να διαγράψετε το επιλεγμένο προφίλ", "DialogUserProfileUnsavedChangesTitle": "Προσοχή - Μην Αποθηκευμένες Αλλαγές.", diff --git a/src/Ryujinx/Assets/Locales/en_US.json b/src/Ryujinx/Assets/Locales/en_US.json index 90290b760..b7ab8969b 100644 --- a/src/Ryujinx/Assets/Locales/en_US.json +++ b/src/Ryujinx/Assets/Locales/en_US.json @@ -31,6 +31,9 @@ "MenuBarToolsInstallFirmware": "Install Firmware", "MenuBarFileToolsInstallFirmwareFromFile": "Install a firmware from XCI or ZIP", "MenuBarFileToolsInstallFirmwareFromDirectory": "Install a firmware from a directory", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "Manage file types", "MenuBarToolsInstallFileTypes": "Install file types", "MenuBarToolsUninstallFileTypes": "Uninstall file types", @@ -518,6 +521,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nDo you want to continue?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Installing firmware...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "System version {0} successfully installed.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "There would be no other profiles to be opened if selected profile is deleted", "DialogUserProfileDeletionConfirmMessage": "Do you want to delete the selected profile", "DialogUserProfileUnsavedChangesTitle": "Warning - Unsaved Changes", diff --git a/src/Ryujinx/Assets/Locales/es_ES.json b/src/Ryujinx/Assets/Locales/es_ES.json index 8a426b3a4..730bd7961 100644 --- a/src/Ryujinx/Assets/Locales/es_ES.json +++ b/src/Ryujinx/Assets/Locales/es_ES.json @@ -31,6 +31,9 @@ "MenuBarToolsInstallFirmware": "Instalar firmware", "MenuBarFileToolsInstallFirmwareFromFile": "Instalar firmware desde un archivo XCI o ZIP", "MenuBarFileToolsInstallFirmwareFromDirectory": "Instalar firmware desde una carpeta", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "Administrar tipos de archivo", "MenuBarToolsInstallFileTypes": "Instalar tipos de archivo", "MenuBarToolsUninstallFileTypes": "Desinstalar tipos de archivo", @@ -506,6 +509,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\n¿Continuar?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Instalando firmware...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Versión de sistema {0} instalada con éxito.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "Si eliminas el perfil seleccionado no quedará ningún otro perfil", "DialogUserProfileDeletionConfirmMessage": "¿Quieres eliminar el perfil seleccionado?", "DialogUserProfileUnsavedChangesTitle": "Advertencia - Cambios sin guardar", diff --git a/src/Ryujinx/Assets/Locales/fr_FR.json b/src/Ryujinx/Assets/Locales/fr_FR.json index 355c2814d..947c48eab 100644 --- a/src/Ryujinx/Assets/Locales/fr_FR.json +++ b/src/Ryujinx/Assets/Locales/fr_FR.json @@ -31,6 +31,9 @@ "MenuBarToolsInstallFirmware": "Installer un firmware", "MenuBarFileToolsInstallFirmwareFromFile": "Installer un firmware depuis un fichier XCI ou ZIP", "MenuBarFileToolsInstallFirmwareFromDirectory": "Installer un firmware depuis un dossier", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "Gérer les types de fichiers", "MenuBarToolsInstallFileTypes": "Installer les types de fichiers", "MenuBarToolsUninstallFileTypes": "Désinstaller les types de fichiers", @@ -506,6 +509,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nVoulez-vous continuer ?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Installation du firmware...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Version du système {0} installée avec succès.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "Il n'y aurait aucun autre profil à ouvrir si le profil sélectionné est supprimé", "DialogUserProfileDeletionConfirmMessage": "Voulez-vous supprimer le profil sélectionné ?", "DialogUserProfileUnsavedChangesTitle": "Avertissement - Modifications non enregistrées", diff --git a/src/Ryujinx/Assets/Locales/he_IL.json b/src/Ryujinx/Assets/Locales/he_IL.json index 51c3c8835..88b6a059a 100644 --- a/src/Ryujinx/Assets/Locales/he_IL.json +++ b/src/Ryujinx/Assets/Locales/he_IL.json @@ -31,6 +31,9 @@ "MenuBarToolsInstallFirmware": "התקן קושחה", "MenuBarFileToolsInstallFirmwareFromFile": "התקן קושחה מקובץ- ZIP/XCI", "MenuBarFileToolsInstallFirmwareFromDirectory": "התקן קושחה מתוך תקייה", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "ניהול סוגי קבצים", "MenuBarToolsInstallFileTypes": "סוגי קבצי התקנה", "MenuBarToolsUninstallFileTypes": "סוגי קבצי הסרה", @@ -506,6 +509,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nהאם ברצונך להמשיך?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "מתקין קושחה...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "גרסת המערכת {0} הותקנה בהצלחה.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "לא יהיו פרופילים אחרים שייפתחו אם הפרופיל שנבחר יימחק", "DialogUserProfileDeletionConfirmMessage": "האם ברצונך למחוק את הפרופיל שנבחר", "DialogUserProfileUnsavedChangesTitle": "אזהרה - שינויים לא שמורים", diff --git a/src/Ryujinx/Assets/Locales/it_IT.json b/src/Ryujinx/Assets/Locales/it_IT.json index 52ea833d3..e689a2cd9 100644 --- a/src/Ryujinx/Assets/Locales/it_IT.json +++ b/src/Ryujinx/Assets/Locales/it_IT.json @@ -28,6 +28,9 @@ "MenuBarToolsInstallFirmware": "Installa firmware", "MenuBarFileToolsInstallFirmwareFromFile": "Installa un firmware da file XCI o ZIP", "MenuBarFileToolsInstallFirmwareFromDirectory": "Installa un firmare da una cartella", + "MenuBarToolsInstallKeys": "Installa Chiavi", + "MenuBarFileToolsInstallKeysFromFile": "Installa Chiavi da file KEYS o ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Installa Chiavi da una Cartella", "MenuBarToolsManageFileTypes": "Gestisci i tipi di file", "MenuBarToolsInstallFileTypes": "Installa i tipi di file", "MenuBarToolsUninstallFileTypes": "Disinstalla i tipi di file", @@ -506,6 +509,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nVuoi continuare?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Installazione del firmware...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "La versione del sistema {0} è stata installata.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "E' stato trovato un file di chiavi invalido ' {0}", + "DialogKeysInstallerKeysInstallTitle": "Installa Chavi", + "DialogKeysInstallerKeysInstallMessage": "Un nuovo file di Chiavi sarà intallato.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nQuesto potrebbe sovrascrivere alcune delle Chiavi già installate.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nVuoi continuare?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installando le chiavi...", + "DialogKeysInstallerKeysInstallSuccessMessage": "Nuovo file di chiavi installato con successo.", "DialogUserProfileDeletionWarningMessage": "Non ci sarebbero altri profili da aprire se il profilo selezionato viene cancellato", "DialogUserProfileDeletionConfirmMessage": "Vuoi eliminare il profilo selezionato?", "DialogUserProfileUnsavedChangesTitle": "Attenzione - Modifiche Non Salvate", diff --git a/src/Ryujinx/Assets/Locales/ja_JP.json b/src/Ryujinx/Assets/Locales/ja_JP.json index 59b7aa3b3..d55d1449d 100644 --- a/src/Ryujinx/Assets/Locales/ja_JP.json +++ b/src/Ryujinx/Assets/Locales/ja_JP.json @@ -31,6 +31,9 @@ "MenuBarToolsInstallFirmware": "ファームウェアをインストール", "MenuBarFileToolsInstallFirmwareFromFile": "XCI または ZIP からファームウェアをインストール", "MenuBarFileToolsInstallFirmwareFromDirectory": "ディレクトリからファームウェアをインストール", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "ファイル形式を管理", "MenuBarToolsInstallFileTypes": "ファイル形式をインストール", "MenuBarToolsUninstallFileTypes": "ファイル形式をアンインストール", @@ -506,6 +509,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\n続けてよろしいですか?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "ファームウェアをインストール中...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "システムバージョン {0} が正常にインストールされました.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "選択されたプロファイルを削除すると,プロファイルがひとつも存在しなくなります", "DialogUserProfileDeletionConfirmMessage": "選択されたプロファイルを削除しますか", "DialogUserProfileUnsavedChangesTitle": "警告 - 保存されていない変更", diff --git a/src/Ryujinx/Assets/Locales/ko_KR.json b/src/Ryujinx/Assets/Locales/ko_KR.json index aeeb84c62..ef4e96440 100644 --- a/src/Ryujinx/Assets/Locales/ko_KR.json +++ b/src/Ryujinx/Assets/Locales/ko_KR.json @@ -31,6 +31,9 @@ "MenuBarToolsInstallFirmware": "펌웨어 설치", "MenuBarFileToolsInstallFirmwareFromFile": "XCI 또는 ZIP으로 펌웨어 설치", "MenuBarFileToolsInstallFirmwareFromDirectory": "디렉터리에서 펌웨어 설치", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "파일 형식 관리", "MenuBarToolsInstallFileTypes": "파일 형식 설치", "MenuBarToolsUninstallFileTypes": "파일 형식 제거", @@ -506,6 +509,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\n계속하시겠습니까?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "펌웨어 설치 중...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "시스템 버전 {0}이(가) 설치되었습니다.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "선택한 프로필을 삭제하면 다른 프로필을 열 수 없음", "DialogUserProfileDeletionConfirmMessage": "선택한 프로필을 삭제하시겠습니까?", "DialogUserProfileUnsavedChangesTitle": "경고 - 저장되지 않은 변경 사항", diff --git a/src/Ryujinx/Assets/Locales/pl_PL.json b/src/Ryujinx/Assets/Locales/pl_PL.json index 1d8cf4f03..c3202020f 100644 --- a/src/Ryujinx/Assets/Locales/pl_PL.json +++ b/src/Ryujinx/Assets/Locales/pl_PL.json @@ -31,6 +31,9 @@ "MenuBarToolsInstallFirmware": "Zainstaluj oprogramowanie", "MenuBarFileToolsInstallFirmwareFromFile": "Zainstaluj oprogramowanie z XCI lub ZIP", "MenuBarFileToolsInstallFirmwareFromDirectory": "Zainstaluj oprogramowanie z katalogu", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "Zarządzaj rodzajami plików", "MenuBarToolsInstallFileTypes": "Typy plików instalacyjnych", "MenuBarToolsUninstallFileTypes": "Typy plików dezinstalacyjnych", @@ -506,6 +509,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nCzy chcesz kontynuować?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Instalowanie firmware'u...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Wersja systemu {0} została pomyślnie zainstalowana.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "Nie będzie innych profili do otwarcia, jeśli wybrany profil zostanie usunięty", "DialogUserProfileDeletionConfirmMessage": "Czy chcesz usunąć wybrany profil", "DialogUserProfileUnsavedChangesTitle": "Uwaga - Niezapisane zmiany", diff --git a/src/Ryujinx/Assets/Locales/pt_BR.json b/src/Ryujinx/Assets/Locales/pt_BR.json index 7574c1d20..71992434b 100644 --- a/src/Ryujinx/Assets/Locales/pt_BR.json +++ b/src/Ryujinx/Assets/Locales/pt_BR.json @@ -31,6 +31,9 @@ "MenuBarToolsInstallFirmware": "_Instalar firmware", "MenuBarFileToolsInstallFirmwareFromFile": "Instalar firmware a partir de um arquivo ZIP/XCI", "MenuBarFileToolsInstallFirmwareFromDirectory": "Instalar firmware a partir de um diretório", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "Gerenciar tipos de arquivo", "MenuBarToolsInstallFileTypes": "Instalar tipos de arquivo", "MenuBarToolsUninstallFileTypes": "Desinstalar tipos de arquivos", @@ -506,6 +509,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nDeseja continuar?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Instalando firmware...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Versão do sistema {0} instalada com sucesso.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "Não haveria nenhum perfil selecionado se o perfil atual fosse deletado", "DialogUserProfileDeletionConfirmMessage": "Deseja deletar o perfil selecionado", "DialogUserProfileUnsavedChangesTitle": "Alerta - Alterações não salvas", diff --git a/src/Ryujinx/Assets/Locales/ru_RU.json b/src/Ryujinx/Assets/Locales/ru_RU.json index 86e51f09f..f0218ffcc 100644 --- a/src/Ryujinx/Assets/Locales/ru_RU.json +++ b/src/Ryujinx/Assets/Locales/ru_RU.json @@ -31,6 +31,9 @@ "MenuBarToolsInstallFirmware": "Установка прошивки", "MenuBarFileToolsInstallFirmwareFromFile": "Установить прошивку из XCI или ZIP", "MenuBarFileToolsInstallFirmwareFromDirectory": "Установить прошивку из папки", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "Управление типами файлов", "MenuBarToolsInstallFileTypes": "Установить типы файлов", "MenuBarToolsUninstallFileTypes": "Удалить типы файлов", @@ -506,6 +509,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nПродолжить?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Установка прошивки...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Прошивка версии {0} успешно установлена.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "Если выбранный профиль будет удален, другие профили не будут открываться.", "DialogUserProfileDeletionConfirmMessage": "Удалить выбранный профиль?", "DialogUserProfileUnsavedChangesTitle": "Внимание - Несохраненные изменения", diff --git a/src/Ryujinx/Assets/Locales/th_TH.json b/src/Ryujinx/Assets/Locales/th_TH.json index 259828583..02ddda899 100644 --- a/src/Ryujinx/Assets/Locales/th_TH.json +++ b/src/Ryujinx/Assets/Locales/th_TH.json @@ -31,6 +31,9 @@ "MenuBarToolsInstallFirmware": "ติดตั้งเฟิร์มแวร์", "MenuBarFileToolsInstallFirmwareFromFile": "ติดตั้งเฟิร์มแวร์จาก ไฟล์ XCI หรือ ไฟล์ ZIP", "MenuBarFileToolsInstallFirmwareFromDirectory": "ติดตั้งเฟิร์มแวร์จากไดเร็กทอรี", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "จัดการประเภทไฟล์", "MenuBarToolsInstallFileTypes": "ติดตั้งประเภทไฟล์", "MenuBarToolsUninstallFileTypes": "ถอนการติดตั้งประเภทไฟล์", @@ -506,6 +509,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nคุณต้องการดำเนินการต่อหรือไม่?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "กำลังติดตั้งเฟิร์มแวร์...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "ระบบเวอร์ชั่น {0} ติดตั้งเรียบร้อยแล้ว", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "จะไม่มีโปรไฟล์อื่นให้เปิดหากโปรไฟล์ที่เลือกถูกลบ", "DialogUserProfileDeletionConfirmMessage": "คุณต้องการลบโปรไฟล์ที่เลือกหรือไม่?", "DialogUserProfileUnsavedChangesTitle": "คำเตือน - มีการเปลี่ยนแปลงที่ไม่ได้บันทึก", diff --git a/src/Ryujinx/Assets/Locales/tr_TR.json b/src/Ryujinx/Assets/Locales/tr_TR.json index 18dbb12b0..a65064a38 100644 --- a/src/Ryujinx/Assets/Locales/tr_TR.json +++ b/src/Ryujinx/Assets/Locales/tr_TR.json @@ -31,6 +31,9 @@ "MenuBarToolsInstallFirmware": "Yazılım Yükle", "MenuBarFileToolsInstallFirmwareFromFile": "XCI veya ZIP'ten Yazılım Yükle", "MenuBarFileToolsInstallFirmwareFromDirectory": "Bir Dizin Üzerinden Yazılım Yükle", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "Dosya uzantılarını yönet", "MenuBarToolsInstallFileTypes": "Dosya uzantılarını yükle", "MenuBarToolsUninstallFileTypes": "Dosya uzantılarını kaldır", @@ -506,6 +509,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nDevam etmek istiyor musunuz?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Firmware yükleniyor...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Sistem sürümü {0} başarıyla yüklendi.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "Seçilen profil silinirse kullanılabilen başka profil kalmayacak", "DialogUserProfileDeletionConfirmMessage": "Seçilen profili silmek istiyor musunuz", "DialogUserProfileUnsavedChangesTitle": "Uyarı - Kaydedilmemiş Değişiklikler", diff --git a/src/Ryujinx/Assets/Locales/uk_UA.json b/src/Ryujinx/Assets/Locales/uk_UA.json index e123afa6b..ef26ace65 100644 --- a/src/Ryujinx/Assets/Locales/uk_UA.json +++ b/src/Ryujinx/Assets/Locales/uk_UA.json @@ -31,6 +31,9 @@ "MenuBarToolsInstallFirmware": "Установити прошивку", "MenuBarFileToolsInstallFirmwareFromFile": "Установити прошивку з XCI або ZIP", "MenuBarFileToolsInstallFirmwareFromDirectory": "Установити прошивку з теки", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "Керувати типами файлів", "MenuBarToolsInstallFileTypes": "Установити типи файлів", "MenuBarToolsUninstallFileTypes": "Видалити типи файлів", @@ -506,6 +509,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nВи хочете продовжити?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Встановлення прошивки...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Версію системи {0} успішно встановлено.", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "Якщо вибраний профіль буде видалено, інші профілі не відкриватимуться", "DialogUserProfileDeletionConfirmMessage": "Ви хочете видалити вибраний профіль", "DialogUserProfileUnsavedChangesTitle": "Увага — Незбережені зміни", diff --git a/src/Ryujinx/Assets/Locales/zh_CN.json b/src/Ryujinx/Assets/Locales/zh_CN.json index 8fcd41cd2..dc3f27b5a 100644 --- a/src/Ryujinx/Assets/Locales/zh_CN.json +++ b/src/Ryujinx/Assets/Locales/zh_CN.json @@ -31,6 +31,9 @@ "MenuBarToolsInstallFirmware": "安装系统固件", "MenuBarFileToolsInstallFirmwareFromFile": "从 XCI 或 ZIP 文件中安装系统固件", "MenuBarFileToolsInstallFirmwareFromDirectory": "从文件夹中安装系统固件", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "管理文件扩展名", "MenuBarToolsInstallFileTypes": "关联文件扩展名", "MenuBarToolsUninstallFileTypes": "取消关联扩展名", @@ -506,6 +509,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\n是否继续?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "安装系统固件中...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "成功安装系统固件版本 {0} 。", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "删除后将没有可用的账户", "DialogUserProfileDeletionConfirmMessage": "是否删除所选账户", "DialogUserProfileUnsavedChangesTitle": "警告 - 有未保存的更改", diff --git a/src/Ryujinx/Assets/Locales/zh_TW.json b/src/Ryujinx/Assets/Locales/zh_TW.json index d219bc708..c33885784 100644 --- a/src/Ryujinx/Assets/Locales/zh_TW.json +++ b/src/Ryujinx/Assets/Locales/zh_TW.json @@ -31,6 +31,9 @@ "MenuBarToolsInstallFirmware": "安裝韌體", "MenuBarFileToolsInstallFirmwareFromFile": "從 XCI 或 ZIP 安裝韌體", "MenuBarFileToolsInstallFirmwareFromDirectory": "從資料夾安裝韌體", + "MenuBarToolsInstallKeys": "Install Keys", + "MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", + "MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarToolsManageFileTypes": "管理檔案類型", "MenuBarToolsInstallFileTypes": "安裝檔案類型", "MenuBarToolsUninstallFileTypes": "移除檔案類型", @@ -506,6 +509,13 @@ "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\n您確定要繼續嗎?", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "正在安裝韌體...", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "成功安裝系統版本 {0}。", + "DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", + "DialogKeysInstallerKeysInstallTitle": "Install Keys", + "DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", + "DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", + "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", + "DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", + "DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogUserProfileDeletionWarningMessage": "如果刪除選取的設定檔,將無法開啟其他設定檔", "DialogUserProfileDeletionConfirmMessage": "您是否要刪除所選設定檔", "DialogUserProfileUnsavedChangesTitle": "警告 - 未儲存的變更", diff --git a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs index 824fdd717..3672f8c71 100644 --- a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs @@ -1271,6 +1271,108 @@ namespace Ryujinx.Ava.UI.ViewModels } } + private async Task HandleKeysInstallation(string filename) + { + try + { + string systemDirectory = AppDataManager.KeysDirPath; + if (AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && Directory.Exists(AppDataManager.KeysDirPathUser)) + { + systemDirectory = AppDataManager.KeysDirPathUser; + } + + string dialogTitle = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysInstallTitle); + string dialogMessage = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysInstallMessage); + + bool alreadyKesyInstalled = ContentManager.AreKeysAlredyPresent(systemDirectory); + if (alreadyKesyInstalled) + { + dialogMessage += LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysInstallSubMessage); + } + + dialogMessage += LocaleManager.Instance[LocaleKeys.DialogKeysInstallerKeysInstallConfirmMessage]; + + UserResult result = await ContentDialogHelper.CreateConfirmationDialog( + dialogTitle, + dialogMessage, + LocaleManager.Instance[LocaleKeys.InputDialogYes], + LocaleManager.Instance[LocaleKeys.InputDialogNo], + LocaleManager.Instance[LocaleKeys.RyujinxConfirm]); + + UpdateWaitWindow waitingDialog = new(dialogTitle, LocaleManager.Instance[LocaleKeys.DialogKeysInstallerKeysInstallWaitMessage]); + + if (result == UserResult.Yes) + { + Logger.Info?.Print(LogClass.Application, $"Installing Keys"); + + Thread thread = new(() => + { + Dispatcher.UIThread.InvokeAsync(delegate + { + waitingDialog.Show(); + }); + + try + { + ContentManager.InstallKeys(filename, systemDirectory); + + Dispatcher.UIThread.InvokeAsync(async delegate + { + waitingDialog.Close(); + + string message = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysInstallSuccessMessage); + + await ContentDialogHelper.CreateInfoDialog( + dialogTitle, + message, + LocaleManager.Instance[LocaleKeys.InputDialogOk], + string.Empty, + LocaleManager.Instance[LocaleKeys.RyujinxInfo]); + + Logger.Info?.Print(LogClass.Application, message); + }); + } + catch (Exception ex) + { + Dispatcher.UIThread.InvokeAsync(async () => + { + waitingDialog.Close(); + + string message = ex.Message; + if(ex is FormatException) + { + message = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysNotFoundErrorMessage, filename); + } + + await ContentDialogHelper.CreateErrorDialog(message); + }); + } + finally + { + VirtualFileSystem.ReloadKeySet(); + } + }) + { + Name = "GUI.KeysInstallerThread", + }; + + thread.Start(); + } + } + catch (MissingKeyException ex) + { + if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime) + { + Logger.Error?.Print(LogClass.Application, ex.ToString()); + + await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys); + } + } + catch (Exception ex) + { + await ContentDialogHelper.CreateErrorDialog(ex.Message); + } + } private void ProgressHandler(T state, int current, int total) where T : Enum { Dispatcher.UIThread.Post(() => @@ -1559,6 +1661,53 @@ namespace Ryujinx.Ava.UI.ViewModels } } + public async Task InstallKeysFromFile() + { + var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions + { + AllowMultiple = false, + FileTypeFilter = new List + { + new(LocaleManager.Instance[LocaleKeys.FileDialogAllTypes]) + { + Patterns = new[] { "*.keys", "*.zip" }, + AppleUniformTypeIdentifiers = new[] { "com.ryujinx.xci", "public.zip-archive" }, + MimeTypes = new[] { "application/keys", "application/zip" }, + }, + new("KEYS") + { + Patterns = new[] { "*.keys" }, + AppleUniformTypeIdentifiers = new[] { "com.ryujinx.xci" }, + MimeTypes = new[] { "application/keys" }, + }, + new("ZIP") + { + Patterns = new[] { "*.zip" }, + AppleUniformTypeIdentifiers = new[] { "public.zip-archive" }, + MimeTypes = new[] { "application/zip" }, + }, + }, + }); + + if (result.Count > 0) + { + await HandleKeysInstallation(result[0].Path.LocalPath); + } + } + + public async Task InstallKeysFromFolder() + { + var result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions + { + AllowMultiple = false, + }); + + if (result.Count > 0) + { + await HandleKeysInstallation(result[0].Path.LocalPath); + } + } + public void OpenRyujinxFolder() { OpenHelper.OpenFolder(AppDataManager.BaseDirPath); diff --git a/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml b/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml index 6cf76cf49..c5e794da2 100644 --- a/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml +++ b/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml @@ -260,6 +260,10 @@ IsEnabled="{Binding IsGameRunning}" /> + + + +