diff options
| author | 2018-08-24 23:47:46 -0400 | |
|---|---|---|
| committer | 2018-08-24 23:47:46 -0400 | |
| commit | 6426b0f5514d6a7c5cc369368947eceb380bfc85 (patch) | |
| tree | b7acdc39a4344570a6f2c098c30ad20114bf84db /src/core/loader | |
| parent | Merge pull request #1065 from DarkLordZach/window-title (diff) | |
| parent | file_sys/crypto: Fix missing/unnecessary includes (diff) | |
| download | yuzu-6426b0f5514d6a7c5cc369368947eceb380bfc85.tar.gz yuzu-6426b0f5514d6a7c5cc369368947eceb380bfc85.tar.xz yuzu-6426b0f5514d6a7c5cc369368947eceb380bfc85.zip | |
Merge pull request #1094 from DarkLordZach/nax0
file_sys: Add support for NAX archives
Diffstat (limited to 'src/core/loader')
| -rw-r--r-- | src/core/loader/loader.cpp | 29 | ||||
| -rw-r--r-- | src/core/loader/loader.h | 14 | ||||
| -rw-r--r-- | src/core/loader/nax.cpp | 66 | ||||
| -rw-r--r-- | src/core/loader/nax.h | 48 | ||||
| -rw-r--r-- | src/core/loader/xci.cpp | 11 |
5 files changed, 160 insertions, 8 deletions
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 70ef5d240..c13fb49b8 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include "core/hle/kernel/process.h" | 11 | #include "core/hle/kernel/process.h" |
| 12 | #include "core/loader/deconstructed_rom_directory.h" | 12 | #include "core/loader/deconstructed_rom_directory.h" |
| 13 | #include "core/loader/elf.h" | 13 | #include "core/loader/elf.h" |
| 14 | #include "core/loader/nax.h" | ||
| 14 | #include "core/loader/nca.h" | 15 | #include "core/loader/nca.h" |
| 15 | #include "core/loader/nro.h" | 16 | #include "core/loader/nro.h" |
| 16 | #include "core/loader/nso.h" | 17 | #include "core/loader/nso.h" |
| @@ -32,6 +33,7 @@ FileType IdentifyFile(FileSys::VirtualFile file) { | |||
| 32 | CHECK_TYPE(NRO) | 33 | CHECK_TYPE(NRO) |
| 33 | CHECK_TYPE(NCA) | 34 | CHECK_TYPE(NCA) |
| 34 | CHECK_TYPE(XCI) | 35 | CHECK_TYPE(XCI) |
| 36 | CHECK_TYPE(NAX) | ||
| 35 | 37 | ||
| 36 | #undef CHECK_TYPE | 38 | #undef CHECK_TYPE |
| 37 | 39 | ||
| @@ -73,6 +75,8 @@ std::string GetFileTypeString(FileType type) { | |||
| 73 | return "NCA"; | 75 | return "NCA"; |
| 74 | case FileType::XCI: | 76 | case FileType::XCI: |
| 75 | return "XCI"; | 77 | return "XCI"; |
| 78 | case FileType::NAX: | ||
| 79 | return "NAX"; | ||
| 76 | case FileType::DeconstructedRomDirectory: | 80 | case FileType::DeconstructedRomDirectory: |
| 77 | return "Directory"; | 81 | return "Directory"; |
| 78 | case FileType::Error: | 82 | case FileType::Error: |
| @@ -83,7 +87,7 @@ std::string GetFileTypeString(FileType type) { | |||
| 83 | return "unknown"; | 87 | return "unknown"; |
| 84 | } | 88 | } |
| 85 | 89 | ||
| 86 | constexpr std::array<const char*, 36> RESULT_MESSAGES{ | 90 | constexpr std::array<const char*, 49> RESULT_MESSAGES{ |
| 87 | "The operation completed successfully.", | 91 | "The operation completed successfully.", |
| 88 | "The loader requested to load is already loaded.", | 92 | "The loader requested to load is already loaded.", |
| 89 | "The operation is not implemented.", | 93 | "The operation is not implemented.", |
| @@ -120,6 +124,19 @@ constexpr std::array<const char*, 36> RESULT_MESSAGES{ | |||
| 120 | "There was a general error loading the NRO into emulated memory.", | 124 | "There was a general error loading the NRO into emulated memory.", |
| 121 | "There is no icon available.", | 125 | "There is no icon available.", |
| 122 | "There is no control data available.", | 126 | "There is no control data available.", |
| 127 | "The NAX file has a bad header.", | ||
| 128 | "The NAX file has incorrect size as determined by the header.", | ||
| 129 | "The HMAC to generated the NAX decryption keys failed.", | ||
| 130 | "The HMAC to validate the NAX decryption keys failed.", | ||
| 131 | "The NAX key derivation failed.", | ||
| 132 | "The NAX file cannot be interpreted as an NCA file.", | ||
| 133 | "The NAX file has an incorrect path.", | ||
| 134 | "The SD seed could not be found or derived.", | ||
| 135 | "The SD KEK Source could not be found.", | ||
| 136 | "The AES KEK Generation Source could not be found.", | ||
| 137 | "The AES Key Generation Source could not be found.", | ||
| 138 | "The SD Save Key Source could not be found.", | ||
| 139 | "The SD NCA Key Source could not be found.", | ||
| 123 | }; | 140 | }; |
| 124 | 141 | ||
| 125 | std::ostream& operator<<(std::ostream& os, ResultStatus status) { | 142 | std::ostream& operator<<(std::ostream& os, ResultStatus status) { |
| @@ -150,13 +167,18 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT | |||
| 150 | case FileType::NRO: | 167 | case FileType::NRO: |
| 151 | return std::make_unique<AppLoader_NRO>(std::move(file)); | 168 | return std::make_unique<AppLoader_NRO>(std::move(file)); |
| 152 | 169 | ||
| 153 | // NX NCA file format. | 170 | // NX NCA (Nintendo Content Archive) file format. |
| 154 | case FileType::NCA: | 171 | case FileType::NCA: |
| 155 | return std::make_unique<AppLoader_NCA>(std::move(file)); | 172 | return std::make_unique<AppLoader_NCA>(std::move(file)); |
| 156 | 173 | ||
| 174 | // NX XCI (nX Card Image) file format. | ||
| 157 | case FileType::XCI: | 175 | case FileType::XCI: |
| 158 | return std::make_unique<AppLoader_XCI>(std::move(file)); | 176 | return std::make_unique<AppLoader_XCI>(std::move(file)); |
| 159 | 177 | ||
| 178 | // NX NAX (NintendoAesXts) file format. | ||
| 179 | case FileType::NAX: | ||
| 180 | return std::make_unique<AppLoader_NAX>(std::move(file)); | ||
| 181 | |||
| 160 | // NX deconstructed ROM directory. | 182 | // NX deconstructed ROM directory. |
| 161 | case FileType::DeconstructedRomDirectory: | 183 | case FileType::DeconstructedRomDirectory: |
| 162 | return std::make_unique<AppLoader_DeconstructedRomDirectory>(std::move(file)); | 184 | return std::make_unique<AppLoader_DeconstructedRomDirectory>(std::move(file)); |
| @@ -170,7 +192,8 @@ std::unique_ptr<AppLoader> GetLoader(FileSys::VirtualFile file) { | |||
| 170 | FileType type = IdentifyFile(file); | 192 | FileType type = IdentifyFile(file); |
| 171 | FileType filename_type = GuessFromFilename(file->GetName()); | 193 | FileType filename_type = GuessFromFilename(file->GetName()); |
| 172 | 194 | ||
| 173 | if (type != filename_type) { | 195 | // Special case: 00 is either a NCA or NAX. |
| 196 | if (type != filename_type && !(file->GetName() == "00" && type == FileType::NAX)) { | ||
| 174 | LOG_WARNING(Loader, "File {} has a different type than its extension.", file->GetName()); | 197 | LOG_WARNING(Loader, "File {} has a different type than its extension.", file->GetName()); |
| 175 | if (FileType::Unknown == type) | 198 | if (FileType::Unknown == type) |
| 176 | type = filename_type; | 199 | type = filename_type; |
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index b74cfbf8a..885fee84c 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h | |||
| @@ -32,6 +32,7 @@ enum class FileType { | |||
| 32 | NRO, | 32 | NRO, |
| 33 | NCA, | 33 | NCA, |
| 34 | XCI, | 34 | XCI, |
| 35 | NAX, | ||
| 35 | DeconstructedRomDirectory, | 36 | DeconstructedRomDirectory, |
| 36 | }; | 37 | }; |
| 37 | 38 | ||
| @@ -93,6 +94,19 @@ enum class ResultStatus : u16 { | |||
| 93 | ErrorLoadingNRO, | 94 | ErrorLoadingNRO, |
| 94 | ErrorNoIcon, | 95 | ErrorNoIcon, |
| 95 | ErrorNoControl, | 96 | ErrorNoControl, |
| 97 | ErrorBadNAXHeader, | ||
| 98 | ErrorIncorrectNAXFileSize, | ||
| 99 | ErrorNAXKeyHMACFailed, | ||
| 100 | ErrorNAXValidationHMACFailed, | ||
| 101 | ErrorNAXKeyDerivationFailed, | ||
| 102 | ErrorNAXInconvertibleToNCA, | ||
| 103 | ErrorBadNAXFilePath, | ||
| 104 | ErrorMissingSDSeed, | ||
| 105 | ErrorMissingSDKEKSource, | ||
| 106 | ErrorMissingAESKEKGenerationSource, | ||
| 107 | ErrorMissingAESKeyGenerationSource, | ||
| 108 | ErrorMissingSDSaveKeySource, | ||
| 109 | ErrorMissingSDNCAKeySource, | ||
| 96 | }; | 110 | }; |
| 97 | 111 | ||
| 98 | std::ostream& operator<<(std::ostream& os, ResultStatus status); | 112 | std::ostream& operator<<(std::ostream& os, ResultStatus status); |
diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp new file mode 100644 index 000000000..b46d81c02 --- /dev/null +++ b/src/core/loader/nax.cpp | |||
| @@ -0,0 +1,66 @@ | |||
| 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 "common/logging/log.h" | ||
| 6 | #include "core/file_sys/content_archive.h" | ||
| 7 | #include "core/file_sys/romfs.h" | ||
| 8 | #include "core/file_sys/xts_archive.h" | ||
| 9 | #include "core/hle/kernel/process.h" | ||
| 10 | #include "core/loader/nax.h" | ||
| 11 | #include "core/loader/nca.h" | ||
| 12 | |||
| 13 | namespace Loader { | ||
| 14 | |||
| 15 | AppLoader_NAX::AppLoader_NAX(FileSys::VirtualFile file) | ||
| 16 | : AppLoader(file), nax(std::make_unique<FileSys::NAX>(file)), | ||
| 17 | nca_loader(std::make_unique<AppLoader_NCA>(nax->GetDecrypted())) {} | ||
| 18 | |||
| 19 | AppLoader_NAX::~AppLoader_NAX() = default; | ||
| 20 | |||
| 21 | FileType AppLoader_NAX::IdentifyType(const FileSys::VirtualFile& file) { | ||
| 22 | FileSys::NAX nax(file); | ||
| 23 | |||
| 24 | if (nax.GetStatus() == ResultStatus::Success && nax.AsNCA() != nullptr && | ||
| 25 | nax.AsNCA()->GetStatus() == ResultStatus::Success) { | ||
| 26 | return FileType::NAX; | ||
| 27 | } | ||
| 28 | |||
| 29 | return FileType::Error; | ||
| 30 | } | ||
| 31 | |||
| 32 | ResultStatus AppLoader_NAX::Load(Kernel::SharedPtr<Kernel::Process>& process) { | ||
| 33 | if (is_loaded) { | ||
| 34 | return ResultStatus::ErrorAlreadyLoaded; | ||
| 35 | } | ||
| 36 | |||
| 37 | if (nax->GetStatus() != ResultStatus::Success) | ||
| 38 | return nax->GetStatus(); | ||
| 39 | |||
| 40 | const auto nca = nax->AsNCA(); | ||
| 41 | if (nca == nullptr) { | ||
| 42 | if (!Core::Crypto::KeyManager::KeyFileExists(false)) | ||
| 43 | return ResultStatus::ErrorMissingProductionKeyFile; | ||
| 44 | return ResultStatus::ErrorNAXInconvertibleToNCA; | ||
| 45 | } | ||
| 46 | |||
| 47 | if (nca->GetStatus() != ResultStatus::Success) | ||
| 48 | return nca->GetStatus(); | ||
| 49 | |||
| 50 | const auto result = nca_loader->Load(process); | ||
| 51 | if (result != ResultStatus::Success) | ||
| 52 | return result; | ||
| 53 | |||
| 54 | is_loaded = true; | ||
| 55 | |||
| 56 | return ResultStatus::Success; | ||
| 57 | } | ||
| 58 | |||
| 59 | ResultStatus AppLoader_NAX::ReadRomFS(FileSys::VirtualFile& dir) { | ||
| 60 | return nca_loader->ReadRomFS(dir); | ||
| 61 | } | ||
| 62 | |||
| 63 | ResultStatus AppLoader_NAX::ReadProgramId(u64& out_program_id) { | ||
| 64 | return nca_loader->ReadProgramId(out_program_id); | ||
| 65 | } | ||
| 66 | } // namespace Loader | ||
diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h new file mode 100644 index 000000000..4dbae2918 --- /dev/null +++ b/src/core/loader/nax.h | |||
| @@ -0,0 +1,48 @@ | |||
| 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/loader/loader.h" | ||
| 10 | |||
| 11 | namespace FileSys { | ||
| 12 | |||
| 13 | class NAX; | ||
| 14 | |||
| 15 | } // namespace FileSys | ||
| 16 | |||
| 17 | namespace Loader { | ||
| 18 | |||
| 19 | class AppLoader_NCA; | ||
| 20 | |||
| 21 | /// Loads a NAX file | ||
| 22 | class AppLoader_NAX final : public AppLoader { | ||
| 23 | public: | ||
| 24 | explicit AppLoader_NAX(FileSys::VirtualFile file); | ||
| 25 | ~AppLoader_NAX() 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 | |||
| 43 | private: | ||
| 44 | std::unique_ptr<FileSys::NAX> nax; | ||
| 45 | std::unique_ptr<AppLoader_NCA> nca_loader; | ||
| 46 | }; | ||
| 47 | |||
| 48 | } // namespace Loader | ||
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index 4c4979545..9dc4d1f35 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp | |||
| @@ -61,11 +61,12 @@ ResultStatus AppLoader_XCI::Load(Kernel::SharedPtr<Kernel::Process>& process) { | |||
| 61 | if (xci->GetStatus() != ResultStatus::Success) | 61 | if (xci->GetStatus() != ResultStatus::Success) |
| 62 | return xci->GetStatus(); | 62 | return xci->GetStatus(); |
| 63 | 63 | ||
| 64 | if (xci->GetNCAFileByType(FileSys::NCAContentType::Program) == nullptr) { | 64 | if (xci->GetProgramNCAStatus() != ResultStatus::Success) |
| 65 | if (!Core::Crypto::KeyManager::KeyFileExists(false)) | 65 | return xci->GetProgramNCAStatus(); |
| 66 | return ResultStatus::ErrorMissingProductionKeyFile; | 66 | |
| 67 | return ResultStatus::ErrorXCIMissingProgramNCA; | 67 | const auto nca = xci->GetNCAFileByType(FileSys::NCAContentType::Program); |
| 68 | } | 68 | if (nca == nullptr && !Core::Crypto::KeyManager::KeyFileExists(false)) |
| 69 | return ResultStatus::ErrorMissingProductionKeyFile; | ||
| 69 | 70 | ||
| 70 | auto result = nca_loader->Load(process); | 71 | auto result = nca_loader->Load(process); |
| 71 | if (result != ResultStatus::Success) | 72 | if (result != ResultStatus::Success) |