diff options
| author | PastaLaPate <pastalapate@proton.me> | 2026-11-02 20:29:43 +0100 |
|---|---|---|
| committer | PastaLaPate <pastalapate@proton.me> | 2026-11-02 20:29:43 +0100 |
| commit | 7d25dbcea1e08e09c952096671b5fe2196d7ac79 (patch) | |
| tree | f0b1ba079e2442daafb25812157100d3409bc564 /src/core/loader/loader.cpp | |
| parent | 0d0e7788f8c86bcdbbef505654e9489808f38183 (diff) | |
| parent | 62214094d6c698b70f51016e5c12af415f025be7 (diff) | |
Merge remote-tracking branch 'upstream/nx2' into nx2
Diffstat (limited to 'src/core/loader/loader.cpp')
| -rw-r--r-- | src/core/loader/loader.cpp | 35 |
1 files changed, 33 insertions, 2 deletions
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 33a93573cf..839bb4d80b 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -29,6 +29,7 @@ #include "core/loader/nro.h" #include "core/loader/nso.h" #include "core/loader/nsp.h" +#include "core/loader/nup.h" #include "core/loader/xci.h" namespace Loader { @@ -130,6 +131,8 @@ FileType IdentifyFile(FileSys::VirtualFile file) { return *nsp_type; } else if (const auto xci_type = IdentifyFileLoader<AppLoader_XCI>(file)) { return *xci_type; + } else if (const auto nup_type = IdentifyFileLoader<AppLoader_NUP>(file)) { + return *nup_type; } else if (const auto nro_type = IdentifyFileLoader<AppLoader_NRO>(file)) { return *nro_type; } else if (const auto nca_type = IdentifyFileLoader<AppLoader_NCA>(file)) { @@ -150,7 +153,7 @@ FileType IdentifyFile(FileSys::VirtualFile file) { bool IsContainerType(FileType type) { return type == FileType::NSP || type == FileType::NSZ || type == FileType::XCI || - type == FileType::XCZ; + type == FileType::XCZ || type == FileType::NUP; } bool IsBootableGameContainer(FileSys::VirtualFile file, FileType type, u64 program_id, @@ -163,6 +166,24 @@ bool IsBootableGameContainer(FileSys::VirtualFile file, FileType type, u64 progr type = IdentifyFile(file); } + if (type == FileType::NUP) { + FileSys::NupContainer nup{file}; + if (nup.GetStatus() != ResultStatus::Success) { + return false; + } + // A base package boots normally; a standalone update (no base) carries + // a complete patched tree and boots on its own (SPEC section 4.1.2). + if (const auto base = nup.FindBasePackage(); + base.has_value() && nup.GetExeFSDir(*base) != nullptr) { + return true; + } + if (const auto update = nup.FindBestUpdatePackage(); + update.has_value() && nup.GetExeFSDir(*update) != nullptr) { + return true; + } + return false; + } + if (!IsContainerType(type)) { return false; } @@ -190,6 +211,8 @@ FileType GuessFromFilename(const std::string& name) { return FileType::XCZ; else if (extension == "nsp") return FileType::NSP; + else if (extension == "nup") + return FileType::NUP; else if (extension == "nsz") return FileType::NSZ; else if (extension == "kip") @@ -215,6 +238,8 @@ std::string GetFileTypeString(FileType type) { return "NSP"; case FileType::NSZ: return "NSZ"; + case FileType::NUP: + return "NUP"; case FileType::KIP: return "KIP"; case FileType::DeconstructedRomDirectory: @@ -227,7 +252,7 @@ std::string GetFileTypeString(FileType type) { return "unknown"; } -constexpr std::array<const char*, 68> RESULT_MESSAGES{ +constexpr std::array<const char*, 70> RESULT_MESSAGES{ "The operation completed successfully.", "The loader requested to load is already loaded.", "The operation is not implemented.", @@ -296,6 +321,8 @@ constexpr std::array<const char*, 68> RESULT_MESSAGES{ "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.", + "The NUP container is malformed or its TOC hash does not match.", + "The NUP container does not contain a loadable base package.", }; std::string GetResultStatusString(ResultStatus status) { @@ -380,6 +407,10 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V case FileType::KIP: return std::make_unique<AppLoader_KIP>(std::move(file)); + // NUP (NX Package) container format. + case FileType::NUP: + return std::make_unique<AppLoader_NUP>(std::move(file)); + // NX deconstructed ROM directory. case FileType::DeconstructedRomDirectory: return std::make_unique<AppLoader_DeconstructedRomDirectory>(std::move(file)); |
