forked from eden-emu/eden
		
	Avoid parsing RomFS to directory in NCA
This commit is contained in:
		
							parent
							
								
									44f76e2cfd
								
							
						
					
					
						commit
						f89988272e
					
				
					 18 changed files with 438 additions and 18 deletions
				
			
		|  | @ -62,6 +62,13 @@ enum class Language : u8 { | ||||||
|     Chinese = 14, |     Chinese = 14, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static std::array<std::string, 15> LANGUAGE_NAMES = { | ||||||
|  |     "AmericanEnglish", "BritishEnglish", "Japanese", | ||||||
|  |     "French",          "German",         "LatinAmericanSpanish", | ||||||
|  |     "Spanish",         "Italian",        "Dutch", | ||||||
|  |     "CanadianFrench",  "Portugese",      "Russian", | ||||||
|  |     "Korean",          "Taiwanese",      "Chinese"}; | ||||||
|  | 
 | ||||||
| // A class representing the format used by NX metadata files, typically named Control.nacp.
 | // 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.
 | // These store application name, dev name, title id, and other miscellaneous data.
 | ||||||
| class NACP { | class NACP { | ||||||
|  |  | ||||||
|  | @ -7,6 +7,7 @@ | ||||||
| #include "common/file_util.h" | #include "common/file_util.h" | ||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
| #include "core/file_sys/content_archive.h" | #include "core/file_sys/content_archive.h" | ||||||
|  | #include "core/file_sys/control_metadata.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" | ||||||
|  | @ -17,8 +18,50 @@ | ||||||
| 
 | 
 | ||||||
| namespace Loader { | namespace Loader { | ||||||
| 
 | 
 | ||||||
| AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file) | AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_) | ||||||
|     : AppLoader(std::move(file)) {} |     : AppLoader(std::move(file_)) { | ||||||
|  |     const auto dir = file->GetContainingDirectory(); | ||||||
|  | 
 | ||||||
|  |     // Icon
 | ||||||
|  |     FileSys::VirtualFile icon_file = nullptr; | ||||||
|  |     for (const auto& language : FileSys::LANGUAGE_NAMES) { | ||||||
|  |         icon_file = dir->GetFile("icon_" + language + ".dat"); | ||||||
|  |         if (icon_file != nullptr) { | ||||||
|  |             icon_data = icon_file->ReadAllBytes(); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (icon_data.empty()) { | ||||||
|  |         // Any png, jpeg, or bmp file
 | ||||||
|  |         const auto& files = dir->GetFiles(); | ||||||
|  |         const auto icon_iter = | ||||||
|  |             std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) { | ||||||
|  |                 return file->GetExtension() == "png" || file->GetExtension() == "jpg" || | ||||||
|  |                        file->GetExtension() == "bmp" || file->GetExtension() == "jpeg"; | ||||||
|  |             }); | ||||||
|  |         if (icon_iter != files.end()) | ||||||
|  |             icon_data = (*icon_iter)->ReadAllBytes(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Metadata
 | ||||||
|  |     FileSys::VirtualFile nacp_file = dir->GetFile("control.nacp"); | ||||||
|  |     if (nacp_file == nullptr) { | ||||||
|  |         const auto& files = dir->GetFiles(); | ||||||
|  |         const auto nacp_iter = | ||||||
|  |             std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) { | ||||||
|  |                 return file->GetExtension() == "nacp"; | ||||||
|  |             }); | ||||||
|  |         if (nacp_iter != files.end()) | ||||||
|  |             nacp_file = *nacp_iter; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (nacp_file != nullptr) { | ||||||
|  |         FileSys::NACP nacp(nacp_file); | ||||||
|  |         title_id = nacp.GetTitleId(); | ||||||
|  |         name = nacp.GetApplicationName(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory( | AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory( | ||||||
|     FileSys::VirtualDir directory) |     FileSys::VirtualDir directory) | ||||||
|  | @ -105,4 +148,25 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile | ||||||
|     return ResultStatus::Success; |     return ResultStatus::Success; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | ResultStatus AppLoader_DeconstructedRomDirectory::ReadIcon(std::vector<u8>& buffer) { | ||||||
|  |     if (icon_data.empty()) | ||||||
|  |         return ResultStatus::ErrorNotUsed; | ||||||
|  |     buffer = icon_data; | ||||||
|  |     return ResultStatus::Success; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultStatus AppLoader_DeconstructedRomDirectory::ReadProgramId(u64& out_program_id) { | ||||||
|  |     if (name.empty()) | ||||||
|  |         return ResultStatus::ErrorNotUsed; | ||||||
|  |     out_program_id = title_id; | ||||||
|  |     return ResultStatus::Success; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultStatus AppLoader_DeconstructedRomDirectory::ReadTitle(std::string& title) { | ||||||
|  |     if (name.empty()) | ||||||
|  |         return ResultStatus::ErrorNotUsed; | ||||||
|  |     title = name; | ||||||
|  |     return ResultStatus::Success; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } // namespace Loader
 | } // namespace Loader
 | ||||||
|  |  | ||||||
|  | @ -39,11 +39,18 @@ public: | ||||||
|     ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; |     ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; | ||||||
| 
 | 
 | ||||||
|     ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; |     ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; | ||||||
|  |     ResultStatus ReadIcon(std::vector<u8>& buffer) override; | ||||||
|  |     ResultStatus ReadProgramId(u64& out_program_id) override; | ||||||
|  |     ResultStatus ReadTitle(std::string& title) override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     FileSys::ProgramMetadata metadata; |     FileSys::ProgramMetadata metadata; | ||||||
|     FileSys::VirtualFile romfs; |     FileSys::VirtualFile romfs; | ||||||
|     FileSys::VirtualDir dir; |     FileSys::VirtualDir dir; | ||||||
|  | 
 | ||||||
|  |     std::vector<u8> icon_data; | ||||||
|  |     std::string name; | ||||||
|  |     u64 title_id{}; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace Loader
 | } // namespace Loader
 | ||||||
|  |  | ||||||
|  | @ -68,7 +68,7 @@ FileType GuessFromFilename(const std::string& name) { | ||||||
|     return FileType::Unknown; |     return FileType::Unknown; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const char* GetFileTypeString(FileType type) { | std::string GetFileTypeString(FileType type) { | ||||||
|     switch (type) { |     switch (type) { | ||||||
|     case FileType::ELF: |     case FileType::ELF: | ||||||
|         return "ELF"; |         return "ELF"; | ||||||
|  |  | ||||||
|  | @ -61,7 +61,7 @@ FileType GuessFromFilename(const std::string& name); | ||||||
| /**
 | /**
 | ||||||
|  * Convert a FileType into a string which can be displayed to the user. |  * Convert a FileType into a string which can be displayed to the user. | ||||||
|  */ |  */ | ||||||
| const char* GetFileTypeString(FileType type); | std::string GetFileTypeString(FileType type); | ||||||
| 
 | 
 | ||||||
| /// Return type for functions in Loader namespace
 | /// Return type for functions in Loader namespace
 | ||||||
| enum class ResultStatus { | enum class ResultStatus { | ||||||
|  |  | ||||||
|  | @ -77,8 +77,8 @@ ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) { | ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) { | ||||||
|     if (nca == nullptr) |     if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) | ||||||
|         return ResultStatus::ErrorNotLoaded; |         return ResultStatus::ErrorInvalidFormat; | ||||||
|     out_program_id = nca->GetTitleId(); |     out_program_id = nca->GetTitleId(); | ||||||
|     return ResultStatus::Success; |     return ResultStatus::Success; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -33,6 +33,7 @@ public: | ||||||
|     ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; |     ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; | ||||||
| 
 | 
 | ||||||
|     ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; |     ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; | ||||||
|  |     ResultStatus ReadProgramId(u64& out_program_id) override; | ||||||
| 
 | 
 | ||||||
|     ResultStatus ReadProgramId(u64& out_program_id) override; |     ResultStatus ReadProgramId(u64& out_program_id) override; | ||||||
| 
 | 
 | ||||||
|  | @ -41,6 +42,7 @@ public: | ||||||
| private: | private: | ||||||
|     FileSys::ProgramMetadata metadata; |     FileSys::ProgramMetadata metadata; | ||||||
| 
 | 
 | ||||||
|  |     FileSys::NCAHeader header; | ||||||
|     std::unique_ptr<FileSys::NCA> nca; |     std::unique_ptr<FileSys::NCA> nca; | ||||||
|     std::unique_ptr<AppLoader_DeconstructedRomDirectory> directory_loader; |     std::unique_ptr<AppLoader_DeconstructedRomDirectory> directory_loader; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -17,6 +17,8 @@ add_executable(yuzu | ||||||
|     configuration/configure_debug.h |     configuration/configure_debug.h | ||||||
|     configuration/configure_dialog.cpp |     configuration/configure_dialog.cpp | ||||||
|     configuration/configure_dialog.h |     configuration/configure_dialog.h | ||||||
|  |     configuration/configure_gamelist.cpp | ||||||
|  |     configuration/configure_gamelist.h | ||||||
|     configuration/configure_general.cpp |     configuration/configure_general.cpp | ||||||
|     configuration/configure_general.h |     configuration/configure_general.h | ||||||
|     configuration/configure_graphics.cpp |     configuration/configure_graphics.cpp | ||||||
|  | @ -59,6 +61,7 @@ set(UIS | ||||||
|     configuration/configure.ui |     configuration/configure.ui | ||||||
|     configuration/configure_audio.ui |     configuration/configure_audio.ui | ||||||
|     configuration/configure_debug.ui |     configuration/configure_debug.ui | ||||||
|  |     configuration/configure_gamelist.ui | ||||||
|     configuration/configure_general.ui |     configuration/configure_general.ui | ||||||
|     configuration/configure_graphics.ui |     configuration/configure_graphics.ui | ||||||
|     configuration/configure_input.ui |     configuration/configure_input.ui | ||||||
|  |  | ||||||
|  | @ -122,6 +122,13 @@ void Config::ReadValues() { | ||||||
|     qt_config->beginGroup("UI"); |     qt_config->beginGroup("UI"); | ||||||
|     UISettings::values.theme = qt_config->value("theme", UISettings::themes[0].second).toString(); |     UISettings::values.theme = qt_config->value("theme", UISettings::themes[0].second).toString(); | ||||||
| 
 | 
 | ||||||
|  |     qt_config->beginGroup("UIGameList"); | ||||||
|  |     UISettings::values.show_unknown = qt_config->value("show_unknown", true).toBool(); | ||||||
|  |     UISettings::values.icon_size = qt_config->value("icon_size", 48).toUInt(); | ||||||
|  |     UISettings::values.row_1_text_id = qt_config->value("row_1_text_id", 0).toUInt(); | ||||||
|  |     UISettings::values.row_2_text_id = qt_config->value("row_2_text_id", 3).toUInt(); | ||||||
|  |     qt_config->endGroup(); | ||||||
|  | 
 | ||||||
|     qt_config->beginGroup("UILayout"); |     qt_config->beginGroup("UILayout"); | ||||||
|     UISettings::values.geometry = qt_config->value("geometry").toByteArray(); |     UISettings::values.geometry = qt_config->value("geometry").toByteArray(); | ||||||
|     UISettings::values.state = qt_config->value("state").toByteArray(); |     UISettings::values.state = qt_config->value("state").toByteArray(); | ||||||
|  | @ -234,6 +241,13 @@ void Config::SaveValues() { | ||||||
|     qt_config->beginGroup("UI"); |     qt_config->beginGroup("UI"); | ||||||
|     qt_config->setValue("theme", UISettings::values.theme); |     qt_config->setValue("theme", UISettings::values.theme); | ||||||
| 
 | 
 | ||||||
|  |     qt_config->beginGroup("UIGameList"); | ||||||
|  |     qt_config->setValue("show_unknown", UISettings::values.show_unknown); | ||||||
|  |     qt_config->setValue("icon_size", UISettings::values.icon_size); | ||||||
|  |     qt_config->setValue("row_1_text_id", UISettings::values.row_1_text_id); | ||||||
|  |     qt_config->setValue("row_2_text_id", UISettings::values.row_2_text_id); | ||||||
|  |     qt_config->endGroup(); | ||||||
|  | 
 | ||||||
|     qt_config->beginGroup("UILayout"); |     qt_config->beginGroup("UILayout"); | ||||||
|     qt_config->setValue("geometry", UISettings::values.geometry); |     qt_config->setValue("geometry", UISettings::values.geometry); | ||||||
|     qt_config->setValue("state", UISettings::values.state); |     qt_config->setValue("state", UISettings::values.state); | ||||||
|  |  | ||||||
|  | @ -24,6 +24,11 @@ | ||||||
|        <string>General</string> |        <string>General</string> | ||||||
|       </attribute> |       </attribute> | ||||||
|      </widget> |      </widget> | ||||||
|  |       <widget class="ConfigureGameList" name="gameListTab"> | ||||||
|  |         <attribute name="title"> | ||||||
|  |           <string>Game List</string> | ||||||
|  |         </attribute> | ||||||
|  |       </widget> | ||||||
|      <widget class="ConfigureSystem" name="systemTab"> |      <widget class="ConfigureSystem" name="systemTab"> | ||||||
|       <attribute name="title"> |       <attribute name="title"> | ||||||
|        <string>System</string> |        <string>System</string> | ||||||
|  | @ -67,6 +72,12 @@ | ||||||
|    <header>configuration/configure_general.h</header> |    <header>configuration/configure_general.h</header> | ||||||
|    <container>1</container> |    <container>1</container> | ||||||
|   </customwidget> |   </customwidget> | ||||||
|  |    <customwidget> | ||||||
|  |      <class>ConfigureGameList</class> | ||||||
|  |      <extends>QWidget</extends> | ||||||
|  |      <header>configuration/configure_gamelist.h</header> | ||||||
|  |      <container>1</container> | ||||||
|  |    </customwidget> | ||||||
|   <customwidget> |   <customwidget> | ||||||
|    <class>ConfigureSystem</class> |    <class>ConfigureSystem</class> | ||||||
|    <extends>QWidget</extends> |    <extends>QWidget</extends> | ||||||
|  |  | ||||||
|  | @ -18,6 +18,7 @@ void ConfigureDialog::setConfiguration() {} | ||||||
| 
 | 
 | ||||||
| void ConfigureDialog::applyConfiguration() { | void ConfigureDialog::applyConfiguration() { | ||||||
|     ui->generalTab->applyConfiguration(); |     ui->generalTab->applyConfiguration(); | ||||||
|  |     ui->gameListTab->applyConfiguration(); | ||||||
|     ui->systemTab->applyConfiguration(); |     ui->systemTab->applyConfiguration(); | ||||||
|     ui->inputTab->applyConfiguration(); |     ui->inputTab->applyConfiguration(); | ||||||
|     ui->graphicsTab->applyConfiguration(); |     ui->graphicsTab->applyConfiguration(); | ||||||
|  |  | ||||||
							
								
								
									
										61
									
								
								src/yuzu/configuration/configure_gamelist.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/yuzu/configuration/configure_gamelist.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,61 @@ | ||||||
|  | // Copyright 2016 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #include "core/core.h" | ||||||
|  | #include "core/settings.h" | ||||||
|  | #include "ui_configure_gamelist.h" | ||||||
|  | #include "ui_settings.h" | ||||||
|  | #include "yuzu/configuration/configure_gamelist.h" | ||||||
|  | 
 | ||||||
|  | ConfigureGameList::ConfigureGameList(QWidget* parent) | ||||||
|  |     : QWidget(parent), ui(new Ui::ConfigureGameList) { | ||||||
|  |     ui->setupUi(this); | ||||||
|  | 
 | ||||||
|  |     static std::vector<std::pair<u32, std::string>> default_icon_sizes{ | ||||||
|  |         std::make_pair(0, "None"),        std::make_pair(24, "Small"), | ||||||
|  |         std::make_pair(48, "Standard"),   std::make_pair(96, "Large"), | ||||||
|  |         std::make_pair(256, "Full Size"), | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     for (const auto& size : default_icon_sizes) { | ||||||
|  |         ui->icon_size_combobox->addItem(QString::fromStdString(size.second + " (" + | ||||||
|  |                                                                std::to_string(size.first) + "x" + | ||||||
|  |                                                                std::to_string(size.first) + ")"), | ||||||
|  |                                         size.first); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     static std::vector<std::string> row_text_names{ | ||||||
|  |         "Filename", | ||||||
|  |         "Filetype", | ||||||
|  |         "Title ID", | ||||||
|  |         "Title Name", | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     for (size_t i = 0; i < row_text_names.size(); ++i) { | ||||||
|  |         ui->row_1_text_combobox->addItem(QString::fromStdString(row_text_names[i]), i); | ||||||
|  |         ui->row_2_text_combobox->addItem(QString::fromStdString(row_text_names[i]), i); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     this->setConfiguration(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ConfigureGameList::~ConfigureGameList() {} | ||||||
|  | 
 | ||||||
|  | void ConfigureGameList::setConfiguration() { | ||||||
|  |     ui->show_unknown->setChecked(UISettings::values.show_unknown); | ||||||
|  |     ui->icon_size_combobox->setCurrentIndex( | ||||||
|  |         ui->icon_size_combobox->findData(UISettings::values.icon_size)); | ||||||
|  |     ui->row_1_text_combobox->setCurrentIndex( | ||||||
|  |         ui->row_1_text_combobox->findData(UISettings::values.row_1_text_id)); | ||||||
|  |     ui->row_2_text_combobox->setCurrentIndex( | ||||||
|  |         ui->row_2_text_combobox->findData(UISettings::values.row_2_text_id)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigureGameList::applyConfiguration() { | ||||||
|  |     UISettings::values.show_unknown = ui->show_unknown->isChecked(); | ||||||
|  |     UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt(); | ||||||
|  |     UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt(); | ||||||
|  |     UISettings::values.row_2_text_id = ui->row_2_text_combobox->currentData().toUInt(); | ||||||
|  |     Settings::Apply(); | ||||||
|  | } | ||||||
							
								
								
									
										28
									
								
								src/yuzu/configuration/configure_gamelist.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/yuzu/configuration/configure_gamelist.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | ||||||
|  | // Copyright 2016 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <memory> | ||||||
|  | #include <QWidget> | ||||||
|  | 
 | ||||||
|  | namespace Ui { | ||||||
|  | class ConfigureGameList; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class ConfigureGameList : public QWidget { | ||||||
|  |     Q_OBJECT | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  |     explicit ConfigureGameList(QWidget* parent = nullptr); | ||||||
|  |     ~ConfigureGameList(); | ||||||
|  | 
 | ||||||
|  |     void applyConfiguration(); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     void setConfiguration(); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     std::unique_ptr<Ui::ConfigureGameList> ui; | ||||||
|  | }; | ||||||
							
								
								
									
										126
									
								
								src/yuzu/configuration/configure_gamelist.ui
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								src/yuzu/configuration/configure_gamelist.ui
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,126 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <ui version="4.0"> | ||||||
|  |  <class>ConfigureGameList</class> | ||||||
|  |   <widget class="QWidget" name="ConfigureGeneral"> | ||||||
|  |     <property name="geometry"> | ||||||
|  |       <rect> | ||||||
|  |         <x>0</x> | ||||||
|  |         <y>0</y> | ||||||
|  |         <width>300</width> | ||||||
|  |         <height>377</height> | ||||||
|  |       </rect> | ||||||
|  |     </property> | ||||||
|  |     <property name="windowTitle"> | ||||||
|  |       <string>Form</string> | ||||||
|  |     </property> | ||||||
|  |     <layout class="QHBoxLayout" name="HorizontalLayout"> | ||||||
|  |       <item> | ||||||
|  |         <layout class="QVBoxLayout" name="VerticalLayout"> | ||||||
|  |           <item> | ||||||
|  |             <widget class="QGroupBox" name="GeneralGroupBox"> | ||||||
|  |               <property name="title"> | ||||||
|  |                 <string>General</string> | ||||||
|  |               </property> | ||||||
|  |               <layout class="QHBoxLayout" name="GeneralHorizontalLayout"> | ||||||
|  |                 <item> | ||||||
|  |                   <layout class="QVBoxLayout" name="GeneralVerticalLayout"> | ||||||
|  |                     <item> | ||||||
|  |                       <widget class="QCheckBox" name="show_unknown"> | ||||||
|  |                         <property name="text"> | ||||||
|  |                           <string>Show files with type 'Unknown'</string> | ||||||
|  |                         </property> | ||||||
|  |                       </widget> | ||||||
|  |                     </item> | ||||||
|  |                   </layout> | ||||||
|  |                 </item> | ||||||
|  |               </layout> | ||||||
|  |             </widget> | ||||||
|  |           </item> | ||||||
|  |           <item> | ||||||
|  |             <widget class="QGroupBox" name="IconSizeGroupBox"> | ||||||
|  |               <property name="title"> | ||||||
|  |                 <string>Icon Size</string> | ||||||
|  |               </property> | ||||||
|  |               <layout class="QHBoxLayout" name="icon_size_qhbox_layout"> | ||||||
|  |                 <item> | ||||||
|  |                   <layout class="QVBoxLayout" name="icon_size_qvbox_layout"> | ||||||
|  |                     <item> | ||||||
|  |                       <layout class="QHBoxLayout" name="icon_size_qhbox_layout_2"> | ||||||
|  |                         <item> | ||||||
|  |                           <widget class="QLabel" name="icon_size_label"> | ||||||
|  |                             <property name="text"> | ||||||
|  |                               <string>Icon Size:</string> | ||||||
|  |                             </property> | ||||||
|  |                           </widget> | ||||||
|  |                         </item> | ||||||
|  |                         <item> | ||||||
|  |                           <widget class="QComboBox" name="icon_size_combobox"/> | ||||||
|  |                         </item> | ||||||
|  |                       </layout> | ||||||
|  |                     </item> | ||||||
|  |                   </layout> | ||||||
|  |                 </item> | ||||||
|  |               </layout> | ||||||
|  |             </widget> | ||||||
|  |           </item> | ||||||
|  |           <item> | ||||||
|  |             <widget class="QGroupBox" name="RowGroupBox"> | ||||||
|  |               <property name="title"> | ||||||
|  |                 <string>Row Text</string> | ||||||
|  |               </property> | ||||||
|  |               <layout class="QHBoxLayout" name="RowHorizontalLayout"> | ||||||
|  |                 <item> | ||||||
|  |                   <layout class="QVBoxLayout" name="RowVerticalLayout"> | ||||||
|  |                     <item> | ||||||
|  |                       <layout class="QHBoxLayout" name="row_1_qhbox_layout"> | ||||||
|  |                         <item> | ||||||
|  |                           <widget class="QLabel" name="row_1_label"> | ||||||
|  |                             <property name="text"> | ||||||
|  |                               <string>Row 1 Text:</string> | ||||||
|  |                             </property> | ||||||
|  |                           </widget> | ||||||
|  |                         </item> | ||||||
|  |                         <item> | ||||||
|  |                           <widget class="QComboBox" name="row_1_text_combobox"/> | ||||||
|  |                         </item> | ||||||
|  |                       </layout> | ||||||
|  |                     </item> | ||||||
|  |                     <item> | ||||||
|  |                       <layout class="QHBoxLayout" name="row_2_qhbox_layout"> | ||||||
|  |                         <item> | ||||||
|  |                           <widget class="QLabel" name="row_2_label"> | ||||||
|  |                             <property name="text"> | ||||||
|  |                               <string>Row 2 Text:</string> | ||||||
|  |                             </property> | ||||||
|  |                           </widget> | ||||||
|  |                         </item> | ||||||
|  |                         <item> | ||||||
|  |                           <widget class="QComboBox" name="row_2_text_combobox"/> | ||||||
|  |                         </item> | ||||||
|  |                       </layout> | ||||||
|  |                     </item> | ||||||
|  |                   </layout> | ||||||
|  |                 </item> | ||||||
|  |               </layout> | ||||||
|  |             </widget> | ||||||
|  |           </item> | ||||||
|  |           <item> | ||||||
|  |             <spacer name="verticalSpacer"> | ||||||
|  |               <property name="orientation"> | ||||||
|  |                 <enum>Qt::Vertical</enum> | ||||||
|  |               </property> | ||||||
|  |               <property name="sizeHint" stdset="0"> | ||||||
|  |                 <size> | ||||||
|  |                   <width>20</width> | ||||||
|  |                   <height>40</height> | ||||||
|  |                 </size> | ||||||
|  |               </property> | ||||||
|  |             </spacer> | ||||||
|  |           </item> | ||||||
|  |         </layout> | ||||||
|  |       </item> | ||||||
|  |     </layout> | ||||||
|  |   </widget> | ||||||
|  |  <resources/> | ||||||
|  |  <connections/> | ||||||
|  | </ui> | ||||||
|  | @ -12,6 +12,8 @@ | ||||||
| #include "common/common_paths.h" | #include "common/common_paths.h" | ||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
| #include "common/string_util.h" | #include "common/string_util.h" | ||||||
|  | #include "core/file_sys/content_archive.h" | ||||||
|  | #include "core/file_sys/control_metadata.h" | ||||||
| #include "core/file_sys/vfs_real.h" | #include "core/file_sys/vfs_real.h" | ||||||
| #include "core/loader/loader.h" | #include "core/loader/loader.h" | ||||||
| #include "game_list.h" | #include "game_list.h" | ||||||
|  | @ -398,8 +400,32 @@ void GameList::RefreshGameDirectory() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) { | void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) { | ||||||
|     const auto callback = [this, recursion](u64* num_entries_out, const std::string& directory, |     boost::container::flat_map<u64, std::shared_ptr<FileSys::NCA>> nca_control_map; | ||||||
|                                             const std::string& virtual_name) -> bool { | 
 | ||||||
|  |     const auto nca_control_callback = | ||||||
|  |         [this, &nca_control_map](u64* num_entries_out, const std::string& directory, | ||||||
|  |                                  const std::string& virtual_name) -> bool { | ||||||
|  |         std::string physical_name = directory + DIR_SEP + virtual_name; | ||||||
|  | 
 | ||||||
|  |         if (stop_processing) | ||||||
|  |             return false; // Breaks the callback loop.
 | ||||||
|  | 
 | ||||||
|  |         bool is_dir = FileUtil::IsDirectory(physical_name); | ||||||
|  |         QFileInfo file_info(physical_name.c_str()); | ||||||
|  |         if (!is_dir && file_info.suffix().toStdString() == "nca") { | ||||||
|  |             auto nca = std::make_shared<FileSys::NCA>( | ||||||
|  |                 std::make_shared<FileSys::RealVfsFile>(physical_name)); | ||||||
|  |             if (nca->GetType() == FileSys::NCAContentType::Control) | ||||||
|  |                 nca_control_map.insert_or_assign(nca->GetTitleId(), nca); | ||||||
|  |         } | ||||||
|  |         return true; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     FileUtil::ForeachDirectoryEntry(nullptr, dir_path, nca_control_callback); | ||||||
|  | 
 | ||||||
|  |     const auto callback = [this, recursion, | ||||||
|  |                            &nca_control_map](u64* num_entries_out, const std::string& directory, | ||||||
|  |                                              const std::string& virtual_name) -> bool { | ||||||
|         std::string physical_name = directory + DIR_SEP + virtual_name; |         std::string physical_name = directory + DIR_SEP + virtual_name; | ||||||
| 
 | 
 | ||||||
|         if (stop_processing) |         if (stop_processing) | ||||||
|  | @ -410,17 +436,50 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign | ||||||
|             (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) { |             (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) { | ||||||
|             std::unique_ptr<Loader::AppLoader> loader = |             std::unique_ptr<Loader::AppLoader> loader = | ||||||
|                 Loader::GetLoader(std::make_shared<FileSys::RealVfsFile>(physical_name)); |                 Loader::GetLoader(std::make_shared<FileSys::RealVfsFile>(physical_name)); | ||||||
|             if (!loader) |             if (!loader || ((loader->GetFileType() == Loader::FileType::Unknown || | ||||||
|  |                              loader->GetFileType() == Loader::FileType::Error) && | ||||||
|  |                             !UISettings::values.show_unknown)) | ||||||
|                 return true; |                 return true; | ||||||
| 
 | 
 | ||||||
|             std::vector<u8> smdh; |             std::vector<u8> icon; | ||||||
|             loader->ReadIcon(smdh); |             const auto res1 = loader->ReadIcon(icon); | ||||||
| 
 | 
 | ||||||
|             u64 program_id = 0; |             u64 program_id; | ||||||
|             loader->ReadProgramId(program_id); |             const auto res2 = loader->ReadProgramId(program_id); | ||||||
|  | 
 | ||||||
|  |             std::string name = " "; | ||||||
|  |             const auto res3 = loader->ReadTitle(name); | ||||||
|  | 
 | ||||||
|  |             if ((res1 == Loader::ResultStatus::ErrorNotUsed || | ||||||
|  |                  res1 == Loader::ResultStatus::ErrorNotImplemented) && | ||||||
|  |                 (res3 == Loader::ResultStatus::ErrorNotUsed || | ||||||
|  |                  res3 == Loader::ResultStatus::ErrorNotImplemented) && | ||||||
|  |                 res2 == Loader::ResultStatus::Success) { | ||||||
|  |                 // Use from metadata pool.
 | ||||||
|  |                 if (nca_control_map.find(program_id) != nca_control_map.end()) { | ||||||
|  |                     const auto nca = nca_control_map[program_id]; | ||||||
|  |                     auto control_dir = nca->GetSection(0); | ||||||
|  | 
 | ||||||
|  |                     auto nacp_file = control_dir->GetFile("control.nacp"); | ||||||
|  |                     FileSys::NACP nacp(nacp_file); | ||||||
|  |                     name = nacp.GetApplicationName(); | ||||||
|  | 
 | ||||||
|  |                     FileSys::VirtualFile icon_file = nullptr; | ||||||
|  |                     for (const auto& language : FileSys::LANGUAGE_NAMES) { | ||||||
|  |                         icon_file = control_dir->GetFile("icon_" + language + ".dat"); | ||||||
|  |                         if (icon_file != nullptr) { | ||||||
|  |                             icon = icon_file->ReadAllBytes(); | ||||||
|  |                             break; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|             emit EntryReady({ |             emit EntryReady({ | ||||||
|                 new GameListItemPath(FormatGameName(physical_name), smdh, program_id), |                 new GameListItemPath( | ||||||
|  |                     FormatGameName(physical_name), icon, QString::fromStdString(name), | ||||||
|  |                     QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())), | ||||||
|  |                     program_id), | ||||||
|                 new GameListItem( |                 new GameListItem( | ||||||
|                     QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))), |                     QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))), | ||||||
|                 new GameListItemSize(FileUtil::GetSize(physical_name)), |                 new GameListItemSize(FileUtil::GetSize(physical_name)), | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ | ||||||
| #include <QStandardItem> | #include <QStandardItem> | ||||||
| #include <QString> | #include <QString> | ||||||
| #include "common/string_util.h" | #include "common/string_util.h" | ||||||
|  | #include "ui_settings.h" | ||||||
| #include "yuzu/util/util.h" | #include "yuzu/util/util.h" | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -18,8 +19,7 @@ | ||||||
|  * @param large If true, returns large icon (48x48), otherwise returns small icon (24x24) |  * @param large If true, returns large icon (48x48), otherwise returns small icon (24x24) | ||||||
|  * @return QPixmap default icon |  * @return QPixmap default icon | ||||||
|  */ |  */ | ||||||
| static QPixmap GetDefaultIcon(bool large) { | static QPixmap GetDefaultIcon(u32 size) { | ||||||
|     int size = large ? 48 : 24; |  | ||||||
|     QPixmap icon(size, size); |     QPixmap icon(size, size); | ||||||
|     icon.fill(Qt::transparent); |     icon.fill(Qt::transparent); | ||||||
|     return icon; |     return icon; | ||||||
|  | @ -44,11 +44,25 @@ public: | ||||||
|     static const int FullPathRole = Qt::UserRole + 1; |     static const int FullPathRole = Qt::UserRole + 1; | ||||||
|     static const int TitleRole = Qt::UserRole + 2; |     static const int TitleRole = Qt::UserRole + 2; | ||||||
|     static const int ProgramIdRole = Qt::UserRole + 3; |     static const int ProgramIdRole = Qt::UserRole + 3; | ||||||
|  |     static const int FileTypeRole = Qt::UserRole + 4; | ||||||
| 
 | 
 | ||||||
|     GameListItemPath() = default; |     GameListItemPath() = default; | ||||||
|     GameListItemPath(const QString& game_path, const std::vector<u8>& smdh_data, u64 program_id) { |     GameListItemPath(const QString& game_path, const std::vector<u8>& picture_data, | ||||||
|  |                      const QString& game_name, const QString& game_type, u64 program_id) | ||||||
|  |         : GameListItem() { | ||||||
|         setData(game_path, FullPathRole); |         setData(game_path, FullPathRole); | ||||||
|  |         setData(game_name, TitleRole); | ||||||
|         setData(qulonglong(program_id), ProgramIdRole); |         setData(qulonglong(program_id), ProgramIdRole); | ||||||
|  |         setData(game_type, FileTypeRole); | ||||||
|  | 
 | ||||||
|  |         QPixmap picture; | ||||||
|  |         u32 size = UISettings::values.icon_size; | ||||||
|  |         if (!picture.loadFromData(picture_data.data(), picture_data.size())) | ||||||
|  |             picture = GetDefaultIcon(size); | ||||||
|  | 
 | ||||||
|  |         picture = picture.scaled(size, size); | ||||||
|  | 
 | ||||||
|  |         setData(picture, Qt::DecorationRole); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     QVariant data(int role) const override { |     QVariant data(int role) const override { | ||||||
|  | @ -57,7 +71,23 @@ public: | ||||||
|             Common::SplitPath(data(FullPathRole).toString().toStdString(), nullptr, &filename, |             Common::SplitPath(data(FullPathRole).toString().toStdString(), nullptr, &filename, | ||||||
|                               nullptr); |                               nullptr); | ||||||
|             QString title = data(TitleRole).toString(); |             QString title = data(TitleRole).toString(); | ||||||
|             return QString::fromStdString(filename) + (title.isEmpty() ? "" : "\n    " + title); | 
 | ||||||
|  |             std::vector<QString> row_data{ | ||||||
|  |                 QString::fromStdString(filename), | ||||||
|  |                 data(FileTypeRole).toString(), | ||||||
|  |                 QString::fromStdString(fmt::format("0x{:016X}", data(ProgramIdRole).toULongLong())), | ||||||
|  |                 data(TitleRole).toString(), | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             auto row1 = row_data.at(UISettings::values.row_1_text_id); | ||||||
|  |             auto row2 = row_data.at(UISettings::values.row_2_text_id); | ||||||
|  | 
 | ||||||
|  |             if (row1.isEmpty() || row1 == row2) | ||||||
|  |                 return row2; | ||||||
|  |             if (row2.isEmpty()) | ||||||
|  |                 return row1; | ||||||
|  | 
 | ||||||
|  |             return row1 + "\n    " + row2; | ||||||
|         } else { |         } else { | ||||||
|             return GameListItem::data(role); |             return GameListItem::data(role); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -764,6 +764,7 @@ void GMainWindow::OnConfigure() { | ||||||
|         configureDialog.applyConfiguration(); |         configureDialog.applyConfiguration(); | ||||||
|         if (UISettings::values.theme != old_theme) |         if (UISettings::values.theme != old_theme) | ||||||
|             UpdateUITheme(); |             UpdateUITheme(); | ||||||
|  |         game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan); | ||||||
|         config->Save(); |         config->Save(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -54,6 +54,12 @@ struct Values { | ||||||
| 
 | 
 | ||||||
|     // logging
 |     // logging
 | ||||||
|     bool show_console; |     bool show_console; | ||||||
|  | 
 | ||||||
|  |     // Game List
 | ||||||
|  |     bool show_unknown; | ||||||
|  |     uint32_t icon_size; | ||||||
|  |     uint8_t row_1_text_id; | ||||||
|  |     uint8_t row_2_text_id; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| extern Values values; | extern Values values; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Zach Hilman
						Zach Hilman