mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Merge pull request #1700 from wwylele/gamelist-icon
Qt: display game icon and title in the game list
This commit is contained in:
		
						commit
						55946cdc11
					
				
					 10 changed files with 260 additions and 37 deletions
				
			
		|  | @ -303,4 +303,31 @@ ResultStatus AppLoader_THREEDSX::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& ro | |||
|     return ResultStatus::ErrorNotUsed; | ||||
| } | ||||
| 
 | ||||
| ResultStatus AppLoader_THREEDSX::ReadIcon(std::vector<u8>& buffer) { | ||||
|     if (!file.IsOpen()) | ||||
|         return ResultStatus::Error; | ||||
| 
 | ||||
|     // Reset read pointer in case this file has been read before.
 | ||||
|     file.Seek(0, SEEK_SET); | ||||
| 
 | ||||
|     THREEDSX_Header hdr; | ||||
|     if (file.ReadBytes(&hdr, sizeof(THREEDSX_Header)) != sizeof(THREEDSX_Header)) | ||||
|         return ResultStatus::Error; | ||||
| 
 | ||||
|     if (hdr.header_size != sizeof(THREEDSX_Header)) | ||||
|         return ResultStatus::Error; | ||||
| 
 | ||||
|     // Check if the 3DSX has a SMDH...
 | ||||
|     if (hdr.smdh_offset != 0) { | ||||
|         file.Seek(hdr.smdh_offset, SEEK_SET); | ||||
|         buffer.resize(hdr.smdh_size); | ||||
| 
 | ||||
|         if (file.ReadBytes(&buffer[0], hdr.smdh_size) != hdr.smdh_size) | ||||
|             return ResultStatus::Error; | ||||
| 
 | ||||
|         return ResultStatus::Success; | ||||
|     } | ||||
|     return ResultStatus::ErrorNotUsed; | ||||
| } | ||||
| 
 | ||||
