summaryrefslogtreecommitdiffstats
path: root/src/core/loader
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/loader')
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp44
-rw-r--r--src/core/loader/deconstructed_rom_directory.h8
-rw-r--r--src/core/loader/elf.cpp2
-rw-r--r--src/core/loader/loader.cpp28
-rw-r--r--src/core/loader/loader.h37
-rw-r--r--src/core/loader/nax.cpp26
-rw-r--r--src/core/loader/nax.h4
-rw-r--r--src/core/loader/nca.cpp8
-rw-r--r--src/core/loader/nca.h1
-rw-r--r--src/core/loader/nro.cpp7
-rw-r--r--src/core/loader/nro.h1
-rw-r--r--src/core/loader/nso.cpp3
-rw-r--r--src/core/loader/nsp.cpp125
-rw-r--r--src/core/loader/nsp.h54
-rw-r--r--src/core/loader/xci.cpp25
15 files changed, 320 insertions, 53 deletions
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 921b899e2..2b8f78136 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -9,6 +9,7 @@
#include "core/core.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h"
+#include "core/file_sys/patch_manager.h"
#include "core/file_sys/romfs_factory.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/kernel.h"
@@ -21,10 +22,19 @@
namespace Loader {
-AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_)
- : AppLoader(std::move(file_)) {
+AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_,
+ bool override_update)
+ : AppLoader(std::move(file_)), override_update(override_update) {
const auto dir = file->GetContainingDirectory();
+ // Title ID
+ const auto npdm = dir->GetFile("main.npdm");
+ if (npdm != nullptr) {
+ const auto res = metadata.Load(npdm);
+ if (res == ResultStatus::Success)
+ title_id = metadata.GetTitleID();
+ }
+
// Icon
FileSys::VirtualFile icon_file = nullptr;
for (const auto& language : FileSys::LANGUAGE_NAMES) {
@@ -61,14 +71,14 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys
if (nacp_file != nullptr) {
FileSys::NACP nacp(nacp_file);
- title_id = nacp.GetTitleId();
name = nacp.GetApplicationName();
}
}
AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(
- FileSys::VirtualDir directory)
- : AppLoader(directory->GetFile("main")), dir(std::move(directory)) {}
+ FileSys::VirtualDir directory, bool override_update)
+ : AppLoader(directory->GetFile("main")), dir(std::move(directory)),
+ override_update(override_update) {}
FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::VirtualFile& file) {
if (FileSys::IsDirectoryExeFS(file->GetContainingDirectory())) {
@@ -90,7 +100,8 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
dir = file->GetContainingDirectory();
}
- const FileSys::VirtualFile npdm = dir->GetFile("main.npdm");
+ // Read meta to determine title ID
+ FileSys::VirtualFile npdm = dir->GetFile("main.npdm");
if (npdm == nullptr)
return ResultStatus::ErrorMissingNPDM;
@@ -98,6 +109,21 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
if (result != ResultStatus::Success) {
return result;
}
+
+ if (override_update) {
+ const FileSys::PatchManager patch_manager(metadata.GetTitleID());
+ dir = patch_manager.PatchExeFS(dir);
+ }
+
+ // Reread in case PatchExeFS affected the main.npdm
+ npdm = dir->GetFile("main.npdm");
+ if (npdm == nullptr)
+ return ResultStatus::ErrorMissingNPDM;
+
+ ResultStatus result2 = metadata.Load(npdm);
+ if (result2 != ResultStatus::Success) {
+ return result2;
+ }
metadata.Print();
const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()};
@@ -159,8 +185,6 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadIcon(std::vector<u8>& buff
}
ResultStatus AppLoader_DeconstructedRomDirectory::ReadProgramId(u64& out_program_id) {
- if (name.empty())
- return ResultStatus::ErrorNoControl;
out_program_id = title_id;
return ResultStatus::Success;
}
@@ -172,4 +196,8 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadTitle(std::string& title)
return ResultStatus::Success;
}
+bool AppLoader_DeconstructedRomDirectory::IsRomFSUpdatable() const {
+ return false;
+}
+
} // namespace Loader
diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h
index b20804f75..8a0dc1b1e 100644
--- a/src/core/loader/deconstructed_rom_directory.h
+++ b/src/core/loader/deconstructed_rom_directory.h
@@ -20,10 +20,12 @@ namespace Loader {
*/
class AppLoader_DeconstructedRomDirectory final : public AppLoader {
public:
- explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile main_file);
+ explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile main_file,
+ bool override_update = false);
// Overload to accept exefs directory. Must contain 'main' and 'main.npdm'
- explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualDir directory);
+ explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualDir directory,
+ bool override_update = false);
/**
* Returns the type of the file
@@ -42,6 +44,7 @@ public:
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
ResultStatus ReadProgramId(u64& out_program_id) override;
ResultStatus ReadTitle(std::string& title) override;
+ bool IsRomFSUpdatable() const override;
private:
FileSys::ProgramMetadata metadata;
@@ -51,6 +54,7 @@ private:
std::vector<u8> icon_data;
std::string name;
u64 title_id{};
+ bool override_update;
};
} // namespace Loader
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 120e1e133..0e2af20b4 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -300,7 +300,7 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
}
std::vector<u8> program_image(total_image_size);
- size_t current_image_position = 0;
+ std::size_t current_image_position = 0;
auto& kernel = Core::System::GetInstance().Kernel();
SharedPtr<CodeSet> codeset = CodeSet::Create(kernel, "");
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index c13fb49b8..f2a183ba1 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -5,9 +5,9 @@
#include <memory>
#include <ostream>
#include <string>
+#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/string_util.h"
-#include "core/file_sys/vfs_real.h"
#include "core/hle/kernel/process.h"
#include "core/loader/deconstructed_rom_directory.h"
#include "core/loader/elf.h"
@@ -15,6 +15,7 @@
#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 {
@@ -34,6 +35,7 @@ FileType IdentifyFile(FileSys::VirtualFile file) {
CHECK_TYPE(NCA)
CHECK_TYPE(XCI)
CHECK_TYPE(NAX)
+ CHECK_TYPE(NSP)
#undef CHECK_TYPE
@@ -59,6 +61,8 @@ FileType GuessFromFilename(const std::string& name) {
return FileType::NCA;
if (extension == "xci")
return FileType::XCI;
+ if (extension == "nsp")
+ return FileType::NSP;
return FileType::Unknown;
}
@@ -77,6 +81,8 @@ std::string GetFileTypeString(FileType type) {
return "XCI";
case FileType::NAX:
return "NAX";
+ case FileType::NSP:
+ return "NSP";
case FileType::DeconstructedRomDirectory:
return "Directory";
case FileType::Error:
@@ -87,7 +93,7 @@ std::string GetFileTypeString(FileType type) {
return "unknown";
}
-constexpr std::array<const char*, 49> RESULT_MESSAGES{
+constexpr std::array<const char*, 58> RESULT_MESSAGES{
"The operation completed successfully.",
"The loader requested to load is already loaded.",
"The operation is not implemented.",
@@ -137,13 +143,25 @@ constexpr std::array<const char*, 49> RESULT_MESSAGES{
"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.",
+ "The BKTR-type NCA is missing the base RomFS.",
};
std::ostream& operator<<(std::ostream& os, ResultStatus status) {
- os << RESULT_MESSAGES.at(static_cast<size_t>(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 file The file to load
@@ -179,6 +197,10 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT
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));
+
// NX deconstructed ROM directory.
case FileType::DeconstructedRomDirectory:
return std::make_unique<AppLoader_DeconstructedRomDirectory>(std::move(file));
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 885fee84c..843c4bb91 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -4,7 +4,6 @@
#pragma once
-#include <algorithm>
#include <iosfwd>
#include <memory>
#include <string>
@@ -12,7 +11,6 @@
#include <vector>
#include <boost/optional.hpp>
#include "common/common_types.h"
-#include "common/file_util.h"
#include "core/file_sys/vfs.h"
#include "core/hle/kernel/object.h"
@@ -31,6 +29,7 @@ enum class FileType {
NSO,
NRO,
NCA,
+ NSP,
XCI,
NAX,
DeconstructedRomDirectory,
@@ -107,6 +106,15 @@ enum class ResultStatus : u16 {
ErrorMissingAESKeyGenerationSource,
ErrorMissingSDSaveKeySource,
ErrorMissingSDNCAKeySource,
+ ErrorNSPMissingProgramNCA,
+ ErrorBadBKTRHeader,
+ ErrorBKTRSubsectionNotAfterRelocation,
+ ErrorBKTRSubsectionNotAtEnd,
+ ErrorBadRelocationBlock,
+ ErrorBadSubsectionBlock,
+ ErrorBadRelocationBuckets,
+ ErrorBadSubsectionBuckets,
+ ErrorMissingBKTRBaseRomFS,
};
std::ostream& operator<<(std::ostream& os, ResultStatus status);
@@ -114,8 +122,8 @@ std::ostream& operator<<(std::ostream& os, ResultStatus status);
/// Interface for loading an application
class AppLoader : NonCopyable {
public:
- explicit AppLoader(FileSys::VirtualFile file) : file(std::move(file)) {}
- virtual ~AppLoader() {}
+ explicit AppLoader(FileSys::VirtualFile file);
+ virtual ~AppLoader();
/**
* Returns the type of this file
@@ -197,13 +205,22 @@ public:
}
/**
- * Get the update RomFS of the application
- * Since the RomFS can be huge, we return a file reference instead of copying to a buffer
- * @param file The file containing the RomFS
- * @return ResultStatus result of function
+ * Get whether or not updates can be applied to the RomFS.
+ * By default, this is true, however for formats where it cannot be guaranteed that the RomFS is
+ * the base game it should be set to false.
+ * @return bool whether or not updatable.
*/
- virtual ResultStatus ReadUpdateRomFS(FileSys::VirtualFile& file) {
- return ResultStatus::ErrorNotImplemented;
+ virtual bool IsRomFSUpdatable() const {
+ return true;
+ }
+
+ /**
+ * Gets the difference between the start of the IVFC header and the start of level 6 (RomFS)
+ * data. Needed for bktr patching.
+ * @return IVFC offset for romfs.
+ */
+ virtual u64 ReadRomFSIVFCOffset() const {
+ return 0;
}
/**
diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp
index b46d81c02..5d4380684 100644
--- a/src/core/loader/nax.cpp
+++ b/src/core/loader/nax.cpp
@@ -11,6 +11,20 @@
#include "core/loader/nca.h"
namespace Loader {
+namespace {
+FileType IdentifyTypeImpl(const FileSys::NAX& nax) {
+ if (nax.GetStatus() != ResultStatus::Success) {
+ return FileType::Error;
+ }
+
+ const auto nca = nax.AsNCA();
+ if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) {
+ return FileType::Error;
+ }
+
+ return FileType::NAX;
+}
+} // Anonymous namespace
AppLoader_NAX::AppLoader_NAX(FileSys::VirtualFile file)
: AppLoader(file), nax(std::make_unique<FileSys::NAX>(file)),
@@ -19,14 +33,12 @@ AppLoader_NAX::AppLoader_NAX(FileSys::VirtualFile file)
AppLoader_NAX::~AppLoader_NAX() = default;
FileType AppLoader_NAX::IdentifyType(const FileSys::VirtualFile& file) {
- FileSys::NAX nax(file);
-
- if (nax.GetStatus() == ResultStatus::Success && nax.AsNCA() != nullptr &&
- nax.AsNCA()->GetStatus() == ResultStatus::Success) {
- return FileType::NAX;
- }
+ const FileSys::NAX nax(file);
+ return IdentifyTypeImpl(nax);
+}
- return FileType::Error;
+FileType AppLoader_NAX::GetFileType() {
+ return IdentifyTypeImpl(*nax);
}
ResultStatus AppLoader_NAX::Load(Kernel::SharedPtr<Kernel::Process>& process) {
diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h
index 4dbae2918..56605fe45 100644
--- a/src/core/loader/nax.h
+++ b/src/core/loader/nax.h
@@ -31,9 +31,7 @@ public:
*/
static FileType IdentifyType(const FileSys::VirtualFile& file);
- FileType GetFileType() override {
- return IdentifyType(file);
- }
+ FileType GetFileType() override;
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp
index c036a8a1c..6aaffae59 100644
--- a/src/core/loader/nca.cpp
+++ b/src/core/loader/nca.cpp
@@ -48,7 +48,7 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) {
if (exefs == nullptr)
return ResultStatus::ErrorNoExeFS;
- directory_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(exefs);
+ directory_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(exefs, true);
const auto load_result = directory_loader->Load(process);
if (load_result != ResultStatus::Success)
@@ -71,6 +71,12 @@ ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) {
return ResultStatus::Success;
}
+u64 AppLoader_NCA::ReadRomFSIVFCOffset() const {
+ if (nca == nullptr)
+ return 0;
+ return nca->GetBaseIVFCOffset();
+}
+
ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) {
if (nca == nullptr || nca->GetStatus() != ResultStatus::Success)
return ResultStatus::ErrorNotInitialized;
diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h
index 326f84857..10be197c4 100644
--- a/src/core/loader/nca.h
+++ b/src/core/loader/nca.h
@@ -37,6 +37,7 @@ public:
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
+ u64 ReadRomFSIVFCOffset() const override;
ResultStatus ReadProgramId(u64& out_program_id) override;
private:
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 77026b850..c49ec34ab 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -191,7 +191,7 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
process->svc_access_mask.set();
process->resource_limit =
kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
- process->Run(base_addr, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
+ process->Run(base_addr, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
is_loaded = true;
return ResultStatus::Success;
@@ -232,4 +232,9 @@ ResultStatus AppLoader_NRO::ReadTitle(std::string& title) {
title = nacp->GetApplicationName();
return ResultStatus::Success;
}
+
+bool AppLoader_NRO::IsRomFSUpdatable() const {
+ return false;
+}
+
} // namespace Loader
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h
index bb01c9e25..96d2de305 100644
--- a/src/core/loader/nro.h
+++ b/src/core/loader/nro.h
@@ -39,6 +39,7 @@ public:
ResultStatus ReadProgramId(u64& out_program_id) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
ResultStatus ReadTitle(std::string& title) override;
+ bool IsRomFSUpdatable() const override;
private:
bool LoadNro(FileSys::VirtualFile file, VAddr load_base);
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 082a95d40..3c6306818 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -157,7 +157,8 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
process->svc_access_mask.set();
process->resource_limit =
kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
- process->Run(Memory::PROCESS_IMAGE_VADDR, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
+ process->Run(Memory::PROCESS_IMAGE_VADDR, Kernel::THREADPRIO_DEFAULT,
+ Memory::DEFAULT_STACK_SIZE);
is_loaded = true;
return ResultStatus::Success;
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp
new file mode 100644
index 000000000..291a9876d
--- /dev/null
+++ b/src/core/loader/nsp.cpp
@@ -0,0 +1,125 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <vector>
+
+#include "common/common_types.h"
+#include "core/file_sys/card_image.h"
+#include "core/file_sys/content_archive.h"
+#include "core/file_sys/control_metadata.h"
+#include "core/file_sys/nca_metadata.h"
+#include "core/file_sys/patch_manager.h"
+#include "core/file_sys/registered_cache.h"
+#include "core/file_sys/romfs.h"
+#include "core/file_sys/submission_package.h"
+#include "core/hle/kernel/process.h"
+#include "core/loader/deconstructed_rom_directory.h"
+#include "core/loader/nca.h"
+#include "core/loader/nsp.h"
+
+namespace Loader {
+
+AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file)
+ : AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file)),
+ title_id(nsp->GetProgramTitleID()) {
+
+ if (nsp->GetStatus() != ResultStatus::Success)
+ return;
+ if (nsp->IsExtractedType())
+ return;
+
+ const auto control_nca =
+ nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Control);
+ if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success)
+ return;
+
+ std::tie(nacp_file, icon_file) =
+ FileSys::PatchManager(nsp->GetProgramTitleID()).ParseControlNCA(control_nca);
+}
+
+AppLoader_NSP::~AppLoader_NSP() = default;
+
+FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& file) {
+ FileSys::NSP nsp(file);
+
+ if (nsp.GetStatus() == ResultStatus::Success) {
+ // Extracted Type case
+ if (nsp.IsExtractedType() && nsp.GetExeFS() != nullptr &&
+ FileSys::IsDirectoryExeFS(nsp.GetExeFS()) && nsp.GetRomFS() != nullptr) {
+ return FileType::NSP;
+ }
+
+ // Non-Ectracted Type case
+ if (!nsp.IsExtractedType() &&
+ nsp.GetNCA(nsp.GetFirstTitleID(), FileSys::ContentRecordType::Program) != nullptr &&
+ AppLoader_NCA::IdentifyType(nsp.GetNCAFile(
+ nsp.GetFirstTitleID(), FileSys::ContentRecordType::Program)) == FileType::NCA) {
+ return FileType::NSP;
+ }
+ }
+
+ return FileType::Error;
+}
+
+ResultStatus AppLoader_NSP::Load(Kernel::SharedPtr<Kernel::Process>& process) {
+ if (is_loaded) {
+ return ResultStatus::ErrorAlreadyLoaded;
+ }
+
+ if (nsp->IsExtractedType()) {
+ secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(nsp->GetExeFS());
+ } else {
+ if (title_id == 0)
+ return ResultStatus::ErrorNSPMissingProgramNCA;
+
+ secondary_loader = std::make_unique<AppLoader_NCA>(
+ nsp->GetNCAFile(title_id, FileSys::ContentRecordType::Program));
+
+ if (nsp->GetStatus() != ResultStatus::Success)
+ return nsp->GetStatus();
+
+ if (nsp->GetProgramStatus(title_id) != ResultStatus::Success)
+ return nsp->GetProgramStatus(title_id);
+
+ if (nsp->GetNCA(title_id, FileSys::ContentRecordType::Program) == nullptr) {
+ if (!Core::Crypto::KeyManager::KeyFileExists(false))
+ return ResultStatus::ErrorMissingProductionKeyFile;
+ return ResultStatus::ErrorNSPMissingProgramNCA;
+ }
+ }
+
+ const auto result = secondary_loader->Load(process);
+ if (result != ResultStatus::Success)
+ return result;
+
+ is_loaded = true;
+
+ return ResultStatus::Success;
+}
+
+ResultStatus AppLoader_NSP::ReadRomFS(FileSys::VirtualFile& dir) {
+ return secondary_loader->ReadRomFS(dir);
+}
+
+ResultStatus AppLoader_NSP::ReadProgramId(u64& out_program_id) {
+ if (title_id == 0)
+ return ResultStatus::ErrorNotInitialized;
+ out_program_id = title_id;
+ return ResultStatus::Success;
+}
+
+ResultStatus AppLoader_NSP::ReadIcon(std::vector<u8>& buffer) {
+ if (icon_file == nullptr)
+ return ResultStatus::ErrorNoControl;
+ buffer = icon_file->ReadAllBytes();
+ return ResultStatus::Success;
+}
+
+ResultStatus AppLoader_NSP::ReadTitle(std::string& title) {
+ if (nacp_file == nullptr)
+ return ResultStatus::ErrorNoControl;
+ title = nacp_file->GetApplicationName();
+ return ResultStatus::Success;
+}
+} // namespace Loader
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h
new file mode 100644
index 000000000..7ef810499
--- /dev/null
+++ b/src/core/loader/nsp.h
@@ -0,0 +1,54 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include "common/common_types.h"
+#include "core/file_sys/vfs.h"
+#include "core/loader/loader.h"
+
+namespace FileSys {
+class NACP;
+class NSP;
+} // namespace FileSys
+
+namespace Loader {
+
+class AppLoader_NCA;
+
+/// Loads an XCI file
+class AppLoader_NSP final : public AppLoader {
+public:
+ explicit AppLoader_NSP(FileSys::VirtualFile file);
+ ~AppLoader_NSP() override;
+
+ /**
+ * Returns the type of the file
+ * @param file std::shared_ptr<VfsFile> open file
+ * @return FileType found, or FileType::Error if this loader doesn't know it
+ */
+ static FileType IdentifyType(const FileSys::VirtualFile& file);
+
+ FileType GetFileType() override {
+ return IdentifyType(file);
+ }
+
+ ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
+
+ ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
+ ResultStatus ReadProgramId(u64& out_program_id) override;
+ ResultStatus ReadIcon(std::vector<u8>& buffer) override;
+ ResultStatus ReadTitle(std::string& title) override;
+
+private:
+ std::unique_ptr<FileSys::NSP> nsp;
+ std::unique_ptr<AppLoader> secondary_loader;
+
+ FileSys::VirtualFile icon_file;
+ std::shared_ptr<FileSys::NACP> nacp_file;
+ u64 title_id;
+};
+
+} // namespace Loader
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index 9dc4d1f35..16509229f 100644
--- a/src/core/loader/xci.cpp
+++ b/src/core/loader/xci.cpp
@@ -8,7 +8,9 @@
#include "core/file_sys/card_image.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h"
+#include "core/file_sys/patch_manager.h"
#include "core/file_sys/romfs.h"
+#include "core/file_sys/submission_package.h"
#include "core/hle/kernel/process.h"
#include "core/loader/nca.h"
#include "core/loader/xci.h"
@@ -17,25 +19,16 @@ namespace Loader {
AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file)
: AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)),
- nca_loader(std::make_unique<AppLoader_NCA>(
- xci->GetNCAFileByType(FileSys::NCAContentType::Program))) {
+ nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) {
if (xci->GetStatus() != ResultStatus::Success)
return;
+
const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control);
if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success)
return;
- const auto romfs = FileSys::ExtractRomFS(control_nca->GetRomFS());
- if (romfs == nullptr)
- return;
- for (const auto& language : FileSys::LANGUAGE_NAMES) {
- icon_file = romfs->GetFile("icon_" + std::string(language) + ".dat");
- if (icon_file != nullptr)
- break;
- }
- const auto nacp_raw = romfs->GetFile("control.nacp");
- if (nacp_raw == nullptr)
- return;
- nacp_file = std::make_shared<FileSys::NACP>(nacp_raw);
+
+ std::tie(nacp_file, icon_file) =
+ FileSys::PatchManager(xci->GetProgramTitleID()).ParseControlNCA(control_nca);
}
AppLoader_XCI::~AppLoader_XCI() = default;
@@ -64,11 +57,11 @@ ResultStatus AppLoader_XCI::Load(Kernel::SharedPtr<Kernel::Process>& process) {
if (xci->GetProgramNCAStatus() != ResultStatus::Success)
return xci->GetProgramNCAStatus();
- const auto nca = xci->GetNCAFileByType(FileSys::NCAContentType::Program);
+ const auto nca = xci->GetProgramNCA();
if (nca == nullptr && !Core::Crypto::KeyManager::KeyFileExists(false))
return ResultStatus::ErrorMissingProductionKeyFile;
- auto result = nca_loader->Load(process);
+ const auto result = nca_loader->Load(process);
if (result != ResultStatus::Success)
return result;