diff options
| author | 2021-07-20 13:10:05 +0800 | |
|---|---|---|
| committer | 2021-07-20 01:10:05 -0400 | |
| commit | 07073734ed3785d1dee487f0c898a645fbd5f03c (patch) | |
| tree | e7c72b615b7a551cc1fb8a6a336bce60e5a0d314 /src/core/loader | |
| parent | Merge pull request #6580 from ReinUsesLisp/xfb-radv (diff) | |
| download | yuzu-07073734ed3785d1dee487f0c898a645fbd5f03c.tar.gz yuzu-07073734ed3785d1dee487f0c898a645fbd5f03c.tar.xz yuzu-07073734ed3785d1dee487f0c898a645fbd5f03c.zip | |
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
Diffstat (limited to 'src/core/loader')
| -rw-r--r-- | src/core/loader/loader.cpp | 13 | ||||
| -rw-r--r-- | src/core/loader/loader.h | 13 | ||||
| -rw-r--r-- | src/core/loader/nsp.cpp | 34 | ||||
| -rw-r--r-- | src/core/loader/nsp.h | 4 | ||||
| -rw-r--r-- | src/core/loader/xci.cpp | 14 | ||||
| -rw-r--r-- | src/core/loader/xci.h | 3 |
6 files changed, 52 insertions, 29 deletions
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 228dc6389..199e69e89 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp | |||
| @@ -206,7 +206,8 @@ AppLoader::~AppLoader() = default; | |||
| 206 | * @return std::unique_ptr<AppLoader> a pointer to a loader object; nullptr for unsupported type | 206 | * @return std::unique_ptr<AppLoader> a pointer to a loader object; nullptr for unsupported type |
| 207 | */ | 207 | */ |
| 208 | static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::VirtualFile file, | 208 | static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::VirtualFile file, |
| 209 | FileType type, std::size_t program_index) { | 209 | FileType type, u64 program_id, |
| 210 | std::size_t program_index) { | ||
| 210 | switch (type) { | 211 | switch (type) { |
| 211 | // Standard ELF file format. | 212 | // Standard ELF file format. |
| 212 | case FileType::ELF: | 213 | case FileType::ELF: |
| @@ -227,7 +228,8 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V | |||
| 227 | // NX XCI (nX Card Image) file format. | 228 | // NX XCI (nX Card Image) file format. |
| 228 | case FileType::XCI: | 229 | case FileType::XCI: |
| 229 | return std::make_unique<AppLoader_XCI>(std::move(file), system.GetFileSystemController(), | 230 | return std::make_unique<AppLoader_XCI>(std::move(file), system.GetFileSystemController(), |
| 230 | system.GetContentProvider(), program_index); | 231 | system.GetContentProvider(), program_id, |
| 232 | program_index); | ||
| 231 | 233 | ||
| 232 | // NX NAX (NintendoAesXts) file format. | 234 | // NX NAX (NintendoAesXts) file format. |
| 233 | case FileType::NAX: | 235 | case FileType::NAX: |
| @@ -236,7 +238,8 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V | |||
| 236 | // NX NSP (Nintendo Submission Package) file format | 238 | // NX NSP (Nintendo Submission Package) file format |
| 237 | case FileType::NSP: | 239 | case FileType::NSP: |
| 238 | return std::make_unique<AppLoader_NSP>(std::move(file), system.GetFileSystemController(), | 240 | return std::make_unique<AppLoader_NSP>(std::move(file), system.GetFileSystemController(), |
| 239 | system.GetContentProvider(), program_index); | 241 | system.GetContentProvider(), program_id, |
| 242 | program_index); | ||
| 240 | 243 | ||
| 241 | // NX KIP (Kernel Internal Process) file format | 244 | // NX KIP (Kernel Internal Process) file format |
| 242 | case FileType::KIP: | 245 | case FileType::KIP: |
| @@ -252,7 +255,7 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V | |||
| 252 | } | 255 | } |
| 253 | 256 | ||
| 254 | std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file, | 257 | std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file, |
| 255 | std::size_t program_index) { | 258 | u64 program_id, std::size_t program_index) { |
| 256 | FileType type = IdentifyFile(file); | 259 | FileType type = IdentifyFile(file); |
| 257 | const FileType filename_type = GuessFromFilename(file->GetName()); | 260 | const FileType filename_type = GuessFromFilename(file->GetName()); |
| 258 | 261 | ||
| @@ -266,7 +269,7 @@ std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile | |||
| 266 | 269 | ||
| 267 | LOG_DEBUG(Loader, "Loading file {} as {}...", file->GetName(), GetFileTypeString(type)); | 270 | LOG_DEBUG(Loader, "Loading file {} as {}...", file->GetName(), GetFileTypeString(type)); |
| 268 | 271 | ||
| 269 | return GetFileLoader(system, std::move(file), type, program_index); | 272 | return GetFileLoader(system, std::move(file), type, program_id, program_index); |
| 270 | } | 273 | } |
| 271 | 274 | ||
| 272 | } // namespace Loader | 275 | } // namespace Loader |
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index edc8bb257..7b1bac3f7 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h | |||
| @@ -227,6 +227,17 @@ public: | |||
| 227 | } | 227 | } |
| 228 | 228 | ||
| 229 | /** | 229 | /** |
| 230 | * Get the program ids of the application | ||
| 231 | * | ||
| 232 | * @param[out] out_program_ids Reference to store program ids into | ||
| 233 | * | ||
| 234 | * @return ResultStatus result of function | ||
| 235 | */ | ||
| 236 | virtual ResultStatus ReadProgramIds(std::vector<u64>& out_program_ids) { | ||
| 237 | return ResultStatus::ErrorNotImplemented; | ||
| 238 | } | ||
| 239 | |||
| 240 | /** | ||
| 230 | * Get the RomFS of the application | 241 | * Get the RomFS of the application |
| 231 | * Since the RomFS can be huge, we return a file reference instead of copying to a buffer | 242 | * Since the RomFS can be huge, we return a file reference instead of copying to a buffer |
| 232 | * | 243 | * |
| @@ -324,6 +335,6 @@ protected: | |||
| 324 | * @return the best loader for this file. | 335 | * @return the best loader for this file. |
| 325 | */ | 336 | */ |
| 326 | std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file, | 337 | std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file, |
| 327 | std::size_t program_index = 0); | 338 | u64 program_id = 0, std::size_t program_index = 0); |
| 328 | 339 | ||
| 329 | } // namespace Loader | 340 | } // namespace Loader |
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index d815a7cd3..8b167ad3c 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp | |||
| @@ -23,10 +23,9 @@ namespace Loader { | |||
| 23 | 23 | ||
| 24 | AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file_, | 24 | AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file_, |
| 25 | const Service::FileSystem::FileSystemController& fsc, | 25 | const Service::FileSystem::FileSystemController& fsc, |
| 26 | const FileSys::ContentProvider& content_provider, | 26 | const FileSys::ContentProvider& content_provider, u64 program_id, |
| 27 | std::size_t program_index) | 27 | std::size_t program_index) |
| 28 | : AppLoader(file_), nsp(std::make_unique<FileSys::NSP>(file_, program_index)), | 28 | : AppLoader(file_), nsp(std::make_unique<FileSys::NSP>(file_, program_id, program_index)) { |
| 29 | title_id(nsp->GetProgramTitleID()) { | ||
| 30 | 29 | ||
| 31 | if (nsp->GetStatus() != ResultStatus::Success) { | 30 | if (nsp->GetStatus() != ResultStatus::Success) { |
| 32 | return; | 31 | return; |
| @@ -46,12 +45,8 @@ AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file_, | |||
| 46 | return pm.ParseControlNCA(*control_nca); | 45 | return pm.ParseControlNCA(*control_nca); |
| 47 | }(); | 46 | }(); |
| 48 | 47 | ||
| 49 | if (title_id == 0) { | ||
| 50 | return; | ||
| 51 | } | ||
| 52 | |||
| 53 | secondary_loader = std::make_unique<AppLoader_NCA>( | 48 | secondary_loader = std::make_unique<AppLoader_NCA>( |
| 54 | nsp->GetNCAFile(title_id, FileSys::ContentRecordType::Program)); | 49 | nsp->GetNCAFile(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Program)); |
| 55 | } | 50 | } |
| 56 | } | 51 | } |
| 57 | 52 | ||
| @@ -68,10 +63,11 @@ FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& nsp_file) { | |||
| 68 | } | 63 | } |
| 69 | 64 | ||
| 70 | // Non-Extracted Type case | 65 | // Non-Extracted Type case |
| 66 | const auto program_id = nsp.GetProgramTitleID(); | ||
| 71 | if (!nsp.IsExtractedType() && | 67 | if (!nsp.IsExtractedType() && |
| 72 | nsp.GetNCA(nsp.GetFirstTitleID(), FileSys::ContentRecordType::Program) != nullptr && | 68 | nsp.GetNCA(program_id, FileSys::ContentRecordType::Program) != nullptr && |
| 73 | AppLoader_NCA::IdentifyType(nsp.GetNCAFile( | 69 | AppLoader_NCA::IdentifyType( |
| 74 | nsp.GetFirstTitleID(), FileSys::ContentRecordType::Program)) == FileType::NCA) { | 70 | nsp.GetNCAFile(program_id, FileSys::ContentRecordType::Program)) == FileType::NCA) { |
| 75 | return FileType::NSP; | 71 | return FileType::NSP; |
| 76 | } | 72 | } |
| 77 | } | 73 | } |
| @@ -84,6 +80,8 @@ AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::KProcess& process, Core::S | |||
| 84 | return {ResultStatus::ErrorAlreadyLoaded, {}}; | 80 | return {ResultStatus::ErrorAlreadyLoaded, {}}; |
| 85 | } | 81 | } |
| 86 | 82 | ||
| 83 | const auto title_id = nsp->GetProgramTitleID(); | ||
| 84 | |||
| 87 | if (!nsp->IsExtractedType() && title_id == 0) { | 85 | if (!nsp->IsExtractedType() && title_id == 0) { |
| 88 | return {ResultStatus::ErrorNSPMissingProgramNCA, {}}; | 86 | return {ResultStatus::ErrorNSPMissingProgramNCA, {}}; |
| 89 | } | 87 | } |
| @@ -93,7 +91,7 @@ AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::KProcess& process, Core::S | |||
| 93 | return {nsp_status, {}}; | 91 | return {nsp_status, {}}; |
| 94 | } | 92 | } |
| 95 | 93 | ||
| 96 | const auto nsp_program_status = nsp->GetProgramStatus(title_id); | 94 | const auto nsp_program_status = nsp->GetProgramStatus(); |
| 97 | if (nsp_program_status != ResultStatus::Success) { | 95 | if (nsp_program_status != ResultStatus::Success) { |
| 98 | return {nsp_program_status, {}}; | 96 | return {nsp_program_status, {}}; |
| 99 | } | 97 | } |
| @@ -134,8 +132,8 @@ ResultStatus AppLoader_NSP::ReadUpdateRaw(FileSys::VirtualFile& out_file) { | |||
| 134 | return ResultStatus::ErrorNoPackedUpdate; | 132 | return ResultStatus::ErrorNoPackedUpdate; |
| 135 | } | 133 | } |
| 136 | 134 | ||
| 137 | const auto read = | 135 | const auto read = nsp->GetNCAFile(FileSys::GetUpdateTitleID(nsp->GetProgramTitleID()), |
| 138 | nsp->GetNCAFile(FileSys::GetUpdateTitleID(title_id), FileSys::ContentRecordType::Program); | 136 | FileSys::ContentRecordType::Program); |
| 139 | 137 | ||
| 140 | if (read == nullptr) { | 138 | if (read == nullptr) { |
| 141 | return ResultStatus::ErrorNoPackedUpdate; | 139 | return ResultStatus::ErrorNoPackedUpdate; |
| @@ -151,11 +149,15 @@ ResultStatus AppLoader_NSP::ReadUpdateRaw(FileSys::VirtualFile& out_file) { | |||
| 151 | } | 149 | } |
| 152 | 150 | ||
| 153 | ResultStatus AppLoader_NSP::ReadProgramId(u64& out_program_id) { | 151 | ResultStatus AppLoader_NSP::ReadProgramId(u64& out_program_id) { |
| 154 | if (title_id == 0) { | 152 | out_program_id = nsp->GetProgramTitleID(); |
| 153 | if (out_program_id == 0) { | ||
| 155 | return ResultStatus::ErrorNotInitialized; | 154 | return ResultStatus::ErrorNotInitialized; |
| 156 | } | 155 | } |
| 156 | return ResultStatus::Success; | ||
| 157 | } | ||
| 157 | 158 | ||
| 158 | out_program_id = title_id; | 159 | ResultStatus AppLoader_NSP::ReadProgramIds(std::vector<u64>& out_program_ids) { |
| 160 | out_program_ids = nsp->GetProgramTitleIDs(); | ||
| 159 | return ResultStatus::Success; | 161 | return ResultStatus::Success; |
| 160 | } | 162 | } |
| 161 | 163 | ||
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h index 644c0ff58..50406a92e 100644 --- a/src/core/loader/nsp.h +++ b/src/core/loader/nsp.h | |||
| @@ -28,7 +28,7 @@ class AppLoader_NSP final : public AppLoader { | |||
| 28 | public: | 28 | public: |
| 29 | explicit AppLoader_NSP(FileSys::VirtualFile file_, | 29 | explicit AppLoader_NSP(FileSys::VirtualFile file_, |
| 30 | const Service::FileSystem::FileSystemController& fsc, | 30 | const Service::FileSystem::FileSystemController& fsc, |
| 31 | const FileSys::ContentProvider& content_provider, | 31 | const FileSys::ContentProvider& content_provider, u64 program_id, |
| 32 | std::size_t program_index); | 32 | std::size_t program_index); |
| 33 | ~AppLoader_NSP() override; | 33 | ~AppLoader_NSP() override; |
| 34 | 34 | ||
| @@ -51,6 +51,7 @@ public: | |||
| 51 | u64 ReadRomFSIVFCOffset() const override; | 51 | u64 ReadRomFSIVFCOffset() const override; |
| 52 | ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) override; | 52 | ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) override; |
| 53 | ResultStatus ReadProgramId(u64& out_program_id) override; | 53 | ResultStatus ReadProgramId(u64& out_program_id) override; |
| 54 | ResultStatus ReadProgramIds(std::vector<u64>& out_program_ids) override; | ||
| 54 | ResultStatus ReadIcon(std::vector<u8>& buffer) override; | 55 | ResultStatus ReadIcon(std::vector<u8>& buffer) override; |
| 55 | ResultStatus ReadTitle(std::string& title) override; | 56 | ResultStatus ReadTitle(std::string& title) override; |
| 56 | ResultStatus ReadControlData(FileSys::NACP& nacp) override; | 57 | ResultStatus ReadControlData(FileSys::NACP& nacp) override; |
| @@ -67,7 +68,6 @@ private: | |||
| 67 | 68 | ||
| 68 | FileSys::VirtualFile icon_file; | 69 | FileSys::VirtualFile icon_file; |
| 69 | std::unique_ptr<FileSys::NACP> nacp_file; | 70 | std::unique_ptr<FileSys::NACP> nacp_file; |
| 70 | u64 title_id; | ||
| 71 | }; | 71 | }; |
| 72 | 72 | ||
| 73 | } // namespace Loader | 73 | } // namespace Loader |
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index 635d6ae15..269603eef 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp | |||
| @@ -22,9 +22,9 @@ namespace Loader { | |||
| 22 | 22 | ||
| 23 | AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file_, | 23 | AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file_, |
| 24 | const Service::FileSystem::FileSystemController& fsc, | 24 | const Service::FileSystem::FileSystemController& fsc, |
| 25 | const FileSys::ContentProvider& content_provider, | 25 | const FileSys::ContentProvider& content_provider, u64 program_id, |
| 26 | std::size_t program_index) | 26 | std::size_t program_index) |
| 27 | : AppLoader(file_), xci(std::make_unique<FileSys::XCI>(file_, program_index)), | 27 | : AppLoader(file_), xci(std::make_unique<FileSys::XCI>(file_, program_id, program_index)), |
| 28 | nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) { | 28 | nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) { |
| 29 | if (xci->GetStatus() != ResultStatus::Success) { | 29 | if (xci->GetStatus() != ResultStatus::Success) { |
| 30 | return; | 30 | return; |
| @@ -121,6 +121,11 @@ ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) { | |||
| 121 | return nca_loader->ReadProgramId(out_program_id); | 121 | return nca_loader->ReadProgramId(out_program_id); |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | ResultStatus AppLoader_XCI::ReadProgramIds(std::vector<u64>& out_program_ids) { | ||
| 125 | out_program_ids = xci->GetProgramTitleIDs(); | ||
| 126 | return ResultStatus::Success; | ||
| 127 | } | ||
| 128 | |||
| 124 | ResultStatus AppLoader_XCI::ReadIcon(std::vector<u8>& buffer) { | 129 | ResultStatus AppLoader_XCI::ReadIcon(std::vector<u8>& buffer) { |
| 125 | if (icon_file == nullptr) { | 130 | if (icon_file == nullptr) { |
| 126 | return ResultStatus::ErrorNoControl; | 131 | return ResultStatus::ErrorNoControl; |
| @@ -149,8 +154,9 @@ ResultStatus AppLoader_XCI::ReadControlData(FileSys::NACP& control) { | |||
| 149 | } | 154 | } |
| 150 | 155 | ||
| 151 | ResultStatus AppLoader_XCI::ReadManualRomFS(FileSys::VirtualFile& out_file) { | 156 | ResultStatus AppLoader_XCI::ReadManualRomFS(FileSys::VirtualFile& out_file) { |
| 152 | const auto nca = xci->GetSecurePartitionNSP()->GetNCA(xci->GetProgramTitleID(), | 157 | const auto nca = |
| 153 | FileSys::ContentRecordType::HtmlDocument); | 158 | xci->GetSecurePartitionNSP()->GetNCA(xci->GetSecurePartitionNSP()->GetProgramTitleID(), |
| 159 | FileSys::ContentRecordType::HtmlDocument); | ||
| 154 | if (xci->GetStatus() != ResultStatus::Success || nca == nullptr) { | 160 | if (xci->GetStatus() != ResultStatus::Success || nca == nullptr) { |
| 155 | return ResultStatus::ErrorXCIMissingPartition; | 161 | return ResultStatus::ErrorXCIMissingPartition; |
| 156 | } | 162 | } |
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h index 708155c30..30caaf90e 100644 --- a/src/core/loader/xci.h +++ b/src/core/loader/xci.h | |||
| @@ -28,7 +28,7 @@ class AppLoader_XCI final : public AppLoader { | |||
| 28 | public: | 28 | public: |
| 29 | explicit AppLoader_XCI(FileSys::VirtualFile file_, | 29 | explicit AppLoader_XCI(FileSys::VirtualFile file_, |
| 30 | const Service::FileSystem::FileSystemController& fsc, | 30 | const Service::FileSystem::FileSystemController& fsc, |
| 31 | const FileSys::ContentProvider& content_provider, | 31 | const FileSys::ContentProvider& content_provider, u64 program_id, |
| 32 | std::size_t program_index); | 32 | std::size_t program_index); |
| 33 | ~AppLoader_XCI() override; | 33 | ~AppLoader_XCI() override; |
| 34 | 34 | ||
| @@ -51,6 +51,7 @@ public: | |||
| 51 | u64 ReadRomFSIVFCOffset() const override; | 51 | u64 ReadRomFSIVFCOffset() const override; |
| 52 | ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) override; | 52 | ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) override; |
| 53 | ResultStatus ReadProgramId(u64& out_program_id) override; | 53 | ResultStatus ReadProgramId(u64& out_program_id) override; |
| 54 | ResultStatus ReadProgramIds(std::vector<u64>& out_program_ids) override; | ||
| 54 | ResultStatus ReadIcon(std::vector<u8>& buffer) override; | 55 | ResultStatus ReadIcon(std::vector<u8>& buffer) override; |
| 55 | ResultStatus ReadTitle(std::string& title) override; | 56 | ResultStatus ReadTitle(std::string& title) override; |
| 56 | ResultStatus ReadControlData(FileSys::NACP& control) override; | 57 | ResultStatus ReadControlData(FileSys::NACP& control) override; |