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.cpp42
-rw-r--r--src/core/loader/deconstructed_rom_directory.h8
-rw-r--r--src/core/loader/loader.cpp13
-rw-r--r--src/core/loader/loader.h29
-rw-r--r--src/core/loader/nca.cpp8
-rw-r--r--src/core/loader/nca.h1
-rw-r--r--src/core/loader/nro.cpp5
-rw-r--r--src/core/loader/nro.h1
-rw-r--r--src/core/loader/nsp.cpp20
-rw-r--r--src/core/loader/xci.cpp18
10 files changed, 101 insertions, 44 deletions
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 1ae4bb656..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) {
@@ -66,8 +76,9 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys
}
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())) {
@@ -89,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;
@@ -97,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()};
@@ -119,7 +146,6 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
}
auto& kernel = Core::System::GetInstance().Kernel();
- title_id = metadata.GetTitleID();
process->program_id = metadata.GetTitleID();
process->svc_access_mask.set();
process->resource_limit =
@@ -170,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/loader.cpp b/src/core/loader/loader.cpp
index 446adf557..fa43a2650 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -93,7 +93,7 @@ std::string GetFileTypeString(FileType type) {
return "unknown";
}
-constexpr std::array<const char*, 50> 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.",
@@ -143,7 +143,16 @@ constexpr std::array<const char*, 50> 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 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));
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index be66b2257..843c4bb91 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -107,6 +107,14 @@ enum class ResultStatus : u16 {
ErrorMissingSDSaveKeySource,
ErrorMissingSDNCAKeySource,
ErrorNSPMissingProgramNCA,
+ ErrorBadBKTRHeader,
+ ErrorBKTRSubsectionNotAfterRelocation,
+ ErrorBKTRSubsectionNotAtEnd,
+ ErrorBadRelocationBlock,
+ ErrorBadSubsectionBlock,
+ ErrorBadRelocationBuckets,
+ ErrorBadSubsectionBuckets,
+ ErrorMissingBKTRBaseRomFS,
};
std::ostream& operator<<(std::ostream& os, ResultStatus status);
@@ -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/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..bb89a9da3 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -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/nsp.cpp b/src/core/loader/nsp.cpp
index 7c06239f2..291a9876d 100644
--- a/src/core/loader/nsp.cpp
+++ b/src/core/loader/nsp.cpp
@@ -9,6 +9,8 @@
#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"
@@ -28,24 +30,12 @@ AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file)
return;
const auto control_nca =
- nsp->GetNCA(nsp->GetFirstTitleID(), FileSys::ContentRecordType::Control);
+ nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::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(nsp->GetProgramTitleID()).ParseControlNCA(control_nca);
}
AppLoader_NSP::~AppLoader_NSP() = default;
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index 75b998faa..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"
@@ -20,21 +22,13 @@ AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file)
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;