mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Merge pull request #1817 from linkmauve/smdh-stuff
Improve SMDH support in loaders and frontends
This commit is contained in:
		
						commit
						f50a32bfce
					
				
					 14 changed files with 229 additions and 167 deletions
				
			
		|  | @ -121,6 +121,7 @@ set(SRCS | |||
|             loader/elf.cpp | ||||
|             loader/loader.cpp | ||||
|             loader/ncch.cpp | ||||
|             loader/smdh.cpp | ||||
|             tracer/recorder.cpp | ||||
|             memory.cpp | ||||
|             settings.cpp | ||||
|  | @ -256,6 +257,7 @@ set(HEADERS | |||
|             loader/elf.h | ||||
|             loader/loader.h | ||||
|             loader/ncch.h | ||||
|             loader/smdh.h | ||||
|             tracer/recorder.h | ||||
|             tracer/citrace.h | ||||
|             memory.h | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ | |||
| #include "core/file_sys/archive_romfs.h" | ||||
| #include "core/hle/kernel/process.h" | ||||
| #include "core/hle/kernel/resource_limit.h" | ||||
| #include "core/hle/service/fs/archive.h" | ||||
| #include "core/loader/3dsx.h" | ||||
| #include "core/memory.h" | ||||
| 
 | ||||
|  | @ -263,6 +264,8 @@ ResultStatus AppLoader_THREEDSX::Load() { | |||
| 
 | ||||
|     Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE); | ||||
| 
 | ||||
|     Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_RomFS>(*this), Service::FS::ArchiveIdCode::RomFS); | ||||
| 
 | ||||
|     is_loaded = true; | ||||
|     return ResultStatus::Success; | ||||
| } | ||||
|  |  | |||
|  | @ -27,6 +27,14 @@ public: | |||
|      */ | ||||
|     static FileType IdentifyType(FileUtil::IOFile& file); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Returns the type of this file | ||||
|      * @return FileType corresponding to the loaded file | ||||
|      */ | ||||
|     FileType GetFileType() override { | ||||
|         return IdentifyType(file); | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * Load the bootable file | ||||
|      * @return ResultStatus result of function | ||||
|  |  | |||
|  | @ -27,6 +27,14 @@ public: | |||
|      */ | ||||
|     static FileType IdentifyType(FileUtil::IOFile& file); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Returns the type of this file | ||||
|      * @return FileType corresponding to the loaded file | ||||
|      */ | ||||
|     FileType GetFileType() override { | ||||
|         return IdentifyType(file); | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * Load the bootable file | ||||
|      * @return ResultStatus result of function | ||||
|  |  | |||
|  | @ -8,9 +8,7 @@ | |||
| #include "common/logging/log.h" | ||||
| #include "common/string_util.h" | ||||
| 
 | ||||
| #include "core/file_sys/archive_romfs.h" | ||||
| #include "core/hle/kernel/process.h" | ||||
| #include "core/hle/service/fs/archive.h" | ||||
| #include "core/loader/3dsx.h" | ||||
| #include "core/loader/elf.h" | ||||
| #include "core/loader/ncch.h" | ||||
|  | @ -67,6 +65,9 @@ FileType GuessFromExtension(const std::string& extension_) { | |||
|     if (extension == ".3dsx") | ||||
|         return FileType::THREEDSX; | ||||
| 
 | ||||
|     if (extension == ".cia") | ||||
|         return FileType::CIA; | ||||
| 
 | ||||
|     return FileType::Unknown; | ||||
| } | ||||
| 
 | ||||
|  | @ -90,7 +91,15 @@ const char* GetFileTypeString(FileType type) { | |||
|     return "unknown"; | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<AppLoader> GetLoader(FileUtil::IOFile&& file, FileType type, | ||||
| /**
 | ||||
|  * Get a loader for a file with a specific type | ||||
|  * @param file The file to load | ||||
|  * @param type The type of the file | ||||
|  * @param filename the file name (without path) | ||||
|  * @param filepath the file full path (with name) | ||||
|  * @return std::unique_ptr<AppLoader> a pointer to a loader object;  nullptr for unsupported type | ||||
|  */ | ||||
| static std::unique_ptr<AppLoader> GetFileLoader(FileUtil::IOFile&& file, FileType type, | ||||
|     const std::string& filename, const std::string& filepath) { | ||||
|     switch (type) { | ||||
| 
 | ||||
|  | @ -108,15 +117,15 @@ std::unique_ptr<AppLoader> GetLoader(FileUtil::IOFile&& file, FileType type, | |||
|         return std::make_unique<AppLoader_NCCH>(std::move(file), filepath); | ||||
| 
 | ||||
|     default: | ||||
|         return std::unique_ptr<AppLoader>(); | ||||
|         return nullptr; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| ResultStatus LoadFile(const std::string& filename) { | ||||
| std::unique_ptr<AppLoader> GetLoader(const std::string& filename) { | ||||
|     FileUtil::IOFile file(filename, "rb"); | ||||
|     if (!file.IsOpen()) { | ||||
|         LOG_ERROR(Loader, "Failed to load file %s", filename.c_str()); | ||||
|         return ResultStatus::Error; | ||||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
|     std::string filename_filename, filename_extension; | ||||
|  | @ -133,44 +142,7 @@ ResultStatus LoadFile(const std::string& filename) { | |||
| 
 | ||||
|     LOG_INFO(Loader, "Loading file %s as %s...", filename.c_str(), GetFileTypeString(type)); | ||||
| 
 | ||||
|     std::unique_ptr<AppLoader> app_loader = GetLoader(std::move(file), type, filename_filename, filename); | ||||
| 
 | ||||
|     switch (type) { | ||||
| 
 | ||||
|     // 3DSX file format...
 | ||||
|     // or NCCH/NCSD container formats...
 | ||||
|     case FileType::THREEDSX: | ||||
|     case FileType::CXI: | ||||
|     case FileType::CCI: | ||||
|     { | ||||
|         // Load application and RomFS
 | ||||
|         ResultStatus result = app_loader->Load(); | ||||
|         if (ResultStatus::Success == result) { | ||||
|             Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_RomFS>(*app_loader), Service::FS::ArchiveIdCode::RomFS); | ||||
|             return ResultStatus::Success; | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     // Standard ELF file format...
 | ||||
|     case FileType::ELF: | ||||
|         return app_loader->Load(); | ||||
| 
 | ||||
|     // CIA file format...
 | ||||
|     case FileType::CIA: | ||||
|         return ResultStatus::ErrorNotImplemented; | ||||
| 
 | ||||
|     // Error occurred durring IdentifyFile...
 | ||||
|     case FileType::Error: | ||||
| 
 | ||||
|     // IdentifyFile could know identify file type...
 | ||||
|     case FileType::Unknown: | ||||
|     { | ||||
|         LOG_CRITICAL(Loader, "File %s is of unknown type.", filename.c_str()); | ||||
|         return ResultStatus::ErrorInvalidFormat; | ||||
|     } | ||||
|     } | ||||
|     return ResultStatus::Error; | ||||
|     return GetFileLoader(std::move(file), type, filename_filename, filename); | ||||
| } | ||||
| 
 | ||||
| } // namespace Loader
 | ||||
|  |  | |||
|  | @ -10,10 +10,8 @@ | |||
| #include <string> | ||||
| #include <vector> | ||||
| 
 | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/common_types.h" | ||||
| #include "common/file_util.h" | ||||
| #include "common/swap.h" | ||||
| 
 | ||||
| namespace Kernel { | ||||
| struct AddressMapping; | ||||
|  | @ -80,57 +78,18 @@ constexpr u32 MakeMagic(char a, char b, char c, char d) { | |||
|     return a | b << 8 | c << 16 | d << 24; | ||||
| } | ||||
| 
 | ||||
| /// SMDH data structure that contains titles, icons etc. See https://www.3dbrew.org/wiki/SMDH
 | ||||
| struct SMDH { | ||||
|     u32_le magic; | ||||
|     u16_le version; | ||||
|     INSERT_PADDING_BYTES(2); | ||||
| 
 | ||||
|     struct Title { | ||||
|         std::array<u16, 0x40> short_title; | ||||
|         std::array<u16, 0x80> long_title; | ||||
|         std::array<u16, 0x40> publisher; | ||||
|     }; | ||||
|     std::array<Title, 16> titles; | ||||
| 
 | ||||
|     std::array<u8, 16> ratings; | ||||
|     u32_le region_lockout; | ||||
|     u32_le match_maker_id; | ||||
|     u64_le match_maker_bit_id; | ||||
|     u32_le flags; | ||||
|     u16_le eula_version; | ||||
|     INSERT_PADDING_BYTES(2); | ||||
|     float_le banner_animation_frame; | ||||
|     u32_le cec_id; | ||||
|     INSERT_PADDING_BYTES(8); | ||||
| 
 | ||||
|     std::array<u8, 0x480> small_icon; | ||||
|     std::array<u8, 0x1200> large_icon; | ||||
| 
 | ||||
|     /// indicates the language used for each title entry
 | ||||
|     enum class TitleLanguage { | ||||
|         Japanese = 0, | ||||
|         English = 1, | ||||
|         French = 2, | ||||
|         German = 3, | ||||
|         Italian = 4, | ||||
|         Spanish = 5, | ||||
|         SimplifiedChinese = 6, | ||||
|         Korean= 7, | ||||
|         Dutch = 8, | ||||
|         Portuguese = 9, | ||||
|         Russian = 10, | ||||
|         TraditionalChinese = 11 | ||||
|     }; | ||||
| }; | ||||
| static_assert(sizeof(SMDH) == 0x36C0, "SMDH structure size is wrong"); | ||||
| 
 | ||||
| /// Interface for loading an application
 | ||||
| class AppLoader : NonCopyable { | ||||
| public: | ||||
|     AppLoader(FileUtil::IOFile&& file) : file(std::move(file)) { } | ||||
|     virtual ~AppLoader() { } | ||||
| 
 | ||||
|     /**
 | ||||
|      * Returns the type of this file | ||||
|      * @return FileType corresponding to the loaded file | ||||
|      */ | ||||
|     virtual FileType GetFileType() = 0; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Load the application | ||||
|      * @return ResultStatus result of function | ||||
|  | @ -197,20 +156,10 @@ protected: | |||
| extern const std::initializer_list<Kernel::AddressMapping> default_address_mappings; | ||||
| 
 | ||||
| /**
 | ||||
|  * Get a loader for a file with a specific type | ||||
|  * @param file The file to load | ||||
|  * @param type The type of the file | ||||
|  * @param filename the file name (without path) | ||||
|  * @param filepath the file full path (with name) | ||||
|  * @return std::unique_ptr<AppLoader> a pointer to a loader object;  nullptr for unsupported type | ||||
|  */ | ||||
| std::unique_ptr<AppLoader> GetLoader(FileUtil::IOFile&& file, FileType type, const std::string& filename, const std::string& filepath); | ||||
| 
 | ||||
| /**
 | ||||
|  * Identifies and loads a bootable file | ||||
|  * Identifies a bootable file and return a suitable loader | ||||
|  * @param filename String filename of bootable file | ||||
|  * @return ResultStatus result of function | ||||
|  * @return best loader for this file | ||||
|  */ | ||||
| ResultStatus LoadFile(const std::string& filename); | ||||
| std::unique_ptr<AppLoader> GetLoader(const std::string& filename); | ||||
| 
 | ||||
| } // namespace
 | ||||
|  |  | |||
|  | @ -10,8 +10,10 @@ | |||
| #include "common/string_util.h" | ||||
| #include "common/swap.h" | ||||
| 
 | ||||
| #include "core/file_sys/archive_romfs.h" | ||||
| #include "core/hle/kernel/process.h" | ||||
| #include "core/hle/kernel/resource_limit.h" | ||||
| #include "core/hle/service/fs/archive.h" | ||||
| #include "core/loader/ncch.h" | ||||
| #include "core/memory.h" | ||||
| 
 | ||||
|  | @ -303,7 +305,12 @@ ResultStatus AppLoader_NCCH::Load() { | |||
| 
 | ||||
|     is_loaded = true; // Set state to loaded
 | ||||
| 
 | ||||
|     return LoadExec(); // Load the executable into memory for booting
 | ||||
|     result = LoadExec(); // Load the executable into memory for booting
 | ||||
|     if (ResultStatus::Success != result) | ||||
|         return result; | ||||
| 
 | ||||
|     Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_RomFS>(*this), Service::FS::ArchiveIdCode::RomFS); | ||||
|     return ResultStatus::Success; | ||||
| } | ||||
| 
 | ||||
| ResultStatus AppLoader_NCCH::ReadCode(std::vector<u8>& buffer) { | ||||
|  |  | |||
|  | @ -173,6 +173,14 @@ public: | |||
|      */ | ||||
|     static FileType IdentifyType(FileUtil::IOFile& file); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Returns the type of this file | ||||
|      * @return FileType corresponding to the loaded file | ||||
|      */ | ||||
|     FileType GetFileType() override { | ||||
|         return IdentifyType(file); | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * Load the application | ||||
|      * @return ResultStatus result of function | ||||
|  |  | |||
							
								
								
									
										54
									
								
								src/core/loader/smdh.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/core/loader/smdh.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,54 @@ | |||
| // Copyright 2016 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <cstring> | ||||
| #include <vector> | ||||
| 
 | ||||
| #include "common/common_types.h" | ||||
| 
 | ||||
| #include "core/loader/loader.h" | ||||
| #include "core/loader/smdh.h" | ||||
| 
 | ||||
| #include "video_core/utils.h" | ||||
| 
 | ||||
| namespace Loader { | ||||
| 
 | ||||
| bool IsValidSMDH(const std::vector<u8>& smdh_data) { | ||||
|     if (smdh_data.size() < sizeof(Loader::SMDH)) | ||||
|         return false; | ||||
| 
 | ||||
|     u32 magic; | ||||
|     memcpy(&magic, smdh_data.data(), sizeof(u32)); | ||||
| 
 | ||||
|     return Loader::MakeMagic('S', 'M', 'D', 'H') == magic; | ||||
| } | ||||
| 
 | ||||
| std::vector<u16> SMDH::GetIcon(bool large) const { | ||||
|     u32 size; | ||||
|     const u8* icon_data; | ||||
| 
 | ||||
|     if (large) { | ||||
|         size = 48; | ||||
|         icon_data = large_icon.data(); | ||||
|     } else { | ||||
|         size = 24; | ||||
|         icon_data = small_icon.data(); | ||||
|     } | ||||
| 
 | ||||
|     std::vector<u16> icon(size * size); | ||||
|     for (u32 x = 0; x < size; ++x) { | ||||
|         for (u32 y = 0; y < size; ++y) { | ||||
|             u32 coarse_y = y & ~7; | ||||
|             const u8* pixel = icon_data + VideoCore::GetMortonOffset(x, y, 2) + coarse_y * size * 2; | ||||
|             icon[x + size * y] = (pixel[1] << 8) + pixel[0]; | ||||
|         } | ||||
|     } | ||||
|     return icon; | ||||
| } | ||||
| 
 | ||||
| std::array<u16, 0x40> SMDH::GetShortTitle(Loader::SMDH::TitleLanguage language) const { | ||||
|     return titles[static_cast<int>(language)].short_title; | ||||
| } | ||||
| 
 | ||||
| } // namespace
 | ||||
							
								
								
									
										82
									
								
								src/core/loader/smdh.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/core/loader/smdh.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,82 @@ | |||
| // Copyright 2016 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <array> | ||||
| #include <vector> | ||||
| 
 | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/common_types.h" | ||||
| #include "common/swap.h" | ||||
| 
 | ||||
| namespace Loader { | ||||
| 
 | ||||
| /**
 | ||||
|  * Tests if data is a valid SMDH by its length and magic number. | ||||
|  * @param smdh_data data buffer to test | ||||
|  * @return bool test result | ||||
|  */ | ||||
| bool IsValidSMDH(const std::vector<u8>& smdh_data); | ||||
| 
 | ||||
| /// SMDH data structure that contains titles, icons etc. See https://www.3dbrew.org/wiki/SMDH
 | ||||
| struct SMDH { | ||||
|     u32_le magic; | ||||
|     u16_le version; | ||||
|     INSERT_PADDING_BYTES(2); | ||||
| 
 | ||||
|     struct Title { | ||||
|         std::array<u16, 0x40> short_title; | ||||
|         std::array<u16, 0x80> long_title; | ||||
|         std::array<u16, 0x40> publisher; | ||||
|     }; | ||||
|     std::array<Title, 16> titles; | ||||
| 
 | ||||
|     std::array<u8, 16> ratings; | ||||
|     u32_le region_lockout; | ||||
|     u32_le match_maker_id; | ||||
|     u64_le match_maker_bit_id; | ||||
|     u32_le flags; | ||||
|     u16_le eula_version; | ||||
|     INSERT_PADDING_BYTES(2); | ||||
|     float_le banner_animation_frame; | ||||
|     u32_le cec_id; | ||||
|     INSERT_PADDING_BYTES(8); | ||||
| 
 | ||||
|     std::array<u8, 0x480> small_icon; | ||||
|     std::array<u8, 0x1200> large_icon; | ||||
| 
 | ||||
|     /// indicates the language used for each title entry
 | ||||
|     enum class TitleLanguage { | ||||
|         Japanese = 0, | ||||
|         English = 1, | ||||
|         French = 2, | ||||
|         German = 3, | ||||
|         Italian = 4, | ||||
|         Spanish = 5, | ||||
|         SimplifiedChinese = 6, | ||||
|         Korean= 7, | ||||
|         Dutch = 8, | ||||
|         Portuguese = 9, | ||||
|         Russian = 10, | ||||
|         TraditionalChinese = 11 | ||||
|     }; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Gets game icon from SMDH | ||||
|      * @param large If true, returns large icon (48x48), otherwise returns small icon (24x24) | ||||
|      * @return vector of RGB565 data | ||||
|      */ | ||||
|     std::vector<u16> GetIcon(bool large) const; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Gets the short game title from SMDH | ||||
|      * @param language title language | ||||
|      * @return UTF-16 array of the short title | ||||
|      */ | ||||
|     std::array<u16, 0x40> GetShortTitle(Loader::SMDH::TitleLanguage language) const; | ||||
| }; | ||||
| static_assert(sizeof(SMDH) == 0x36C0, "SMDH structure size is wrong"); | ||||
| 
 | ||||
| } // namespace
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue