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.
master
Subv 2017-09-23 20:32:18 +07:00
parent d881dee818
commit 774e7deae8
6 changed files with 66 additions and 19 deletions

@ -3,12 +3,14 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <array> #include <array>
#include <cinttypes>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/swap.h" #include "common/swap.h"
#include "core/file_sys/archive_selfncch.h" #include "core/file_sys/archive_selfncch.h"
#include "core/file_sys/errors.h" #include "core/file_sys/errors.h"
#include "core/file_sys/ivfc_archive.h" #include "core/file_sys/ivfc_archive.h"
#include "core/hle/kernel/process.h"
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace // FileSys namespace
@ -227,38 +229,57 @@ private:
NCCHData ncch_data; NCCHData ncch_data;
}; };
ArchiveFactory_SelfNCCH::ArchiveFactory_SelfNCCH(Loader::AppLoader& app_loader) { void ArchiveFactory_SelfNCCH::Register(Loader::AppLoader& app_loader) {
std::shared_ptr<FileUtil::IOFile> romfs_file; u64 program_id = 0;
if (Loader::ResultStatus::Success == if (app_loader.ReadProgramId(program_id) != Loader::ResultStatus::Success) {
app_loader.ReadRomFS(romfs_file, ncch_data.romfs_offset, ncch_data.romfs_size)) { 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<FileUtil::IOFile> 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<FileUtil::IOFile> update_romfs_file; std::shared_ptr<FileUtil::IOFile> update_romfs_file;
if (Loader::ResultStatus::Success == if (Loader::ResultStatus::Success ==
app_loader.ReadUpdateRomFS(update_romfs_file, ncch_data.update_romfs_offset, app_loader.ReadUpdateRomFS(update_romfs_file, data.update_romfs_offset,
ncch_data.update_romfs_size)) { 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<u8> buffer; std::vector<u8> buffer;
if (Loader::ResultStatus::Success == app_loader.ReadIcon(buffer)) if (Loader::ResultStatus::Success == app_loader.ReadIcon(buffer))
ncch_data.icon = std::make_shared<std::vector<u8>>(std::move(buffer)); data.icon = std::make_shared<std::vector<u8>>(std::move(buffer));
buffer.clear(); buffer.clear();
if (Loader::ResultStatus::Success == app_loader.ReadLogo(buffer)) if (Loader::ResultStatus::Success == app_loader.ReadLogo(buffer))
ncch_data.logo = std::make_shared<std::vector<u8>>(std::move(buffer)); data.logo = std::make_shared<std::vector<u8>>(std::move(buffer));
buffer.clear(); buffer.clear();
if (Loader::ResultStatus::Success == app_loader.ReadBanner(buffer)) if (Loader::ResultStatus::Success == app_loader.ReadBanner(buffer))
ncch_data.banner = std::make_shared<std::vector<u8>>(std::move(buffer)); data.banner = std::make_shared<std::vector<u8>>(std::move(buffer));
} }
ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SelfNCCH::Open(const Path& path) { ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SelfNCCH::Open(const Path& path) {
auto archive = std::make_unique<SelfNCCHArchive>(ncch_data); auto archive = std::make_unique<SelfNCCHArchive>(
ncch_data[Kernel::g_current_process->codeset->program_id]);
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
} }

@ -6,6 +6,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <unordered_map>
#include <vector> #include <vector>
#include "common/common_types.h" #include "common/common_types.h"
#include "core/file_sys/archive_backend.h" #include "core/file_sys/archive_backend.h"
@ -33,7 +34,10 @@ struct NCCHData {
/// File system interface to the SelfNCCH archive /// File system interface to the SelfNCCH archive
class ArchiveFactory_SelfNCCH final : public ArchiveFactory { class ArchiveFactory_SelfNCCH final : public ArchiveFactory {
public: 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 { std::string GetName() const override {
return "SelfNCCH"; return "SelfNCCH";
@ -43,7 +47,8 @@ public:
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
private: private:
NCCHData ncch_data; /// Mapping of ProgramId -> NCCHData
std::unordered_map<u64, NCCHData> ncch_data;
}; };
} // namespace FileSys } // namespace FileSys

@ -20,6 +20,7 @@
#include "core/file_sys/archive_savedata.h" #include "core/file_sys/archive_savedata.h"
#include "core/file_sys/archive_sdmc.h" #include "core/file_sys/archive_sdmc.h"
#include "core/file_sys/archive_sdmcwriteonly.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/archive_systemsavedata.h"
#include "core/file_sys/directory_backend.h" #include "core/file_sys/directory_backend.h"
#include "core/file_sys/errors.h" #include "core/file_sys/errors.h"
@ -48,7 +49,7 @@ struct hash<Service::FS::ArchiveIdCode> {
return std::hash<Type>()(static_cast<Type>(id_code)); return std::hash<Type>()(static_cast<Type>(id_code));
} }
}; };
} } // namespace std
static constexpr Kernel::Handle INVALID_HANDLE{}; static constexpr Kernel::Handle INVALID_HANDLE{};
@ -564,6 +565,21 @@ void RegisterArchiveTypes() {
auto systemsavedata_factory = auto systemsavedata_factory =
std::make_unique<FileSys::ArchiveFactory_SystemSaveData>(nand_directory); std::make_unique<FileSys::ArchiveFactory_SystemSaveData>(nand_directory);
RegisterArchiveType(std::move(systemsavedata_factory), ArchiveIdCode::SystemSaveData); RegisterArchiveType(std::move(systemsavedata_factory), ArchiveIdCode::SystemSaveData);
auto selfncch_factory = std::make_unique<FileSys::ArchiveFactory_SelfNCCH>();
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<FileSys::ArchiveFactory_SelfNCCH*>(itr->second.get());
factory->Register(app_loader);
} }
void UnregisterArchiveTypes() { void UnregisterArchiveTypes() {

@ -21,6 +21,10 @@ static constexpr char SYSTEM_ID[]{"00000000000000000000000000000000"};
/// The scrambled SD card CID, also known as ID1 /// The scrambled SD card CID, also known as ID1
static constexpr char SDCARD_ID[]{"00000000000000000000000000000000"}; static constexpr char SDCARD_ID[]{"00000000000000000000000000000000"};
namespace Loader {
class AppLoader;
}
namespace Service { namespace Service {
namespace FS { namespace FS {
@ -259,6 +263,9 @@ void ArchiveInit();
/// Shutdown archives /// Shutdown archives
void ArchiveShutdown(); void ArchiveShutdown();
/// Registers a new NCCH file with the SelfNCCH archive factory
void RegisterSelfNCCH(Loader::AppLoader& app_loader);
/// Register all archive types /// Register all archive types
void RegisterArchiveTypes(); void RegisterArchiveTypes();

@ -278,8 +278,7 @@ ResultStatus AppLoader_THREEDSX::Load() {
Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE); Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE);
Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_SelfNCCH>(*this), Service::FS::RegisterSelfNCCH(*this);
Service::FS::ArchiveIdCode::SelfNCCH);
is_loaded = true; is_loaded = true;
return ResultStatus::Success; return ResultStatus::Success;

@ -187,8 +187,7 @@ ResultStatus AppLoader_NCCH::Load() {
if (ResultStatus::Success != result) if (ResultStatus::Success != result)
return result; return result;
Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_SelfNCCH>(*this), Service::FS::RegisterSelfNCCH(*this);
Service::FS::ArchiveIdCode::SelfNCCH);
ParseRegionLockoutInfo(); ParseRegionLockoutInfo();