file_sys: Support load game collection (#6582)
Adds support for loading games with multiple programs embedded within such as the Dragon Quest 1+2+3 Collection
This commit is contained in:
parent
16f983d33a
commit
07073734ed
17 changed files with 172 additions and 109 deletions
|
@ -206,7 +206,8 @@ AppLoader::~AppLoader() = default;
|
|||
* @return std::unique_ptr<AppLoader> a pointer to a loader object; nullptr for unsupported type
|
||||
*/
|
||||
static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::VirtualFile file,
|
||||
FileType type, std::size_t program_index) {
|
||||
FileType type, u64 program_id,
|
||||
std::size_t program_index) {
|
||||
switch (type) {
|
||||
// Standard ELF file format.
|
||||
case FileType::ELF:
|
||||
|
@ -227,7 +228,8 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V
|
|||
// NX XCI (nX Card Image) file format.
|
||||
case FileType::XCI:
|
||||
return std::make_unique<AppLoader_XCI>(std::move(file), system.GetFileSystemController(),
|
||||
system.GetContentProvider(), program_index);
|
||||
system.GetContentProvider(), program_id,
|
||||
program_index);
|
||||
|
||||
// NX NAX (NintendoAesXts) file format.
|
||||
case FileType::NAX:
|
||||
|
@ -236,7 +238,8 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V
|
|||
// NX NSP (Nintendo Submission Package) file format
|
||||
case FileType::NSP:
|
||||
return std::make_unique<AppLoader_NSP>(std::move(file), system.GetFileSystemController(),
|
||||
system.GetContentProvider(), program_index);
|
||||
system.GetContentProvider(), program_id,
|
||||
program_index);
|
||||
|
||||
// NX KIP (Kernel Internal Process) file format
|
||||
case FileType::KIP:
|
||||
|
@ -252,7 +255,7 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V
|
|||
}
|
||||
|
||||
std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file,
|
||||
std::size_t program_index) {
|
||||
u64 program_id, std::size_t program_index) {
|
||||
FileType type = IdentifyFile(file);
|
||||
const FileType filename_type = GuessFromFilename(file->GetName());
|
||||
|
||||
|
@ -266,7 +269,7 @@ std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile
|
|||
|
||||
LOG_DEBUG(Loader, "Loading file {} as {}...", file->GetName(), GetFileTypeString(type));
|
||||
|
||||
return GetFileLoader(system, std::move(file), type, program_index);
|
||||
return GetFileLoader(system, std::move(file), type, program_id, program_index);
|
||||
}
|
||||
|
||||
} // namespace Loader
|
||||
|
|
|
@ -226,6 +226,17 @@ public:
|
|||
return ResultStatus::ErrorNotImplemented;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the program ids of the application
|
||||
*
|
||||
* @param[out] out_program_ids Reference to store program ids into
|
||||
*
|
||||
* @return ResultStatus result of function
|
||||
*/
|
||||
virtual ResultStatus ReadProgramIds(std::vector<u64>& out_program_ids) {
|
||||
return ResultStatus::ErrorNotImplemented;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the RomFS of the application
|
||||
* Since the RomFS can be huge, we return a file reference instead of copying to a buffer
|
||||
|
@ -324,6 +335,6 @@ protected:
|
|||
* @return the best loader for this file.
|
||||
*/
|
||||
std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file,
|
||||
std::size_t program_index = 0);
|
||||
u64 program_id = 0, std::size_t program_index = 0);
|
||||
|
||||
} // namespace Loader
|
||||
|
|
|
@ -23,10 +23,9 @@ namespace Loader {
|
|||
|
||||
AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file_,
|
||||
const Service::FileSystem::FileSystemController& fsc,
|
||||
const FileSys::ContentProvider& content_provider,
|
||||
const FileSys::ContentProvider& content_provider, u64 program_id,
|
||||
std::size_t program_index)
|
||||
: AppLoader(file_), nsp(std::make_unique<FileSys::NSP>(file_, program_index)),
|
||||
title_id(nsp->GetProgramTitleID()) {
|
||||
: AppLoader(file_), nsp(std::make_unique<FileSys::NSP>(file_, program_id, program_index)) {
|
||||
|
||||
if (nsp->GetStatus() != ResultStatus::Success) {
|
||||
return;
|
||||
|
@ -46,12 +45,8 @@ AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file_,
|
|||
return pm.ParseControlNCA(*control_nca);
|
||||
}();
|
||||
|
||||
if (title_id == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
secondary_loader = std::make_unique<AppLoader_NCA>(
|
||||
nsp->GetNCAFile(title_id, FileSys::ContentRecordType::Program));
|
||||
nsp->GetNCAFile(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Program));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,10 +63,11 @@ FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& nsp_file) {
|
|||
}
|
||||
|
||||
// Non-Extracted Type case
|
||||
const auto program_id = nsp.GetProgramTitleID();
|
||||
if (!nsp.IsExtractedType() &&
|
||||
nsp.GetNCA(nsp.GetFirstTitleID(), FileSys::ContentRecordType::Program) != nullptr &&
|
||||
AppLoader_NCA::IdentifyType(nsp.GetNCAFile(
|
||||
nsp.GetFirstTitleID(), FileSys::ContentRecordType::Program)) == FileType::NCA) {
|
||||
nsp.GetNCA(program_id, FileSys::ContentRecordType::Program) != nullptr &&
|
||||
AppLoader_NCA::IdentifyType(
|
||||
nsp.GetNCAFile(program_id, FileSys::ContentRecordType::Program)) == FileType::NCA) {
|
||||
return FileType::NSP;
|
||||
}
|
||||
}
|
||||
|
@ -84,6 +80,8 @@ AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::KProcess& process, Core::S
|
|||
return {ResultStatus::ErrorAlreadyLoaded, {}};
|
||||
}
|
||||
|
||||
const auto title_id = nsp->GetProgramTitleID();
|
||||
|
||||
if (!nsp->IsExtractedType() && title_id == 0) {
|
||||
return {ResultStatus::ErrorNSPMissingProgramNCA, {}};
|
||||
}
|
||||
|
@ -93,7 +91,7 @@ AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::KProcess& process, Core::S
|
|||
return {nsp_status, {}};
|
||||
}
|
||||
|
||||
const auto nsp_program_status = nsp->GetProgramStatus(title_id);
|
||||
const auto nsp_program_status = nsp->GetProgramStatus();
|
||||
if (nsp_program_status != ResultStatus::Success) {
|
||||
return {nsp_program_status, {}};
|
||||
}
|
||||
|
@ -134,8 +132,8 @@ ResultStatus AppLoader_NSP::ReadUpdateRaw(FileSys::VirtualFile& out_file) {
|
|||
return ResultStatus::ErrorNoPackedUpdate;
|
||||
}
|
||||
|
||||
const auto read =
|
||||
nsp->GetNCAFile(FileSys::GetUpdateTitleID(title_id), FileSys::ContentRecordType::Program);
|
||||
const auto read = nsp->GetNCAFile(FileSys::GetUpdateTitleID(nsp->GetProgramTitleID()),
|
||||
FileSys::ContentRecordType::Program);
|
||||
|
||||
if (read == nullptr) {
|
||||
return ResultStatus::ErrorNoPackedUpdate;
|
||||
|
@ -151,11 +149,15 @@ ResultStatus AppLoader_NSP::ReadUpdateRaw(FileSys::VirtualFile& out_file) {
|
|||
}
|
||||
|
||||
ResultStatus AppLoader_NSP::ReadProgramId(u64& out_program_id) {
|
||||
if (title_id == 0) {
|
||||
out_program_id = nsp->GetProgramTitleID();
|
||||
if (out_program_id == 0) {
|
||||
return ResultStatus::ErrorNotInitialized;
|
||||
}
|
||||
return ResultStatus::Success;
|
||||
}
|
||||
|
||||
out_program_id = title_id;
|
||||
ResultStatus AppLoader_NSP::ReadProgramIds(std::vector<u64>& out_program_ids) {
|
||||
out_program_ids = nsp->GetProgramTitleIDs();
|
||||
return ResultStatus::Success;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ class AppLoader_NSP final : public AppLoader {
|
|||
public:
|
||||
explicit AppLoader_NSP(FileSys::VirtualFile file_,
|
||||
const Service::FileSystem::FileSystemController& fsc,
|
||||
const FileSys::ContentProvider& content_provider,
|
||||
const FileSys::ContentProvider& content_provider, u64 program_id,
|
||||
std::size_t program_index);
|
||||
~AppLoader_NSP() override;
|
||||
|
||||
|
@ -51,6 +51,7 @@ public:
|
|||
u64 ReadRomFSIVFCOffset() const override;
|
||||
ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) override;
|
||||
ResultStatus ReadProgramId(u64& out_program_id) override;
|
||||
ResultStatus ReadProgramIds(std::vector<u64>& out_program_ids) override;
|
||||
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
|
||||
ResultStatus ReadTitle(std::string& title) override;
|
||||
ResultStatus ReadControlData(FileSys::NACP& nacp) override;
|
||||
|
@ -67,7 +68,6 @@ private:
|
|||
|
||||
FileSys::VirtualFile icon_file;
|
||||
std::unique_ptr<FileSys::NACP> nacp_file;
|
||||
u64 title_id;
|
||||
};
|
||||
|
||||
} // namespace Loader
|
||||
|
|
|
@ -22,9 +22,9 @@ namespace Loader {
|
|||
|
||||
AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file_,
|
||||
const Service::FileSystem::FileSystemController& fsc,
|
||||
const FileSys::ContentProvider& content_provider,
|
||||
const FileSys::ContentProvider& content_provider, u64 program_id,
|
||||
std::size_t program_index)
|
||||
: AppLoader(file_), xci(std::make_unique<FileSys::XCI>(file_, program_index)),
|
||||
: AppLoader(file_), xci(std::make_unique<FileSys::XCI>(file_, program_id, program_index)),
|
||||
nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) {
|
||||
if (xci->GetStatus() != ResultStatus::Success) {
|
||||
return;
|
||||
|
@ -121,6 +121,11 @@ ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) {
|
|||
return nca_loader->ReadProgramId(out_program_id);
|
||||
}
|
||||
|
||||
ResultStatus AppLoader_XCI::ReadProgramIds(std::vector<u64>& out_program_ids) {
|
||||
out_program_ids = xci->GetProgramTitleIDs();
|
||||
return ResultStatus::Success;
|
||||
}
|
||||
|
||||
ResultStatus AppLoader_XCI::ReadIcon(std::vector<u8>& buffer) {
|
||||
if (icon_file == nullptr) {
|
||||
return ResultStatus::ErrorNoControl;
|
||||
|
@ -149,8 +154,9 @@ ResultStatus AppLoader_XCI::ReadControlData(FileSys::NACP& control) {
|
|||
}
|
||||
|
||||
ResultStatus AppLoader_XCI::ReadManualRomFS(FileSys::VirtualFile& out_file) {
|
||||
const auto nca = xci->GetSecurePartitionNSP()->GetNCA(xci->GetProgramTitleID(),
|
||||
FileSys::ContentRecordType::HtmlDocument);
|
||||
const auto nca =
|
||||
xci->GetSecurePartitionNSP()->GetNCA(xci->GetSecurePartitionNSP()->GetProgramTitleID(),
|
||||
FileSys::ContentRecordType::HtmlDocument);
|
||||
if (xci->GetStatus() != ResultStatus::Success || nca == nullptr) {
|
||||
return ResultStatus::ErrorXCIMissingPartition;
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ class AppLoader_XCI final : public AppLoader {
|
|||
public:
|
||||
explicit AppLoader_XCI(FileSys::VirtualFile file_,
|
||||
const Service::FileSystem::FileSystemController& fsc,
|
||||
const FileSys::ContentProvider& content_provider,
|
||||
const FileSys::ContentProvider& content_provider, u64 program_id,
|
||||
std::size_t program_index);
|
||||
~AppLoader_XCI() override;
|
||||
|
||||
|
@ -51,6 +51,7 @@ public:
|
|||
u64 ReadRomFSIVFCOffset() const override;
|
||||
ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) override;
|
||||
ResultStatus ReadProgramId(u64& out_program_id) override;
|
||||
ResultStatus ReadProgramIds(std::vector<u64>& out_program_ids) override;
|
||||
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
|
||||
ResultStatus ReadTitle(std::string& title) override;
|
||||
ResultStatus ReadControlData(FileSys::NACP& control) override;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue