NRO Assets and NACP file format
Cleanup Review fixes
This commit is contained in:
		| @@ -12,6 +12,8 @@ add_library(core STATIC | |||||||
|     core_timing.h |     core_timing.h | ||||||
|     file_sys/content_archive.cpp |     file_sys/content_archive.cpp | ||||||
|     file_sys/content_archive.h |     file_sys/content_archive.h | ||||||
|  |     file_sys/control_metadata.cpp | ||||||
|  |     file_sys/control_metadata.h | ||||||
|     file_sys/directory.h |     file_sys/directory.h | ||||||
|     file_sys/errors.h |     file_sys/errors.h | ||||||
|     file_sys/mode.h |     file_sys/mode.h | ||||||
|   | |||||||
							
								
								
									
										42
									
								
								src/core/file_sys/control_metadata.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/core/file_sys/control_metadata.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | |||||||
|  | // Copyright 2018 yuzu emulator team | ||||||
|  | // Licensed under GPLv2 or any later version | ||||||
|  | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #include "common/string_util.h" | ||||||
|  | #include "common/swap.h" | ||||||
|  | #include "core/file_sys/control_metadata.h" | ||||||
|  |  | ||||||
|  | namespace FileSys { | ||||||
|  |  | ||||||
|  | std::string LanguageEntry::GetApplicationName() const { | ||||||
|  |     return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(), 0x200); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::string LanguageEntry::GetDeveloperName() const { | ||||||
|  |     return Common::StringFromFixedZeroTerminatedBuffer(developer_name.data(), 0x100); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | NACP::NACP(VirtualFile file_) : file(std::move(file_)), raw(std::make_unique<RawNACP>()) { | ||||||
|  |     file->ReadObject(raw.get()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const LanguageEntry& NACP::GetLanguageEntry(Language language) const { | ||||||
|  |     return raw->language_entries.at(static_cast<u8>(language)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::string NACP::GetApplicationName(Language language) const { | ||||||
|  |     return GetLanguageEntry(language).GetApplicationName(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::string NACP::GetDeveloperName(Language language) const { | ||||||
|  |     return GetLanguageEntry(language).GetDeveloperName(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | u64 NACP::GetTitleId() const { | ||||||
|  |     return raw->title_id; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::string NACP::GetVersionString() const { | ||||||
|  |     return Common::StringFromFixedZeroTerminatedBuffer(raw->version_string.data(), 0x10); | ||||||
|  | } | ||||||
|  | } // namespace FileSys | ||||||
							
								
								
									
										81
									
								
								src/core/file_sys/control_metadata.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/core/file_sys/control_metadata.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | |||||||
|  | // Copyright 2018 yuzu emulator team | ||||||
|  | // Licensed under GPLv2 or any later version | ||||||
|  | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <array> | ||||||
|  | #include <memory> | ||||||
|  | #include <string> | ||||||
|  | #include "common/common_funcs.h" | ||||||
|  | #include "core/file_sys/vfs.h" | ||||||
|  |  | ||||||
|  | namespace FileSys { | ||||||
|  |  | ||||||
|  | // A localized entry containing strings within the NACP. | ||||||
|  | // One for each language of type Language. | ||||||
|  | struct LanguageEntry { | ||||||
|  |     std::array<char, 0x200> application_name; | ||||||
|  |     std::array<char, 0x100> developer_name; | ||||||
|  |  | ||||||
|  |     std::string GetApplicationName() const; | ||||||
|  |     std::string GetDeveloperName() const; | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(LanguageEntry) == 0x300, "LanguageEntry has incorrect size."); | ||||||
|  |  | ||||||
|  | // The raw file format of a NACP file. | ||||||
|  | struct RawNACP { | ||||||
|  |     std::array<LanguageEntry, 16> language_entries; | ||||||
|  |     INSERT_PADDING_BYTES(0x38); | ||||||
|  |     u64_le title_id; | ||||||
|  |     INSERT_PADDING_BYTES(0x20); | ||||||
|  |     std::array<char, 0x10> version_string; | ||||||
|  |     u64_le dlc_base_title_id; | ||||||
|  |     u64_le title_id_2; | ||||||
|  |     INSERT_PADDING_BYTES(0x28); | ||||||
|  |     u64_le product_code; | ||||||
|  |     u64_le title_id_3; | ||||||
|  |     std::array<u64_le, 0x7> title_id_array; | ||||||
|  |     INSERT_PADDING_BYTES(0x8); | ||||||
|  |     u64_le title_id_update; | ||||||
|  |     std::array<u8, 0x40> bcat_passphrase; | ||||||
|  |     INSERT_PADDING_BYTES(0xEC0); | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(RawNACP) == 0x4000, "RawNACP has incorrect size."); | ||||||
|  |  | ||||||
|  | // A language on the NX. These are for names and icons. | ||||||
|  | enum class Language : u8 { | ||||||
|  |     AmericanEnglish = 0, | ||||||
|  |     BritishEnglish = 1, | ||||||
|  |     Japanese = 2, | ||||||
|  |     French = 3, | ||||||
|  |     German = 4, | ||||||
|  |     LatinAmericanSpanish = 5, | ||||||
|  |     Spanish = 6, | ||||||
|  |     Italian = 7, | ||||||
|  |     Dutch = 8, | ||||||
|  |     CanadianFrench = 9, | ||||||
|  |     Portugese = 10, | ||||||
|  |     Russian = 11, | ||||||
|  |     Korean = 12, | ||||||
|  |     Taiwanese = 13, | ||||||
|  |     Chinese = 14, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // A class representing the format used by NX metadata files, typically named Control.nacp. | ||||||
|  | // These store application name, dev name, title id, and other miscellaneous data. | ||||||
|  | class NACP { | ||||||
|  | public: | ||||||
|  |     explicit NACP(VirtualFile file); | ||||||
|  |     const LanguageEntry& GetLanguageEntry(Language language = Language::AmericanEnglish) const; | ||||||
|  |     std::string GetApplicationName(Language language = Language::AmericanEnglish) const; | ||||||
|  |     std::string GetDeveloperName(Language language = Language::AmericanEnglish) const; | ||||||
|  |     u64 GetTitleId() const; | ||||||
|  |     std::string GetVersionString() const; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     VirtualFile file; | ||||||
|  |     std::unique_ptr<RawNACP> raw; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | } // namespace FileSys | ||||||
| @@ -10,6 +10,8 @@ | |||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
| #include "common/swap.h" | #include "common/swap.h" | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
|  | #include "core/file_sys/control_metadata.h" | ||||||
|  | #include "core/file_sys/vfs_offset.h" | ||||||
| #include "core/gdbstub/gdbstub.h" | #include "core/gdbstub/gdbstub.h" | ||||||
| #include "core/hle/kernel/process.h" | #include "core/hle/kernel/process.h" | ||||||
| #include "core/hle/kernel/resource_limit.h" | #include "core/hle/kernel/resource_limit.h" | ||||||
| @@ -49,7 +51,55 @@ struct ModHeader { | |||||||
| }; | }; | ||||||
| static_assert(sizeof(ModHeader) == 0x1c, "ModHeader has incorrect size."); | static_assert(sizeof(ModHeader) == 0x1c, "ModHeader has incorrect size."); | ||||||
|  |  | ||||||
| AppLoader_NRO::AppLoader_NRO(FileSys::VirtualFile file) : AppLoader(std::move(file)) {} | struct AssetSection { | ||||||
|  |     u64_le offset; | ||||||
|  |     u64_le size; | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(AssetSection) == 0x10, "AssetSection has incorrect size."); | ||||||
|  |  | ||||||
|  | struct AssetHeader { | ||||||
|  |     u32_le magic; | ||||||
|  |     u32_le format_version; | ||||||
|  |     AssetSection icon; | ||||||
|  |     AssetSection nacp; | ||||||
|  |     AssetSection romfs; | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(AssetHeader) == 0x38, "AssetHeader has incorrect size."); | ||||||
|  |  | ||||||
|  | AppLoader_NRO::AppLoader_NRO(FileSys::VirtualFile file) : AppLoader(file) { | ||||||
|  |     NroHeader nro_header{}; | ||||||
|  |     if (file->ReadObject(&nro_header) != sizeof(NroHeader)) | ||||||
|  |         return; | ||||||
|  |  | ||||||
|  |     if (file->GetSize() >= nro_header.file_size + sizeof(AssetHeader)) { | ||||||
|  |         u64 offset = nro_header.file_size; | ||||||
|  |         AssetHeader asset_header{}; | ||||||
|  |         if (file->ReadObject(&asset_header, offset) != sizeof(AssetHeader)) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|  |         if (asset_header.format_version != 0) | ||||||
|  |             LOG_WARNING(Loader, | ||||||
|  |                         "NRO Asset Header has format {}, currently supported format is 0. If " | ||||||
|  |                         "strange glitches occur with metadata, check NRO assets.", | ||||||
|  |                         asset_header.format_version); | ||||||
|  |         if (asset_header.magic != Common::MakeMagic('A', 'S', 'E', 'T')) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|  |         if (asset_header.nacp.size > 0) { | ||||||
|  |             nacp = std::make_unique<FileSys::NACP>(std::make_shared<FileSys::OffsetVfsFile>( | ||||||
|  |                 file, asset_header.nacp.size, offset + asset_header.nacp.offset, "Control.nacp")); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (asset_header.romfs.size > 0) { | ||||||
|  |             romfs = std::make_shared<FileSys::OffsetVfsFile>( | ||||||
|  |                 file, asset_header.romfs.size, offset + asset_header.romfs.offset, "game.romfs"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (asset_header.icon.size > 0) { | ||||||
|  |             icon_data = file->ReadBytes(asset_header.icon.size, offset + asset_header.icon.offset); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& file) { | FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& file) { | ||||||
|     // Read NSO header |     // Read NSO header | ||||||
| @@ -136,4 +186,31 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) { | |||||||
|     return ResultStatus::Success; |     return ResultStatus::Success; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) { | ||||||
|  |     if (icon_data.empty()) | ||||||
|  |         return ResultStatus::ErrorNotUsed; | ||||||
|  |     buffer = icon_data; | ||||||
|  |     return ResultStatus::Success; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ResultStatus AppLoader_NRO::ReadProgramId(u64& out_program_id) { | ||||||
|  |     if (nacp == nullptr) | ||||||
|  |         return ResultStatus::ErrorNotUsed; | ||||||
|  |     out_program_id = nacp->GetTitleId(); | ||||||
|  |     return ResultStatus::Success; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ResultStatus AppLoader_NRO::ReadRomFS(FileSys::VirtualFile& dir) { | ||||||
|  |     if (romfs == nullptr) | ||||||
|  |         return ResultStatus::ErrorNotUsed; | ||||||
|  |     dir = romfs; | ||||||
|  |     return ResultStatus::Success; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ResultStatus AppLoader_NRO::ReadTitle(std::string& title) { | ||||||
|  |     if (nacp == nullptr) | ||||||
|  |         return ResultStatus::ErrorNotUsed; | ||||||
|  |     title = nacp->GetApplicationName(); | ||||||
|  |     return ResultStatus::Success; | ||||||
|  | } | ||||||
| } // namespace Loader | } // namespace Loader | ||||||
|   | |||||||
| @@ -6,12 +6,15 @@ | |||||||
|  |  | ||||||
| #include <string> | #include <string> | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
|  | #include "core/file_sys/control_metadata.h" | ||||||
| #include "core/hle/kernel/kernel.h" | #include "core/hle/kernel/kernel.h" | ||||||
| #include "core/loader/linker.h" | #include "core/loader/linker.h" | ||||||
| #include "core/loader/loader.h" | #include "core/loader/loader.h" | ||||||
|  |  | ||||||
| namespace Loader { | namespace Loader { | ||||||
|  |  | ||||||
|  | struct AssetHeader; | ||||||
|  |  | ||||||
| /// Loads an NRO file | /// Loads an NRO file | ||||||
| class AppLoader_NRO final : public AppLoader, Linker { | class AppLoader_NRO final : public AppLoader, Linker { | ||||||
| public: | public: | ||||||
| @@ -30,8 +33,17 @@ public: | |||||||
|  |  | ||||||
|     ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; |     ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; | ||||||
|  |  | ||||||
|  |     ResultStatus ReadIcon(std::vector<u8>& buffer) override; | ||||||
|  |     ResultStatus ReadProgramId(u64& out_program_id) override; | ||||||
|  |     ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; | ||||||
|  |     ResultStatus ReadTitle(std::string& title) override; | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     bool LoadNro(FileSys::VirtualFile file, VAddr load_base); |     bool LoadNro(FileSys::VirtualFile file, VAddr load_base); | ||||||
|  |  | ||||||
|  |     std::vector<u8> icon_data; | ||||||
|  |     std::unique_ptr<FileSys::NACP> nacp; | ||||||
|  |     FileSys::VirtualFile romfs; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| } // namespace Loader | } // namespace Loader | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Zach Hilman
					Zach Hilman