| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
- // SPDX-License-Identifier: GPL-2.0-or-later
- #include <memory>
- #include <optional>
- #include <ostream>
- #include <string>
- #include "common/concepts.h"
- #include "common/fs/path_util.h"
- #include "common/logging/log.h"
- #include "common/string_util.h"
- #include "core/core.h"
- #include "core/hle/kernel/k_process.h"
- #include "core/loader/deconstructed_rom_directory.h"
- #include "core/loader/kip.h"
- #include "core/loader/nax.h"
- #include "core/loader/nca.h"
- #include "core/loader/nro.h"
- #include "core/loader/nso.h"
- #include "core/loader/nsp.h"
- #include "core/loader/xci.h"
- namespace Loader {
- namespace {
- template <Common::DerivedFrom<AppLoader> T>
- std::optional<FileType> IdentifyFileLoader(FileSys::VirtualFile file) {
- const auto file_type = T::IdentifyType(file);
- if (file_type != FileType::Error) {
- return file_type;
- }
- return std::nullopt;
- }
- } // namespace
- FileType IdentifyFile(FileSys::VirtualFile file) {
- if (const auto nsp_type = IdentifyFileLoader<AppLoader_NSP>(file)) {
- return *nsp_type;
- } else if (const auto xci_type = IdentifyFileLoader<AppLoader_XCI>(file)) {
- return *xci_type;
- } else if (const auto nro_type = IdentifyFileLoader<AppLoader_NRO>(file)) {
- return *nro_type;
- } else if (const auto nca_type = IdentifyFileLoader<AppLoader_NCA>(file)) {
- return *nca_type;
- } else if (const auto nax_type = IdentifyFileLoader<AppLoader_NAX>(file)) {
- return *nax_type;
- } else if (const auto kip_type = IdentifyFileLoader<AppLoader_KIP>(file)) {
- return *kip_type;
- } else if (const auto nso_type = IdentifyFileLoader<AppLoader_NSO>(file)) {
- return *nso_type;
- } else if (const auto romdir_type =
- IdentifyFileLoader<AppLoader_DeconstructedRomDirectory>(file)) {
- return *romdir_type;
- } else {
- return FileType::Unknown;
- }
- }
- FileType GuessFromFilename(const std::string& name) {
- if (name == "main")
- return FileType::DeconstructedRomDirectory;
- if (name == "00")
- return FileType::NCA;
- const std::string extension =
- Common::ToLower(std::string(Common::FS::GetExtensionFromFilename(name)));
- if (extension == "nro")
- return FileType::NRO;
- if (extension == "nso")
- return FileType::NSO;
- if (extension == "nca")
- return FileType::NCA;
- if (extension == "xci")
- return FileType::XCI;
- if (extension == "nsp")
- return FileType::NSP;
- if (extension == "kip")
- return FileType::KIP;
- return FileType::Unknown;
- }
- std::string GetFileTypeString(FileType type) {
- switch (type) {
- case FileType::NRO:
- return "NRO";
- case FileType::NSO:
- return "NSO";
- case FileType::NCA:
- return "NCA";
- case FileType::XCI:
- return "XCI";
- case FileType::NAX:
- return "NAX";
- case FileType::NSP:
- return "NSP";
- case FileType::KIP:
- return "KIP";
- case FileType::DeconstructedRomDirectory:
- return "Directory";
- case FileType::Error:
- case FileType::Unknown:
- break;
- }
- return "unknown";
- }
- constexpr std::array<const char*, 68> RESULT_MESSAGES{
- "The operation completed successfully.",
- "The loader requested to load is already loaded.",
- "The operation is not implemented.",
- "The loader is not initialized properly.",
- "The NPDM file has a bad header.",
- "The NPDM has a bad ACID header.",
- "The NPDM has a bad ACI header,",
- "The NPDM file has a bad file access control.",
- "The NPDM has a bad file access header.",
- "The NPDM has bad kernel capability descriptors.",
- "The PFS/HFS partition has a bad header.",
- "The PFS/HFS partition has incorrect size as determined by the header.",
- "The NCA file has a bad header.",
- "The general keyfile could not be found.",
- "The NCA Header key could not be found.",
- "The NCA Header key is incorrect or the header is invalid.",
- "Support for NCA2-type NCAs is not implemented.",
- "Support for NCA0-type NCAs is not implemented.",
- "The titlekey for this Rights ID could not be found.",
- "The titlekek for this crypto revision could not be found.",
- "The Rights ID in the header is invalid.",
- "The key area key for this application type and crypto revision could not be found.",
- "The key area key is incorrect or the section header is invalid.",
- "The titlekey and/or titlekek is incorrect or the section header is invalid.",
- "The XCI file is missing a Program-type NCA.",
- "The NCA file is not an application.",
- "The Program-type NCA contains no executable. An update may be required.",
- "The XCI file has a bad header.",
- "The XCI file is missing a partition.",
- "The file could not be found or does not exist.",
- "The game is missing a program metadata file (main.npdm).",
- "The game uses the currently-unimplemented 32-bit architecture.",
- "Unable to completely parse the kernel metadata when loading the emulated process",
- "The RomFS could not be found.",
- "The ELF file has incorrect size as determined by the header.",
- "There was a general error loading the NRO into emulated memory.",
- "There was a general error loading the NSO into emulated memory.",
- "There is no icon available.",
- "There is no control data available.",
- "The NAX file has a bad header.",
- "The NAX file has incorrect size as determined by the header.",
- "The HMAC to generated the NAX decryption keys failed.",
- "The HMAC to validate the NAX decryption keys failed.",
- "The NAX key derivation failed.",
- "The NAX file cannot be interpreted as an NCA file.",
- "The NAX file has an incorrect path.",
- "The SD seed could not be found or derived.",
- "The SD KEK Source could not be found.",
- "The AES KEK Generation Source could not be found.",
- "The AES Key Generation Source could not be found.",
- "The SD Save Key Source could not be found.",
- "The SD NCA Key Source could not be found.",
- "The NSP file is missing a Program-type NCA.",
- "The BKTR-type NCA has a bad BKTR header.",
- "The BKTR Subsection entry is not located immediately after the Relocation entry.",
- "The BKTR Subsection entry is not at the end of the media block.",
- "The BKTR-type NCA has a bad Relocation block.",
- "The BKTR-type NCA has a bad Subsection block.",
- "The BKTR-type NCA has a bad Relocation bucket.",
- "The BKTR-type NCA has a bad Subsection bucket.",
- "Game updates cannot be loaded directly. Load the base game instead.",
- "The NSP or XCI does not contain an update in addition to the base game.",
- "The KIP file has a bad header.",
- "The KIP BLZ decompression of the section failed unexpectedly.",
- "The INI file has a bad header.",
- "The INI file contains more than the maximum allowable number of KIP files.",
- "Integrity verification could not be performed for this file.",
- "Integrity verification failed.",
- };
- std::string GetResultStatusString(ResultStatus status) {
- return RESULT_MESSAGES.at(static_cast<std::size_t>(status));
- }
- std::ostream& operator<<(std::ostream& os, ResultStatus status) {
- os << RESULT_MESSAGES.at(static_cast<std::size_t>(status));
- return os;
- }
- AppLoader::AppLoader(FileSys::VirtualFile file_) : file(std::move(file_)) {}
- AppLoader::~AppLoader() = default;
- /**
- * Get a loader for a file with a specific type
- * @param system The system context to use.
- * @param file The file to retrieve the loader for
- * @param type The file type
- * @param program_index Specifies the index within the container of the program to launch.
- * @return std::unique_ptr<AppLoader> a pointer to a loader object; nullptr for unsupported type
- */
- static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::VirtualFile file,
- FileType type, u64 program_id,
- std::size_t program_index) {
- switch (type) {
- // NX NSO file format.
- case FileType::NSO:
- return std::make_unique<AppLoader_NSO>(std::move(file));
- // NX NRO file format.
- case FileType::NRO:
- return std::make_unique<AppLoader_NRO>(std::move(file));
- // NX NCA (Nintendo Content Archive) file format.
- case FileType::NCA:
- return std::make_unique<AppLoader_NCA>(std::move(file));
- // NX XCI (nX Card Image) file format.
- case FileType::XCI:
- return std::make_unique<AppLoader_XCI>(std::move(file), system.GetFileSystemController(),
- system.GetContentProvider(), program_id,
- program_index);
- // NX NAX (NintendoAesXts) file format.
- case FileType::NAX:
- return std::make_unique<AppLoader_NAX>(std::move(file));
- // NX NSP (Nintendo Submission Package) file format
- case FileType::NSP:
- return std::make_unique<AppLoader_NSP>(std::move(file), system.GetFileSystemController(),
- system.GetContentProvider(), program_id,
- program_index);
- // NX KIP (Kernel Internal Process) file format
- case FileType::KIP:
- return std::make_unique<AppLoader_KIP>(std::move(file));
- // NX deconstructed ROM directory.
- case FileType::DeconstructedRomDirectory:
- return std::make_unique<AppLoader_DeconstructedRomDirectory>(std::move(file));
- default:
- return nullptr;
- }
- }
- std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file,
- u64 program_id, std::size_t program_index) {
- if (!file) {
- return nullptr;
- }
- FileType type = IdentifyFile(file);
- const FileType filename_type = GuessFromFilename(file->GetName());
- // Special case: 00 is either a NCA or NAX.
- if (type != filename_type && !(file->GetName() == "00" && type == FileType::NAX)) {
- LOG_WARNING(Loader, "File {} has a different type ({}) than its extension.",
- file->GetName(), GetFileTypeString(type));
- if (FileType::Unknown == type) {
- type = filename_type;
- }
- }
- LOG_DEBUG(Loader, "Loading file {} as {}...", file->GetName(), GetFileTypeString(type));
- return GetFileLoader(system, std::move(file), type, program_id, program_index);
- }
- } // namespace Loader
|