mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 19:21:55 +01:00
Implement a basic NSP loader
An NSP (Nintendo Submission Package) is effectively a PFS0 containing NCAs, there are also tickets and a CNMT file which contains metadata about updates. The current implementation is very basic and only support Control and Program NCAs which is enough for loading games. Support for updates and dlc will be added at a later date.
This commit is contained in:
parent
a5513bd7e6
commit
a53d6266c7
@ -44,6 +44,7 @@ add_library(skyline SHARED
|
|||||||
${source_DIR}/skyline/loader/nro.cpp
|
${source_DIR}/skyline/loader/nro.cpp
|
||||||
${source_DIR}/skyline/loader/nso.cpp
|
${source_DIR}/skyline/loader/nso.cpp
|
||||||
${source_DIR}/skyline/loader/nca.cpp
|
${source_DIR}/skyline/loader/nca.cpp
|
||||||
|
${source_DIR}/skyline/loader/nsp.cpp
|
||||||
${source_DIR}/skyline/kernel/memory.cpp
|
${source_DIR}/skyline/kernel/memory.cpp
|
||||||
${source_DIR}/skyline/kernel/ipc.cpp
|
${source_DIR}/skyline/kernel/ipc.cpp
|
||||||
${source_DIR}/skyline/kernel/svc.cpp
|
${source_DIR}/skyline/kernel/svc.cpp
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "skyline/loader/nro.h"
|
#include "skyline/loader/nro.h"
|
||||||
#include "skyline/loader/nso.h"
|
#include "skyline/loader/nso.h"
|
||||||
#include "skyline/loader/nca.h"
|
#include "skyline/loader/nca.h"
|
||||||
|
#include "skyline/loader/nsp.h"
|
||||||
#include "skyline/jvm.h"
|
#include "skyline/jvm.h"
|
||||||
|
|
||||||
extern "C" JNIEXPORT jlong JNICALL Java_emu_skyline_loader_RomFile_initialize(JNIEnv *env, jobject thiz, jint jformat, jint fd) {
|
extern "C" JNIEXPORT jlong JNICALL Java_emu_skyline_loader_RomFile_initialize(JNIEnv *env, jobject thiz, jint jformat, jint fd) {
|
||||||
@ -20,6 +21,8 @@ extern "C" JNIEXPORT jlong JNICALL Java_emu_skyline_loader_RomFile_initialize(JN
|
|||||||
return reinterpret_cast<jlong>(new skyline::loader::NsoLoader(backing));
|
return reinterpret_cast<jlong>(new skyline::loader::NsoLoader(backing));
|
||||||
case skyline::loader::RomFormat::NCA:
|
case skyline::loader::RomFormat::NCA:
|
||||||
return reinterpret_cast<jlong>(new skyline::loader::NcaLoader(backing));
|
return reinterpret_cast<jlong>(new skyline::loader::NcaLoader(backing));
|
||||||
|
case skyline::loader::RomFormat::NSP:
|
||||||
|
return reinterpret_cast<jlong>(new skyline::loader::NspLoader(backing));
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
62
app/src/main/cpp/skyline/loader/nsp.cpp
Normal file
62
app/src/main/cpp/skyline/loader/nsp.cpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
|
#include "nca.h"
|
||||||
|
#include "nsp.h"
|
||||||
|
|
||||||
|
namespace skyline::loader {
|
||||||
|
NspLoader::NspLoader(const std::shared_ptr<vfs::Backing> &backing) : nsp(std::make_shared<vfs::PartitionFileSystem>(backing)) {
|
||||||
|
auto root = nsp->OpenDirectory("", {false, true});
|
||||||
|
|
||||||
|
for (const auto &entry : root->Read()) {
|
||||||
|
if (entry.name.substr(entry.name.find_last_of(".") + 1) != "nca")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
try {
|
||||||
|
auto nca = vfs::NCA(nsp->OpenFile(entry.name));
|
||||||
|
|
||||||
|
if (nca.contentType == vfs::NcaContentType::Program && nca.romFs != nullptr && nca.exeFs != nullptr)
|
||||||
|
programNca = std::move(nca);
|
||||||
|
else if (nca.contentType == vfs::NcaContentType::Control && nca.romFs != nullptr)
|
||||||
|
controlNca = std::move(nca);
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!programNca.has_value() || !controlNca.has_value())
|
||||||
|
throw exception("Incomplete NSP file");
|
||||||
|
|
||||||
|
romFs = programNca->romFs;
|
||||||
|
controlRomFs = std::make_shared<vfs::RomFileSystem>(controlNca->romFs);
|
||||||
|
nacp = std::make_shared<vfs::NACP>(controlRomFs->OpenFile("control.nacp"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void NspLoader::LoadProcessData(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state) {
|
||||||
|
NcaLoader::LoadExeFs(programNca->exeFs, process, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<u8> NspLoader::GetIcon() {
|
||||||
|
if (romFs == nullptr)
|
||||||
|
return std::vector<u8>();
|
||||||
|
|
||||||
|
auto root = controlRomFs->OpenDirectory("", {false, true});
|
||||||
|
std::shared_ptr<vfs::Backing> icon;
|
||||||
|
|
||||||
|
// Use the first icon file available
|
||||||
|
for (const auto &entry : root->Read()) {
|
||||||
|
if (entry.name.rfind("icon") == 0) {
|
||||||
|
icon = controlRomFs->OpenFile(entry.name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (icon == nullptr)
|
||||||
|
return std::vector<u8>();
|
||||||
|
|
||||||
|
std::vector<u8> buffer(icon->size);
|
||||||
|
|
||||||
|
icon->Read(buffer.data(), 0, icon->size);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
}
|
30
app/src/main/cpp/skyline/loader/nsp.h
Normal file
30
app/src/main/cpp/skyline/loader/nsp.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <vfs/nca.h>
|
||||||
|
#include <vfs/rom_filesystem.h>
|
||||||
|
#include <vfs/partition_filesystem.h>
|
||||||
|
#include "loader.h"
|
||||||
|
|
||||||
|
namespace skyline::loader {
|
||||||
|
/**
|
||||||
|
* @brief The NspLoader class consolidates all the data in an NSP providing a simple way to load an application and access its metadata (https://switchbrew.org/wiki/NCA_Format#PFS0)
|
||||||
|
*/
|
||||||
|
class NspLoader : public Loader {
|
||||||
|
private:
|
||||||
|
std::shared_ptr<vfs::PartitionFileSystem> nsp; //!< A shared pointer to the NSP's PFS0
|
||||||
|
std::shared_ptr<vfs::RomFileSystem> controlRomFs; //!< A pointer to the control NCA's RomFS
|
||||||
|
std::optional<vfs::NCA> programNca; //!< The main program NCA within the NSP
|
||||||
|
std::optional<vfs::NCA> controlNca; //!< The main control NCA within the NSP
|
||||||
|
|
||||||
|
public:
|
||||||
|
NspLoader(const std::shared_ptr<vfs::Backing> &backing);
|
||||||
|
|
||||||
|
std::vector<u8> GetIcon();
|
||||||
|
|
||||||
|
void LoadProcessData(const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state);
|
||||||
|
};
|
||||||
|
}
|
@ -5,6 +5,7 @@
|
|||||||
#include "loader/nro.h"
|
#include "loader/nro.h"
|
||||||
#include "loader/nso.h"
|
#include "loader/nso.h"
|
||||||
#include "loader/nca.h"
|
#include "loader/nca.h"
|
||||||
|
#include "loader/nsp.h"
|
||||||
#include "nce/guest.h"
|
#include "nce/guest.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
|
||||||
@ -20,6 +21,8 @@ namespace skyline::kernel {
|
|||||||
state.loader = std::make_shared<loader::NsoLoader>(romFile);
|
state.loader = std::make_shared<loader::NsoLoader>(romFile);
|
||||||
} else if (romType == loader::RomFormat::NCA) {
|
} else if (romType == loader::RomFormat::NCA) {
|
||||||
state.loader = std::make_shared<loader::NcaLoader>(romFile);
|
state.loader = std::make_shared<loader::NcaLoader>(romFile);
|
||||||
|
} else if (romType == loader::RomFormat::NSP) {
|
||||||
|
state.loader = std::make_shared<loader::NspLoader>(romFile);
|
||||||
} else {
|
} else {
|
||||||
throw exception("Unsupported ROM extension.");
|
throw exception("Unsupported ROM extension.");
|
||||||
}
|
}
|
||||||
|
@ -114,6 +114,7 @@ class MainActivity : AppCompatActivity(), View.OnClickListener, View.OnLongClick
|
|||||||
var foundRoms = addEntries("nro", RomFormat.NRO, DocumentFile.fromTreeUri(this, Uri.parse(sharedPreferences.getString("search_location", "")))!!)
|
var foundRoms = addEntries("nro", RomFormat.NRO, DocumentFile.fromTreeUri(this, Uri.parse(sharedPreferences.getString("search_location", "")))!!)
|
||||||
foundRoms = foundRoms or addEntries("nso", RomFormat.NSO, DocumentFile.fromTreeUri(this, Uri.parse(sharedPreferences.getString("search_location", "")))!!)
|
foundRoms = foundRoms or addEntries("nso", RomFormat.NSO, DocumentFile.fromTreeUri(this, Uri.parse(sharedPreferences.getString("search_location", "")))!!)
|
||||||
foundRoms = foundRoms or addEntries("nca", RomFormat.NCA, DocumentFile.fromTreeUri(this, Uri.parse(sharedPreferences.getString("search_location", "")))!!)
|
foundRoms = foundRoms or addEntries("nca", RomFormat.NCA, DocumentFile.fromTreeUri(this, Uri.parse(sharedPreferences.getString("search_location", "")))!!)
|
||||||
|
foundRoms = foundRoms or addEntries("nsp", RomFormat.NSP, DocumentFile.fromTreeUri(this, Uri.parse(sharedPreferences.getString("search_location", "")))!!)
|
||||||
|
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
if (!foundRoms)
|
if (!foundRoms)
|
||||||
|
Loading…
Reference in New Issue
Block a user