| } // namespace Loader
 | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ namespace Loader { | |||
| /// Loads an 3DSX file
 | ||||
| class AppLoader_THREEDSX final : public AppLoader { | ||||
| public: | ||||
|     AppLoader_THREEDSX(FileUtil::IOFile&& file, std::string filename, const std::string& filepath) | ||||
|     AppLoader_THREEDSX(FileUtil::IOFile&& file, const std::string& filename, const std::string& filepath) | ||||
|         : AppLoader(std::move(file)), filename(std::move(filename)), filepath(filepath) {} | ||||
| 
 | ||||
|     /**
 | ||||
|  | @ -33,6 +33,13 @@ public: | |||
|      */ | ||||
|     ResultStatus Load() override; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Get the icon (typically icon section) of the application | ||||
|      * @param buffer Reference to buffer to store data | ||||
|      * @return ResultStatus result of function | ||||
|      */ | ||||
|     ResultStatus ReadIcon(std::vector<u8>& buffer) override; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Get the RomFS of the application | ||||
|      * @param romfs_file Reference to buffer to store data | ||||
|  |  | |||
|  | @ -90,6 +90,28 @@ const char* GetFileTypeString(FileType type) { | |||
|     return "unknown"; | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<AppLoader> GetLoader(FileUtil::IOFile&& file, FileType type, | ||||
|     const std::string& filename, const std::string& filepath) { | ||||
|     switch (type) { | ||||
| 
 | ||||
|     // 3DSX file format.
 | ||||
|     case FileType::THREEDSX: | ||||
|         return std::make_unique<AppLoader_THREEDSX>(std::move(file), filename, filepath); | ||||
| 
 | ||||
|     // Standard ELF file format.
 | ||||
|     case FileType::ELF: | ||||
|         return std::make_unique<AppLoader_ELF>(std::move(file), filename); | ||||
| 
 | ||||
|     // NCCH/NCSD container formats.
 | ||||
|     case FileType::CXI: | ||||
|     case FileType::CCI: | ||||
|         return std::make_unique<AppLoader_NCCH>(std::move(file), filepath); | ||||
| 
 | ||||
|     default: | ||||
|         return std::unique_ptr<AppLoader>(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| ResultStatus LoadFile(const std::string& filename) { | ||||
|     FileUtil::IOFile file(filename, "rb"); | ||||
|     if (!file.IsOpen()) { | ||||
|  | @ -111,15 +133,19 @@ 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...
 | ||||
|     // 3DSX file format...
 | ||||
|     // or NCCH/NCSD container formats...
 | ||||
|     case FileType::THREEDSX: | ||||
|     case FileType::CXI: | ||||
|     case FileType::CCI: | ||||
|     { | ||||
|         AppLoader_THREEDSX app_loader(std::move(file), filename_filename, filename); | ||||
|         // Load application and RomFS
 | ||||
|         if (ResultStatus::Success == app_loader.Load()) { | ||||
|             Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_RomFS>(app_loader), Service::FS::ArchiveIdCode::RomFS); | ||||
|         if (ResultStatus::Success == app_loader->Load()) { | ||||
|             Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_RomFS>(*app_loader), Service::FS::ArchiveIdCode::RomFS); | ||||
|             return ResultStatus::Success; | ||||
|         } | ||||
|         break; | ||||
|  | @ -127,21 +153,7 @@ ResultStatus LoadFile(const std::string& filename) { | |||
| 
 | ||||
|     // Standard ELF file format...
 | ||||
|     case FileType::ELF: | ||||
|         return AppLoader_ELF(std::move(file), filename_filename).Load(); | ||||
| 
 | ||||
|     // NCCH/NCSD container formats...
 | ||||
|     case FileType::CXI: | ||||
|     case FileType::CCI: | ||||
|     { | ||||
|         AppLoader_NCCH app_loader(std::move(file), filename); | ||||
| 
 | ||||
|         // 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 result; | ||||
|     } | ||||
|         return app_loader->Load(); | ||||
| 
 | ||||
|     // CIA file format...
 | ||||
|     case FileType::CIA: | ||||
|  |  | |||
|  | @ -10,8 +10,10 @@ | |||
| #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; | ||||
|  | @ -78,6 +80,51 @@ 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: | ||||
|  | @ -149,6 +196,16 @@ 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 | ||||
|  * @param filename String filename of bootable file | ||||
|  |  | |||
|  | @ -173,6 +173,10 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& | |||
|     if (!file.IsOpen()) | ||||
|         return ResultStatus::Error; | ||||
| 
 | ||||
|     ResultStatus result = LoadExeFS(); | ||||
|     if (result != ResultStatus::Success) | ||||
|         return result; | ||||
| 
 | ||||
|     LOG_DEBUG(Loader, "%d sections:", kMaxSections); | ||||
|     // Iterate through the ExeFs archive until we find a section with the specified name...
 | ||||
|     for (unsigned section_number = 0; section_number < kMaxSections; section_number++) { | ||||
|  | @ -215,9 +219,9 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& | |||
|     return ResultStatus::ErrorNotUsed; | ||||
| } | ||||
| 
 | ||||
| ResultStatus AppLoader_NCCH::Load() { | ||||
|     if (is_loaded) | ||||
|         return ResultStatus::ErrorAlreadyLoaded; | ||||
| ResultStatus AppLoader_NCCH::LoadExeFS() { | ||||
|     if (is_exefs_loaded) | ||||
|         return ResultStatus::Success; | ||||
| 
 | ||||
|     if (!file.IsOpen()) | ||||
|         return ResultStatus::Error; | ||||
|  | @ -282,6 +286,18 @@ ResultStatus AppLoader_NCCH::Load() { | |||
|     if (file.ReadBytes(&exefs_header, sizeof(ExeFs_Header)) != sizeof(ExeFs_Header)) | ||||
|         return ResultStatus::Error; | ||||
| 
 | ||||
|     is_exefs_loaded = true; | ||||
|     return ResultStatus::Success; | ||||
| } | ||||
| 
 | ||||
| ResultStatus AppLoader_NCCH::Load() { | ||||
|     if (is_loaded) | ||||
|         return ResultStatus::ErrorAlreadyLoaded; | ||||
| 
 | ||||
|     ResultStatus result = LoadExeFS(); | ||||
|     if (result != ResultStatus::Success) | ||||
|         return result; | ||||
| 
 | ||||
|     is_loaded = true; // Set state to loaded
 | ||||
| 
 | ||||
|     return LoadExec(); // Load the executable into memory for booting
 | ||||
|  |  | |||
|  | @ -232,6 +232,13 @@ private: | |||
|      */ | ||||
|     ResultStatus LoadExec(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Ensure ExeFS is loaded and ready for reading sections | ||||
|      * @return ResultStatus result of function | ||||
|      */ | ||||
|     ResultStatus LoadExeFS(); | ||||
| 
 | ||||
|     bool            is_exefs_loaded = false; | ||||
|     bool            is_compressed = false; | ||||
| 
 | ||||
|     u32             entry_point = 0; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue