From 8fc9c0312660aa8b74a1251f02dfedc84da5b96b Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Tue, 17 May 2016 23:06:33 +0100 Subject: Loader, Frontends: Refactor loader creation and game loading This allows frontends to keep a single loader and use it multiple times e.g. for code loading and SMDH parsing. --- src/core/loader/3dsx.cpp | 3 +++ src/core/loader/loader.cpp | 50 +++++++--------------------------------------- src/core/loader/loader.h | 6 +++--- src/core/loader/ncch.cpp | 9 ++++++++- 4 files changed, 21 insertions(+), 47 deletions(-) (limited to 'src/core') diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp index 98e7ab48f..a16411e14 100644 --- a/src/core/loader/3dsx.cpp +++ b/src/core/loader/3dsx.cpp @@ -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(*this), Service::FS::ArchiveIdCode::RomFS); + is_loaded = true; return ResultStatus::Success; } diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index af3f62248..c82688026 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -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; } @@ -108,15 +109,15 @@ std::unique_ptr GetLoader(FileUtil::IOFile&& file, FileType type, return std::make_unique(std::move(file), filepath); default: - return std::unique_ptr(); + return nullptr; } } -ResultStatus LoadFile(const std::string& filename) { +std::unique_ptr GetFileLoader(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 +134,7 @@ ResultStatus LoadFile(const std::string& filename) { LOG_INFO(Loader, "Loading file %s as %s...", filename.c_str(), GetFileTypeString(type)); - std::unique_ptr 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(*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 GetLoader(std::move(file), type, filename_filename, filename); } } // namespace Loader diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 9d3e9ed3b..4a4bd7c77 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -207,10 +207,10 @@ extern const std::initializer_list default_address_mappi std::unique_ptr 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 GetFileLoader(const std::string& filename); } // namespace diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index 7391bdb26..fca091ff9 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp @@ -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(*this), Service::FS::ArchiveIdCode::RomFS); + return ResultStatus::Success; } ResultStatus AppLoader_NCCH::ReadCode(std::vector& buffer) { -- cgit v1.2.3 From 9a35d1fb4ac1c1e37d02bb3826c2c0bfd2a1554f Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Tue, 17 May 2016 23:30:44 +0100 Subject: Loader: Add a GetFileType method to get the type of a loaded file --- src/core/loader/3dsx.h | 8 ++++++++ src/core/loader/elf.h | 8 ++++++++ src/core/loader/loader.h | 6 ++++++ src/core/loader/ncch.h | 8 ++++++++ 4 files changed, 30 insertions(+) (limited to 'src/core') diff --git a/src/core/loader/3dsx.h b/src/core/loader/3dsx.h index 3ee686703..90b20c61c 100644 --- a/src/core/loader/3dsx.h +++ b/src/core/loader/3dsx.h @@ -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 diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h index c6a5ebe99..cb3724f9d 100644 --- a/src/core/loader/elf.h +++ b/src/core/loader/elf.h @@ -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 diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 4a4bd7c77..08bab84e5 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -131,6 +131,12 @@ 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 diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h index fd852c3de..75609ee57 100644 --- a/src/core/loader/ncch.h +++ b/src/core/loader/ncch.h @@ -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 -- cgit v1.2.3 From 314ce5e505aca066ad4d0385be46d7e8de9f6dfb Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Wed, 18 May 2016 22:06:50 +0100 Subject: CitraQt: Simplify the game list loader code --- src/core/loader/loader.cpp | 14 +++++++++++--- src/core/loader/loader.h | 12 +----------- 2 files changed, 12 insertions(+), 14 deletions(-) (limited to 'src/core') diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index c82688026..9719d30d5 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -91,7 +91,15 @@ const char* GetFileTypeString(FileType type) { return "unknown"; } -std::unique_ptr 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 a pointer to a loader object; nullptr for unsupported type + */ +static std::unique_ptr GetFileLoader(FileUtil::IOFile&& file, FileType type, const std::string& filename, const std::string& filepath) { switch (type) { @@ -113,7 +121,7 @@ std::unique_ptr GetLoader(FileUtil::IOFile&& file, FileType type, } } -std::unique_ptr GetFileLoader(const std::string& filename) { +std::unique_ptr GetLoader(const std::string& filename) { FileUtil::IOFile file(filename, "rb"); if (!file.IsOpen()) { LOG_ERROR(Loader, "Failed to load file %s", filename.c_str()); @@ -134,7 +142,7 @@ std::unique_ptr GetFileLoader(const std::string& filename) { LOG_INFO(Loader, "Loading file %s as %s...", filename.c_str(), GetFileTypeString(type)); - return GetLoader(std::move(file), type, filename_filename, filename); + return GetFileLoader(std::move(file), type, filename_filename, filename); } } // namespace Loader diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 08bab84e5..39aedfeeb 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -202,21 +202,11 @@ protected: */ extern const std::initializer_list 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 a pointer to a loader object; nullptr for unsupported type - */ -std::unique_ptr GetLoader(FileUtil::IOFile&& file, FileType type, const std::string& filename, const std::string& filepath); - /** * Identifies a bootable file and return a suitable loader * @param filename String filename of bootable file * @return best loader for this file */ -std::unique_ptr GetFileLoader(const std::string& filename); +std::unique_ptr GetLoader(const std::string& filename); } // namespace -- cgit v1.2.3 From 080a2d719ca825961ec2db5f26ad22e43d456c5a Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Wed, 18 May 2016 00:42:45 +0100 Subject: Loader: Split SMDH into its own header and import helpers from QGameList Also rewrite Qt wrappers to use those. --- src/core/CMakeLists.txt | 2 ++ src/core/loader/loader.h | 47 --------------------------- src/core/loader/smdh.cpp | 54 +++++++++++++++++++++++++++++++ src/core/loader/smdh.h | 82 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 138 insertions(+), 47 deletions(-) create mode 100644 src/core/loader/smdh.cpp create mode 100644 src/core/loader/smdh.h (limited to 'src/core') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 12080a802..ed80cf0e4 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -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 diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 39aedfeeb..77d87afe1 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -10,10 +10,8 @@ #include #include -#include "common/common_funcs.h" #include "common/common_types.h" #include "common/file_util.h" -#include "common/swap.h" namespace Kernel { struct AddressMapping; @@ -80,51 +78,6 @@ 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 short_title; - std::array long_title; - std::array publisher; - }; - std::array titles; - - std::array 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 small_icon; - std::array 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: diff --git a/src/core/loader/smdh.cpp b/src/core/loader/smdh.cpp new file mode 100644 index 000000000..2d014054a --- /dev/null +++ b/src/core/loader/smdh.cpp @@ -0,0 +1,54 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include + +#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& 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 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 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 SMDH::GetShortTitle(Loader::SMDH::TitleLanguage language) const { + return titles[static_cast(language)].short_title; +} + +} // namespace diff --git a/src/core/loader/smdh.h b/src/core/loader/smdh.h new file mode 100644 index 000000000..2011abda2 --- /dev/null +++ b/src/core/loader/smdh.h @@ -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 +#include + +#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& 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 short_title; + std::array long_title; + std::array publisher; + }; + std::array titles; + + std::array 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 small_icon; + std::array 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 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 GetShortTitle(Loader::SMDH::TitleLanguage language) const; +}; +static_assert(sizeof(SMDH) == 0x36C0, "SMDH structure size is wrong"); + +} // namespace -- cgit v1.2.3