diff options
| author | 2018-09-04 16:20:40 -0400 | |
|---|---|---|
| committer | 2018-09-04 16:20:40 -0400 | |
| commit | faa9e066aba320bcd38fd023ee58c6f9e1d3efdd (patch) | |
| tree | c369b13af5a30698564ee54acbae639be4576482 /src/core/loader | |
| parent | Merge pull request #1238 from lioncash/explicit (diff) | |
| parent | main: Only show DRD deprecation warning once (diff) | |
| download | yuzu-faa9e066aba320bcd38fd023ee58c6f9e1d3efdd.tar.gz yuzu-faa9e066aba320bcd38fd023ee58c6f9e1d3efdd.tar.xz yuzu-faa9e066aba320bcd38fd023ee58c6f9e1d3efdd.zip | |
Merge pull request #1178 from DarkLordZach/nsp
file_sys: Add Nintendo Submissions Package (NSP) file format
Diffstat (limited to 'src/core/loader')
| -rw-r--r-- | src/core/loader/deconstructed_rom_directory.cpp | 4 | ||||
| -rw-r--r-- | src/core/loader/loader.cpp | 14 | ||||
| -rw-r--r-- | src/core/loader/loader.h | 2 | ||||
| -rw-r--r-- | src/core/loader/nsp.cpp | 135 | ||||
| -rw-r--r-- | src/core/loader/nsp.h | 54 | ||||
| -rw-r--r-- | src/core/loader/xci.cpp | 7 |
6 files changed, 207 insertions, 9 deletions
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 921b899e2..1ae4bb656 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp | |||
| @@ -61,7 +61,6 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys | |||
| 61 | 61 | ||
| 62 | if (nacp_file != nullptr) { | 62 | if (nacp_file != nullptr) { |
| 63 | FileSys::NACP nacp(nacp_file); | 63 | FileSys::NACP nacp(nacp_file); |
| 64 | title_id = nacp.GetTitleId(); | ||
| 65 | name = nacp.GetApplicationName(); | 64 | name = nacp.GetApplicationName(); |
| 66 | } | 65 | } |
| 67 | } | 66 | } |
| @@ -120,6 +119,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( | |||
| 120 | } | 119 | } |
| 121 | 120 | ||
| 122 | auto& kernel = Core::System::GetInstance().Kernel(); | 121 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 122 | title_id = metadata.GetTitleID(); | ||
| 123 | process->program_id = metadata.GetTitleID(); | 123 | process->program_id = metadata.GetTitleID(); |
| 124 | process->svc_access_mask.set(); | 124 | process->svc_access_mask.set(); |
| 125 | process->resource_limit = | 125 | process->resource_limit = |
| @@ -159,8 +159,6 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadIcon(std::vector<u8>& buff | |||
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | ResultStatus AppLoader_DeconstructedRomDirectory::ReadProgramId(u64& out_program_id) { | 161 | ResultStatus AppLoader_DeconstructedRomDirectory::ReadProgramId(u64& out_program_id) { |
| 162 | if (name.empty()) | ||
| 163 | return ResultStatus::ErrorNoControl; | ||
| 164 | out_program_id = title_id; | 162 | out_program_id = title_id; |
| 165 | return ResultStatus::Success; | 163 | return ResultStatus::Success; |
| 166 | } | 164 | } |
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 5980cdb25..446adf557 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include "core/loader/nca.h" | 15 | #include "core/loader/nca.h" |
| 16 | #include "core/loader/nro.h" | 16 | #include "core/loader/nro.h" |
| 17 | #include "core/loader/nso.h" | 17 | #include "core/loader/nso.h" |
| 18 | #include "core/loader/nsp.h" | ||
| 18 | #include "core/loader/xci.h" | 19 | #include "core/loader/xci.h" |
| 19 | 20 | ||
| 20 | namespace Loader { | 21 | namespace Loader { |
| @@ -34,6 +35,7 @@ FileType IdentifyFile(FileSys::VirtualFile file) { | |||
| 34 | CHECK_TYPE(NCA) | 35 | CHECK_TYPE(NCA) |
| 35 | CHECK_TYPE(XCI) | 36 | CHECK_TYPE(XCI) |
| 36 | CHECK_TYPE(NAX) | 37 | CHECK_TYPE(NAX) |
| 38 | CHECK_TYPE(NSP) | ||
| 37 | 39 | ||
| 38 | #undef CHECK_TYPE | 40 | #undef CHECK_TYPE |
| 39 | 41 | ||
| @@ -59,6 +61,8 @@ FileType GuessFromFilename(const std::string& name) { | |||
| 59 | return FileType::NCA; | 61 | return FileType::NCA; |
| 60 | if (extension == "xci") | 62 | if (extension == "xci") |
| 61 | return FileType::XCI; | 63 | return FileType::XCI; |
| 64 | if (extension == "nsp") | ||
| 65 | return FileType::NSP; | ||
| 62 | 66 | ||
| 63 | return FileType::Unknown; | 67 | return FileType::Unknown; |
| 64 | } | 68 | } |
| @@ -77,6 +81,8 @@ std::string GetFileTypeString(FileType type) { | |||
| 77 | return "XCI"; | 81 | return "XCI"; |
| 78 | case FileType::NAX: | 82 | case FileType::NAX: |
| 79 | return "NAX"; | 83 | return "NAX"; |
| 84 | case FileType::NSP: | ||
| 85 | return "NSP"; | ||
| 80 | case FileType::DeconstructedRomDirectory: | 86 | case FileType::DeconstructedRomDirectory: |
| 81 | return "Directory"; | 87 | return "Directory"; |
| 82 | case FileType::Error: | 88 | case FileType::Error: |
| @@ -87,7 +93,7 @@ std::string GetFileTypeString(FileType type) { | |||
| 87 | return "unknown"; | 93 | return "unknown"; |
| 88 | } | 94 | } |
| 89 | 95 | ||
| 90 | constexpr std::array<const char*, 49> RESULT_MESSAGES{ | 96 | constexpr std::array<const char*, 50> RESULT_MESSAGES{ |
| 91 | "The operation completed successfully.", | 97 | "The operation completed successfully.", |
| 92 | "The loader requested to load is already loaded.", | 98 | "The loader requested to load is already loaded.", |
| 93 | "The operation is not implemented.", | 99 | "The operation is not implemented.", |
| @@ -137,7 +143,7 @@ constexpr std::array<const char*, 49> RESULT_MESSAGES{ | |||
| 137 | "The AES Key Generation Source could not be found.", | 143 | "The AES Key Generation Source could not be found.", |
| 138 | "The SD Save Key Source could not be found.", | 144 | "The SD Save Key Source could not be found.", |
| 139 | "The SD NCA Key Source could not be found.", | 145 | "The SD NCA Key Source could not be found.", |
| 140 | }; | 146 | "The NSP file is missing a Program-type NCA."}; |
| 141 | 147 | ||
| 142 | std::ostream& operator<<(std::ostream& os, ResultStatus status) { | 148 | std::ostream& operator<<(std::ostream& os, ResultStatus status) { |
| 143 | os << RESULT_MESSAGES.at(static_cast<size_t>(status)); | 149 | os << RESULT_MESSAGES.at(static_cast<size_t>(status)); |
| @@ -182,6 +188,10 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT | |||
| 182 | case FileType::NAX: | 188 | case FileType::NAX: |
| 183 | return std::make_unique<AppLoader_NAX>(std::move(file)); | 189 | return std::make_unique<AppLoader_NAX>(std::move(file)); |
| 184 | 190 | ||
| 191 | // NX NSP (Nintendo Submission Package) file format | ||
| 192 | case FileType::NSP: | ||
| 193 | return std::make_unique<AppLoader_NSP>(std::move(file)); | ||
| 194 | |||
| 185 | // NX deconstructed ROM directory. | 195 | // NX deconstructed ROM directory. |
| 186 | case FileType::DeconstructedRomDirectory: | 196 | case FileType::DeconstructedRomDirectory: |
| 187 | return std::make_unique<AppLoader_DeconstructedRomDirectory>(std::move(file)); | 197 | return std::make_unique<AppLoader_DeconstructedRomDirectory>(std::move(file)); |
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 5a8540b0e..be66b2257 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h | |||
| @@ -29,6 +29,7 @@ enum class FileType { | |||
| 29 | NSO, | 29 | NSO, |
| 30 | NRO, | 30 | NRO, |
| 31 | NCA, | 31 | NCA, |
| 32 | NSP, | ||
| 32 | XCI, | 33 | XCI, |
| 33 | NAX, | 34 | NAX, |
| 34 | DeconstructedRomDirectory, | 35 | DeconstructedRomDirectory, |
| @@ -105,6 +106,7 @@ enum class ResultStatus : u16 { | |||
| 105 | ErrorMissingAESKeyGenerationSource, | 106 | ErrorMissingAESKeyGenerationSource, |
| 106 | ErrorMissingSDSaveKeySource, | 107 | ErrorMissingSDSaveKeySource, |
| 107 | ErrorMissingSDNCAKeySource, | 108 | ErrorMissingSDNCAKeySource, |
| 109 | ErrorNSPMissingProgramNCA, | ||
| 108 | }; | 110 | }; |
| 109 | 111 | ||
| 110 | std::ostream& operator<<(std::ostream& os, ResultStatus status); | 112 | std::ostream& operator<<(std::ostream& os, ResultStatus status); |
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp new file mode 100644 index 000000000..7c06239f2 --- /dev/null +++ b/src/core/loader/nsp.cpp | |||
| @@ -0,0 +1,135 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <vector> | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "core/file_sys/card_image.h" | ||
| 9 | #include "core/file_sys/content_archive.h" | ||
| 10 | #include "core/file_sys/control_metadata.h" | ||
| 11 | #include "core/file_sys/nca_metadata.h" | ||
| 12 | #include "core/file_sys/romfs.h" | ||
| 13 | #include "core/file_sys/submission_package.h" | ||
| 14 | #include "core/hle/kernel/process.h" | ||
| 15 | #include "core/loader/deconstructed_rom_directory.h" | ||
| 16 | #include "core/loader/nca.h" | ||
| 17 | #include "core/loader/nsp.h" | ||
| 18 | |||
| 19 | namespace Loader { | ||
| 20 | |||
| 21 | AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file) | ||
| 22 | : AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file)), | ||
| 23 | title_id(nsp->GetProgramTitleID()) { | ||
| 24 | |||
| 25 | if (nsp->GetStatus() != ResultStatus::Success) | ||
| 26 | return; | ||
| 27 | if (nsp->IsExtractedType()) | ||
| 28 | return; | ||
| 29 | |||
| 30 | const auto control_nca = | ||
| 31 | nsp->GetNCA(nsp->GetFirstTitleID(), FileSys::ContentRecordType::Control); | ||
| 32 | if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) | ||
| 33 | return; | ||
| 34 | |||
| 35 | const auto romfs = FileSys::ExtractRomFS(control_nca->GetRomFS()); | ||
| 36 | if (romfs == nullptr) | ||
| 37 | return; | ||
| 38 | |||
| 39 | for (const auto& language : FileSys::LANGUAGE_NAMES) { | ||
| 40 | icon_file = romfs->GetFile("icon_" + std::string(language) + ".dat"); | ||
| 41 | if (icon_file != nullptr) | ||
| 42 | break; | ||
| 43 | } | ||
| 44 | |||
| 45 | const auto nacp_raw = romfs->GetFile("control.nacp"); | ||
| 46 | if (nacp_raw == nullptr) | ||
| 47 | return; | ||
| 48 | nacp_file = std::make_shared<FileSys::NACP>(nacp_raw); | ||
| 49 | } | ||
| 50 | |||
| 51 | AppLoader_NSP::~AppLoader_NSP() = default; | ||
| 52 | |||
| 53 | FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& file) { | ||
| 54 | FileSys::NSP nsp(file); | ||
| 55 | |||
| 56 | if (nsp.GetStatus() == ResultStatus::Success) { | ||
| 57 | // Extracted Type case | ||
| 58 | if (nsp.IsExtractedType() && nsp.GetExeFS() != nullptr && | ||
| 59 | FileSys::IsDirectoryExeFS(nsp.GetExeFS()) && nsp.GetRomFS() != nullptr) { | ||
| 60 | return FileType::NSP; | ||
| 61 | } | ||
| 62 | |||
| 63 | // Non-Ectracted Type case | ||
| 64 | if (!nsp.IsExtractedType() && | ||
| 65 | nsp.GetNCA(nsp.GetFirstTitleID(), FileSys::ContentRecordType::Program) != nullptr && | ||
| 66 | AppLoader_NCA::IdentifyType(nsp.GetNCAFile( | ||
| 67 | nsp.GetFirstTitleID(), FileSys::ContentRecordType::Program)) == FileType::NCA) { | ||
| 68 | return FileType::NSP; | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | return FileType::Error; | ||
| 73 | } | ||
| 74 | |||
| 75 | ResultStatus AppLoader_NSP::Load(Kernel::SharedPtr<Kernel::Process>& process) { | ||
| 76 | if (is_loaded) { | ||
| 77 | return ResultStatus::ErrorAlreadyLoaded; | ||
| 78 | } | ||
| 79 | |||
| 80 | if (nsp->IsExtractedType()) { | ||
| 81 | secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(nsp->GetExeFS()); | ||
| 82 | } else { | ||
| 83 | if (title_id == 0) | ||
| 84 | return ResultStatus::ErrorNSPMissingProgramNCA; | ||
| 85 | |||
| 86 | secondary_loader = std::make_unique<AppLoader_NCA>( | ||
| 87 | nsp->GetNCAFile(title_id, FileSys::ContentRecordType::Program)); | ||
| 88 | |||
| 89 | if (nsp->GetStatus() != ResultStatus::Success) | ||
| 90 | return nsp->GetStatus(); | ||
| 91 | |||
| 92 | if (nsp->GetProgramStatus(title_id) != ResultStatus::Success) | ||
| 93 | return nsp->GetProgramStatus(title_id); | ||
| 94 | |||
| 95 | if (nsp->GetNCA(title_id, FileSys::ContentRecordType::Program) == nullptr) { | ||
| 96 | if (!Core::Crypto::KeyManager::KeyFileExists(false)) | ||
| 97 | return ResultStatus::ErrorMissingProductionKeyFile; | ||
| 98 | return ResultStatus::ErrorNSPMissingProgramNCA; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | const auto result = secondary_loader->Load(process); | ||
| 103 | if (result != ResultStatus::Success) | ||
| 104 | return result; | ||
| 105 | |||
| 106 | is_loaded = true; | ||
| 107 | |||
| 108 | return ResultStatus::Success; | ||
| 109 | } | ||
| 110 | |||
| 111 | ResultStatus AppLoader_NSP::ReadRomFS(FileSys::VirtualFile& dir) { | ||
| 112 | return secondary_loader->ReadRomFS(dir); | ||
| 113 | } | ||
| 114 | |||
| 115 | ResultStatus AppLoader_NSP::ReadProgramId(u64& out_program_id) { | ||
| 116 | if (title_id == 0) | ||
| 117 | return ResultStatus::ErrorNotInitialized; | ||
| 118 | out_program_id = title_id; | ||
| 119 | return ResultStatus::Success; | ||
| 120 | } | ||
| 121 | |||
| 122 | ResultStatus AppLoader_NSP::ReadIcon(std::vector<u8>& buffer) { | ||
| 123 | if (icon_file == nullptr) | ||
| 124 | return ResultStatus::ErrorNoControl; | ||
| 125 | buffer = icon_file->ReadAllBytes(); | ||
| 126 | return ResultStatus::Success; | ||
| 127 | } | ||
| 128 | |||
| 129 | ResultStatus AppLoader_NSP::ReadTitle(std::string& title) { | ||
| 130 | if (nacp_file == nullptr) | ||
| 131 | return ResultStatus::ErrorNoControl; | ||
| 132 | title = nacp_file->GetApplicationName(); | ||
| 133 | return ResultStatus::Success; | ||
| 134 | } | ||
| 135 | } // namespace Loader | ||
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h new file mode 100644 index 000000000..7ef810499 --- /dev/null +++ b/src/core/loader/nsp.h | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/file_sys/vfs.h" | ||
| 10 | #include "core/loader/loader.h" | ||
| 11 | |||
| 12 | namespace FileSys { | ||
| 13 | class NACP; | ||
| 14 | class NSP; | ||
| 15 | } // namespace FileSys | ||
| 16 | |||
| 17 | namespace Loader { | ||
| 18 | |||
| 19 | class AppLoader_NCA; | ||
| 20 | |||
| 21 | /// Loads an XCI file | ||
| 22 | class AppLoader_NSP final : public AppLoader { | ||
| 23 | public: | ||
| 24 | explicit AppLoader_NSP(FileSys::VirtualFile file); | ||
| 25 | ~AppLoader_NSP() override; | ||
| 26 | |||
| 27 | /** | ||
| 28 | * Returns the type of the file | ||
| 29 | * @param file std::shared_ptr<VfsFile> open file | ||
| 30 | * @return FileType found, or FileType::Error if this loader doesn't know it | ||
| 31 | */ | ||
| 32 | static FileType IdentifyType(const FileSys::VirtualFile& file); | ||
| 33 | |||
| 34 | FileType GetFileType() override { | ||
| 35 | return IdentifyType(file); | ||
| 36 | } | ||
| 37 | |||
| 38 | ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; | ||
| 39 | |||
| 40 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; | ||
| 41 | ResultStatus ReadProgramId(u64& out_program_id) override; | ||
| 42 | ResultStatus ReadIcon(std::vector<u8>& buffer) override; | ||
| 43 | ResultStatus ReadTitle(std::string& title) override; | ||
| 44 | |||
| 45 | private: | ||
| 46 | std::unique_ptr<FileSys::NSP> nsp; | ||
| 47 | std::unique_ptr<AppLoader> secondary_loader; | ||
| 48 | |||
| 49 | FileSys::VirtualFile icon_file; | ||
| 50 | std::shared_ptr<FileSys::NACP> nacp_file; | ||
| 51 | u64 title_id; | ||
| 52 | }; | ||
| 53 | |||
| 54 | } // namespace Loader | ||
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index 9dc4d1f35..75b998faa 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp | |||
| @@ -17,8 +17,7 @@ namespace Loader { | |||
| 17 | 17 | ||
| 18 | AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file) | 18 | AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file) |
| 19 | : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)), | 19 | : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)), |
| 20 | nca_loader(std::make_unique<AppLoader_NCA>( | 20 | nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) { |
| 21 | xci->GetNCAFileByType(FileSys::NCAContentType::Program))) { | ||
| 22 | if (xci->GetStatus() != ResultStatus::Success) | 21 | if (xci->GetStatus() != ResultStatus::Success) |
| 23 | return; | 22 | return; |
| 24 | const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control); | 23 | const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control); |
| @@ -64,11 +63,11 @@ ResultStatus AppLoader_XCI::Load(Kernel::SharedPtr<Kernel::Process>& process) { | |||
| 64 | if (xci->GetProgramNCAStatus() != ResultStatus::Success) | 63 | if (xci->GetProgramNCAStatus() != ResultStatus::Success) |
| 65 | return xci->GetProgramNCAStatus(); | 64 | return xci->GetProgramNCAStatus(); |
| 66 | 65 | ||
| 67 | const auto nca = xci->GetNCAFileByType(FileSys::NCAContentType::Program); | 66 | const auto nca = xci->GetProgramNCA(); |
| 68 | if (nca == nullptr && !Core::Crypto::KeyManager::KeyFileExists(false)) | 67 | if (nca == nullptr && !Core::Crypto::KeyManager::KeyFileExists(false)) |
| 69 | return ResultStatus::ErrorMissingProductionKeyFile; | 68 | return ResultStatus::ErrorMissingProductionKeyFile; |
| 70 | 69 | ||
| 71 | auto result = nca_loader->Load(process); | 70 | const auto result = nca_loader->Load(process); |
| 72 | if (result != ResultStatus::Success) | 71 | if (result != ResultStatus::Success) |
| 73 | return result; | 72 | return result; |
| 74 | 73 | ||