From 774e7deae8655a6f09530770c56ae2e75d55309b Mon Sep 17 00:00:00 2001 From: Subv Date: Sat, 23 Sep 2017 20:32:18 -0500 Subject: [PATCH] HLE/Archives: Allow multiple loaded applications to access their SelfNCCH archive independently. The loaders now register each loaded ROM with the SelfNCCH factory, which keeps the data around for the duration of the emulation session. When opening the SelfNCCH archive, the factory queries the current program's programid and uses that as a key to the map that contains the NCCHData structure (RomFS, Icon, Banner, etc). 3dsx files do not have a programid and will use a default of 0 for this value, thus, only 1 3dsx file with RomFS is loadable at the same time. --- src/core/file_sys/archive_selfncch.cpp | 45 +++++++++++++++++++------- src/core/file_sys/archive_selfncch.h | 9 ++++-- src/core/hle/service/fs/archive.cpp | 18 ++++++++++- src/core/hle/service/fs/archive.h | 7 ++++ src/core/loader/3dsx.cpp | 3 +- src/core/loader/ncch.cpp | 3 +- 6 files changed, 66 insertions(+), 19 deletions(-) diff --git a/src/core/file_sys/archive_selfncch.cpp b/src/core/file_sys/archive_selfncch.cpp index 7dc91a405..a16941c70 100644 --- a/src/core/file_sys/archive_selfncch.cpp +++ b/src/core/file_sys/archive_selfncch.cpp @@ -3,12 +3,14 @@ // Refer to the license.txt file included. #include +#include #include "common/common_types.h" #include "common/logging/log.h" #include "common/swap.h" #include "core/file_sys/archive_selfncch.h" #include "core/file_sys/errors.h" #include "core/file_sys/ivfc_archive.h" +#include "core/hle/kernel/process.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // FileSys namespace @@ -227,38 +229,57 @@ private: NCCHData ncch_data; }; -ArchiveFactory_SelfNCCH::ArchiveFactory_SelfNCCH(Loader::AppLoader& app_loader) { - std::shared_ptr romfs_file; - if (Loader::ResultStatus::Success == - app_loader.ReadRomFS(romfs_file, ncch_data.romfs_offset, ncch_data.romfs_size)) { +void ArchiveFactory_SelfNCCH::Register(Loader::AppLoader& app_loader) { + u64 program_id = 0; + if (app_loader.ReadProgramId(program_id) != Loader::ResultStatus::Success) { + LOG_WARNING( + Service_FS, + "Could not read program id when registering with SelfNCCH, this might be a 3dsx file"); + } - ncch_data.romfs_file = std::move(romfs_file); + LOG_DEBUG(Service_FS, "Registering program %016" PRIX64 " with the SelfNCCH archive factory", + program_id); + + if (ncch_data.find(program_id) != ncch_data.end()) { + LOG_WARNING(Service_FS, "Registering program %016" PRIX64 + " with SelfNCCH will override existing mapping", + program_id); + } + + NCCHData& data = ncch_data[program_id]; + + std::shared_ptr romfs_file_; + if (Loader::ResultStatus::Success == + app_loader.ReadRomFS(romfs_file_, data.romfs_offset, data.romfs_size)) { + + data.romfs_file = std::move(romfs_file_); } std::shared_ptr update_romfs_file; if (Loader::ResultStatus::Success == - app_loader.ReadUpdateRomFS(update_romfs_file, ncch_data.update_romfs_offset, - ncch_data.update_romfs_size)) { + app_loader.ReadUpdateRomFS(update_romfs_file, data.update_romfs_offset, + data.update_romfs_size)) { - ncch_data.update_romfs_file = std::move(update_romfs_file); + data.update_romfs_file = std::move(update_romfs_file); } std::vector buffer; if (Loader::ResultStatus::Success == app_loader.ReadIcon(buffer)) - ncch_data.icon = std::make_shared>(std::move(buffer)); + data.icon = std::make_shared>(std::move(buffer)); buffer.clear(); if (Loader::ResultStatus::Success == app_loader.ReadLogo(buffer)) - ncch_data.logo = std::make_shared>(std::move(buffer)); + data.logo = std::make_shared>(std::move(buffer)); buffer.clear(); if (Loader::ResultStatus::Success == app_loader.ReadBanner(buffer)) - ncch_data.banner = std::make_shared>(std::move(buffer)); + data.banner = std::make_shared>(std::move(buffer)); } ResultVal> ArchiveFactory_SelfNCCH::Open(const Path& path) { - auto archive = std::make_unique(ncch_data); + auto archive = std::make_unique( + ncch_data[Kernel::g_current_process->codeset->program_id]); return MakeResult>(std::move(archive)); } diff --git a/src/core/file_sys/archive_selfncch.h b/src/core/file_sys/archive_selfncch.h index f1c659948..0d6d6766e 100644 --- a/src/core/file_sys/archive_selfncch.h +++ b/src/core/file_sys/archive_selfncch.h @@ -6,6 +6,7 @@ #include #include +#include #include #include "common/common_types.h" #include "core/file_sys/archive_backend.h" @@ -33,7 +34,10 @@ struct NCCHData { /// File system interface to the SelfNCCH archive class ArchiveFactory_SelfNCCH final : public ArchiveFactory { public: - explicit ArchiveFactory_SelfNCCH(Loader::AppLoader& app_loader); + ArchiveFactory_SelfNCCH() = default; + + /// Registers a loaded application so that we can open its SelfNCCH archive when requested. + void Register(Loader::AppLoader& app_loader); std::string GetName() const override { return "SelfNCCH"; @@ -43,7 +47,8 @@ public: ResultVal GetFormatInfo(const Path& path) const override; private: - NCCHData ncch_data; + /// Mapping of ProgramId -> NCCHData + std::unordered_map ncch_data; }; } // namespace FileSys diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 033fbc9aa..4ccb3cd32 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -20,6 +20,7 @@ #include "core/file_sys/archive_savedata.h" #include "core/file_sys/archive_sdmc.h" #include "core/file_sys/archive_sdmcwriteonly.h" +#include "core/file_sys/archive_selfncch.h" #include "core/file_sys/archive_systemsavedata.h" #include "core/file_sys/directory_backend.h" #include "core/file_sys/errors.h" @@ -48,7 +49,7 @@ struct hash { return std::hash()(static_cast(id_code)); } }; -} +} // namespace std static constexpr Kernel::Handle INVALID_HANDLE{}; @@ -564,6 +565,21 @@ void RegisterArchiveTypes() { auto systemsavedata_factory = std::make_unique(nand_directory); RegisterArchiveType(std::move(systemsavedata_factory), ArchiveIdCode::SystemSaveData); + + auto selfncch_factory = std::make_unique(); + RegisterArchiveType(std::move(selfncch_factory), ArchiveIdCode::SelfNCCH); +} + +void RegisterSelfNCCH(Loader::AppLoader& app_loader) { + auto itr = id_code_map.find(ArchiveIdCode::SelfNCCH); + if (itr == id_code_map.end()) { + LOG_ERROR(Service_FS, + "Could not register a new NCCH because the SelfNCCH archive hasn't been created"); + return; + } + + auto* factory = static_cast(itr->second.get()); + factory->Register(app_loader); } void UnregisterArchiveTypes() { diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index 3a3371c88..e3c8fc2ef 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -21,6 +21,10 @@ static constexpr char SYSTEM_ID[]{"00000000000000000000000000000000"}; /// The scrambled SD card CID, also known as ID1 static constexpr char SDCARD_ID[]{"00000000000000000000000000000000"}; +namespace Loader { +class AppLoader; +} + namespace Service { namespace FS { @@ -259,6 +263,9 @@ void ArchiveInit(); /// Shutdown archives void ArchiveShutdown(); +/// Registers a new NCCH file with the SelfNCCH archive factory +void RegisterSelfNCCH(Loader::AppLoader& app_loader); + /// Register all archive types void RegisterArchiveTypes(); diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp index a03515e6e..5ad5c5287 100644 --- a/src/core/loader/3dsx.cpp +++ b/src/core/loader/3dsx.cpp @@ -278,8 +278,7 @@ ResultStatus AppLoader_THREEDSX::Load() { Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE); - Service::FS::RegisterArchiveType(std::make_unique(*this), - Service::FS::ArchiveIdCode::SelfNCCH); + Service::FS::RegisterSelfNCCH(*this); is_loaded = true; return ResultStatus::Success; diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index c46d7cfc6..5107135f9 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp @@ -187,8 +187,7 @@ ResultStatus AppLoader_NCCH::Load() { if (ResultStatus::Success != result) return result; - Service::FS::RegisterArchiveType(std::make_unique(*this), - Service::FS::ArchiveIdCode::SelfNCCH); + Service::FS::RegisterSelfNCCH(*this); ParseRegionLockoutInfo();