aboutsummaryrefslogtreecommitdiff
path: root/src/core/loader/loader.cpp
diff options
context:
space:
mode:
authorkraibse <33869366+kraibse@users.noreply.github.com>2026-11-02 16:01:57 +0100
committerkraibse <33869366+kraibse@users.noreply.github.com>2026-11-02 16:01:57 +0100
commitb374709aa202d586dd09f81f3389da8d73fea0d7 (patch)
tree5c4033d827c517aca9cc73dc497fbb3e81291bf1 /src/core/loader/loader.cpp
parent021c9724371e45fa694c9ee3106b9011364d2853 (diff)
parentce1b1de6f1beed36958368f89cda466937ff9716 (diff)
Merge remote-tracking branch 'origin/nx2' into codex/upstream-loading-hotkeys
Diffstat (limited to 'src/core/loader/loader.cpp')
-rw-r--r--src/core/loader/loader.cpp35
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));