diff options
Diffstat (limited to 'src/core')
28 files changed, 171 insertions, 150 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 0abf7edc1..cceb1564b 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -104,8 +104,6 @@ add_library(core STATIC hle/lock.cpp hle/lock.h hle/result.h - hle/romfs.cpp - hle/romfs.h hle/service/acc/acc.cpp hle/service/acc/acc.h hle/service/acc/acc_aa.cpp diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp index 395eea8ae..e897d9913 100644 --- a/src/core/file_sys/card_image.cpp +++ b/src/core/file_sys/card_image.cpp @@ -5,6 +5,7 @@ #include <array> #include <string> #include <core/loader/loader.h> +#include "common/logging/log.h" #include "core/file_sys/card_image.h" #include "core/file_sys/partition_filesystem.h" #include "core/file_sys/vfs_offset.h" diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index 3529166ac..d3007d981 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp @@ -170,6 +170,10 @@ VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting } NCA::NCA(VirtualFile file_) : file(std::move(file_)) { + if (file == nullptr) { + status = Loader::ResultStatus::ErrorInvalidFormat; + return; + } if (sizeof(NCAHeader) != file->ReadObject(&header)) LOG_ERROR(Loader, "File reader errored out during header read."); diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h index a8879d9a8..5cfd5031a 100644 --- a/src/core/file_sys/content_archive.h +++ b/src/core/file_sys/content_archive.h @@ -12,6 +12,7 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "common/swap.h" +#include "control_metadata.h" #include "core/crypto/key_manager.h" #include "core/file_sys/partition_filesystem.h" #include "core/loader/loader.h" diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index cc3b745f7..6582cc240 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h @@ -62,6 +62,13 @@ enum class Language : u8 { Chinese = 14, }; +static constexpr std::array<const char*, 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. // These store application name, dev name, title id, and other miscellaneous data. class NACP { diff --git a/src/core/hle/romfs.cpp b/src/core/hle/romfs.cpp deleted file mode 100644 index 3157df71d..000000000 --- a/src/core/hle/romfs.cpp +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <cstring> -#include "common/swap.h" -#include "core/hle/romfs.h" - -namespace RomFS { - -struct Header { - u32_le header_length; - u32_le dir_hash_table_offset; - u32_le dir_hash_table_length; - u32_le dir_table_offset; - u32_le dir_table_length; - u32_le file_hash_table_offset; - u32_le file_hash_table_length; - u32_le file_table_offset; - u32_le file_table_length; - u32_le data_offset; -}; - -static_assert(sizeof(Header) == 0x28, "Header has incorrect size"); - -struct DirectoryMetadata { - u32_le parent_dir_offset; - u32_le next_dir_offset; - u32_le first_child_dir_offset; - u32_le first_file_offset; - u32_le same_hash_next_dir_offset; - u32_le name_length; // in bytes - // followed by directory name -}; - -static_assert(sizeof(DirectoryMetadata) == 0x18, "DirectoryMetadata has incorrect size"); - -struct FileMetadata { - u32_le parent_dir_offset; - u32_le next_file_offset; - u64_le data_offset; - u64_le data_length; - u32_le same_hash_next_file_offset; - u32_le name_length; // in bytes - // followed by file name -}; - -static_assert(sizeof(FileMetadata) == 0x20, "FileMetadata has incorrect size"); - -static bool MatchName(const u8* buffer, u32 name_length, const std::u16string& name) { - std::vector<char16_t> name_buffer(name_length / sizeof(char16_t)); - std::memcpy(name_buffer.data(), buffer, name_length); - return name == std::u16string(name_buffer.begin(), name_buffer.end()); -} - -const u8* GetFilePointer(const u8* romfs, const std::vector<std::u16string>& path) { - constexpr u32 INVALID_FIELD = 0xFFFFFFFF; - - // Split path into directory names and file name - std::vector<std::u16string> dir_names = path; - dir_names.pop_back(); - const std::u16string& file_name = path.back(); - - Header header; - std::memcpy(&header, romfs, sizeof(header)); - - // Find directories of each level - DirectoryMetadata dir; - const u8* current_dir = romfs + header.dir_table_offset; - std::memcpy(&dir, current_dir, sizeof(dir)); - for (const std::u16string& dir_name : dir_names) { - u32 child_dir_offset; - child_dir_offset = dir.first_child_dir_offset; - while (true) { - if (child_dir_offset == INVALID_FIELD) { - return nullptr; - } - const u8* current_child_dir = romfs + header.dir_table_offset + child_dir_offset; - std::memcpy(&dir, current_child_dir, sizeof(dir)); - if (MatchName(current_child_dir + sizeof(dir), dir.name_length, dir_name)) { - current_dir = current_child_dir; - break; - } - child_dir_offset = dir.next_dir_offset; - } - } - - // Find the file - FileMetadata file; - u32 file_offset = dir.first_file_offset; - while (file_offset != INVALID_FIELD) { - const u8* current_file = romfs + header.file_table_offset + file_offset; - std::memcpy(&file, current_file, sizeof(file)); - if (MatchName(current_file + sizeof(file), file.name_length, file_name)) { - return romfs + header.data_offset + file.data_offset; - } - file_offset = file.next_file_offset; - } - return nullptr; -} - -} // namespace RomFS diff --git a/src/core/hle/romfs.h b/src/core/hle/romfs.h deleted file mode 100644 index ee9f29760..000000000 --- a/src/core/hle/romfs.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <string> -#include <vector> -#include "common/common_types.h" - -namespace RomFS { - -/** - * Gets the pointer to a file in a RomFS image. - * @param romfs The pointer to the RomFS image - * @param path A vector containing the directory names and file name of the path to the file - * @return the pointer to the file - * @todo reimplement this with a full RomFS manager - */ -const u8* GetFilePointer(const u8* romfs, const std::vector<std::u16string>& path); - -} // namespace RomFS diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 6d15b46ed..e952b0518 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -119,6 +119,13 @@ private: } }; +void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_ACC, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(1); +} + void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_ACC, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 3}; diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h index 0a01d954c..88cabaa01 100644 --- a/src/core/hle/service/acc/acc.h +++ b/src/core/hle/service/acc/acc.h @@ -14,6 +14,7 @@ public: public: explicit Interface(std::shared_ptr<Module> module, const char* name); + void GetUserCount(Kernel::HLERequestContext& ctx); void GetUserExistence(Kernel::HLERequestContext& ctx); void ListAllUsers(Kernel::HLERequestContext& ctx); void ListOpenUsers(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp index 9ffb40b22..8b2a71f37 100644 --- a/src/core/hle/service/acc/acc_su.cpp +++ b/src/core/hle/service/acc/acc_su.cpp @@ -8,7 +8,7 @@ namespace Service::Account { ACC_SU::ACC_SU(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "acc:su") { static const FunctionInfo functions[] = { - {0, nullptr, "GetUserCount"}, + {0, &ACC_SU::GetUserCount, "GetUserCount"}, {1, &ACC_SU::GetUserExistence, "GetUserExistence"}, {2, &ACC_SU::ListAllUsers, "ListAllUsers"}, {3, &ACC_SU::ListOpenUsers, "ListOpenUsers"}, diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp index 44e21ac09..d84c8b2e1 100644 --- a/src/core/hle/service/acc/acc_u0.cpp +++ b/src/core/hle/service/acc/acc_u0.cpp @@ -8,7 +8,7 @@ namespace Service::Account { ACC_U0::ACC_U0(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "acc:u0") { static const FunctionInfo functions[] = { - {0, nullptr, "GetUserCount"}, + {0, &ACC_U0::GetUserCount, "GetUserCount"}, {1, &ACC_U0::GetUserExistence, "GetUserExistence"}, {2, &ACC_U0::ListAllUsers, "ListAllUsers"}, {3, &ACC_U0::ListOpenUsers, "ListOpenUsers"}, diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp index d101d4e0d..0ceaf06b5 100644 --- a/src/core/hle/service/acc/acc_u1.cpp +++ b/src/core/hle/service/acc/acc_u1.cpp @@ -8,7 +8,7 @@ namespace Service::Account { ACC_U1::ACC_U1(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "acc:u1") { static const FunctionInfo functions[] = { - {0, nullptr, "GetUserCount"}, + {0, &ACC_U1::GetUserCount, "GetUserCount"}, {1, &ACC_U1::GetUserExistence, "GetUserExistence"}, {2, &ACC_U1::ListAllUsers, "ListAllUsers"}, {3, &ACC_U1::ListOpenUsers, "ListOpenUsers"}, diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 9404d6b8c..762763463 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -136,7 +136,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger {16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"}, {17, nullptr, "SetControllerFirmwareUpdateSection"}, {18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"}, - {19, nullptr, "SetScreenShotImageOrientation"}, + {19, &ISelfController::SetScreenShotImageOrientation, "SetScreenShotImageOrientation"}, {20, nullptr, "SetDesirableKeyboardLayout"}, {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"}, {41, nullptr, "IsSystemBufferSharingEnabled"}, @@ -254,6 +254,13 @@ void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& LOG_WARNING(Service_AM, "(STUBBED) called"); } +void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + + LOG_WARNING(Service_AM, "(STUBBED) called"); +} + void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) { // TODO(Subv): Find out how AM determines the display to use, for now just create the layer // in the Default display. diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 8f4f98346..862f338ac 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -83,6 +83,7 @@ private: void LockExit(Kernel::HLERequestContext& ctx); void UnlockExit(Kernel::HLERequestContext& ctx); void GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx); + void SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx); void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx); void SetScreenShotPermission(Kernel::HLERequestContext& ctx); void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 8f0262e34..dcdfa0e19 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -457,7 +457,7 @@ private: } void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 2}; + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); // TODO (Hexagon12): Properly implement reading gyroscope values from controllers. rb.Push(true); diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index e8b30921a..427f4b574 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -16,19 +16,18 @@ #include "core/hle/service/nvdrv/interface.h" #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvdrv/nvmemp.h" +#include "core/hle/service/nvflinger/nvflinger.h" namespace Service::Nvidia { -std::weak_ptr<Module> nvdrv; - -void InstallInterfaces(SM::ServiceManager& service_manager) { +void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger) { auto module_ = std::make_shared<Module>(); std::make_shared<NVDRV>(module_, "nvdrv")->InstallAsService(service_manager); std::make_shared<NVDRV>(module_, "nvdrv:a")->InstallAsService(service_manager); std::make_shared<NVDRV>(module_, "nvdrv:s")->InstallAsService(service_manager); std::make_shared<NVDRV>(module_, "nvdrv:t")->InstallAsService(service_manager); std::make_shared<NVMEMP>()->InstallAsService(service_manager); - nvdrv = module_; + nvflinger.SetNVDrvInstance(module_); } Module::Module() { diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 184f3c9fc..99eb1128a 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -10,6 +10,10 @@ #include "common/common_types.h" #include "core/hle/service/service.h" +namespace Service::NVFlinger { +class NVFlinger; +} + namespace Service::Nvidia { namespace Devices { @@ -56,8 +60,6 @@ private: }; /// Registers all NVDRV services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager); - -extern std::weak_ptr<Module> nvdrv; +void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger); } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 570aa8493..a26a5f812 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -46,6 +46,10 @@ NVFlinger::~NVFlinger() { CoreTiming::UnscheduleEvent(composition_event, 0); } +void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { + nvdrv = std::move(instance); +} + u64 NVFlinger::OpenDisplay(std::string_view name) { LOG_WARNING(Service, "Opening display {}", name); @@ -141,9 +145,6 @@ void NVFlinger::Compose() { auto& igbp_buffer = buffer->igbp_buffer; // Now send the buffer to the GPU for drawing. - auto nvdrv = Nvidia::nvdrv.lock(); - ASSERT(nvdrv); - // TODO(Subv): Support more than just disp0. The display device selection is probably based // on which display we're drawing (Default, Internal, External, etc) auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0"); diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 5374df175..f7112949f 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -16,6 +16,10 @@ namespace CoreTiming { struct EventType; } +namespace Service::Nvidia { +class Module; +} + namespace Service::NVFlinger { class BufferQueue; @@ -44,6 +48,9 @@ public: NVFlinger(); ~NVFlinger(); + /// Sets the NVDrv module instance to use to send buffers to the GPU. + void SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance); + /// Opens the specified display and returns the id. u64 OpenDisplay(std::string_view name); @@ -70,6 +77,8 @@ private: /// Returns the layer identified by the specified id in the desired display. Layer& GetLayer(u64 display_id, u64 layer_id); + std::shared_ptr<Nvidia::Module> nvdrv; + std::vector<Display> displays; std::vector<std::shared_ptr<BufferQueue>> buffer_queues; diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 889cdd41a..6f286ea74 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -238,7 +238,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm) { NIFM::InstallInterfaces(*sm); NIM::InstallInterfaces(*sm); NS::InstallInterfaces(*sm); - Nvidia::InstallInterfaces(*sm); + Nvidia::InstallInterfaces(*sm, *nv_flinger); PCIe::InstallInterfaces(*sm); PCTL::InstallInterfaces(*sm); PCV::InstallInterfaces(*sm); diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 9a8cdd0ff..915d525b0 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -7,6 +7,7 @@ #include "common/file_util.h" #include "common/logging/log.h" #include "core/file_sys/content_archive.h" +#include "core/file_sys/control_metadata.h" #include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" @@ -17,8 +18,50 @@ namespace Loader { -AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file) - : AppLoader(std::move(file)) {} +AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile 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_" + std::string(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( FileSys::VirtualDir directory) @@ -105,4 +148,25 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile 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 diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h index 7d5433563..b20804f75 100644 --- a/src/core/loader/deconstructed_rom_directory.h +++ b/src/core/loader/deconstructed_rom_directory.h @@ -39,11 +39,18 @@ public: ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) 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: FileSys::ProgramMetadata metadata; FileSys::VirtualFile romfs; FileSys::VirtualDir dir; + + std::vector<u8> icon_data; + std::string name; + u64 title_id{}; }; } // namespace Loader diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 57e6c0365..0781fb8c1 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -68,7 +68,7 @@ FileType GuessFromFilename(const std::string& name) { return FileType::Unknown; } -const char* GetFileTypeString(FileType type) { +std::string GetFileTypeString(FileType type) { switch (type) { case FileType::ELF: return "ELF"; diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index e69ab85ef..7bd0adedb 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -61,7 +61,7 @@ FileType GuessFromFilename(const std::string& name); /** * 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 enum class ResultStatus { diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index dbc67c0b5..46f5cd393 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp @@ -77,8 +77,8 @@ ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) { } ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) { - if (nca == nullptr) - return ResultStatus::ErrorNotLoaded; + if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) + return ResultStatus::ErrorInvalidFormat; out_program_id = nca->GetTitleId(); return ResultStatus::Success; } diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h index 0fd2d0417..7f7d8ea0b 100644 --- a/src/core/loader/nca.h +++ b/src/core/loader/nca.h @@ -33,7 +33,6 @@ public: ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; - ResultStatus ReadProgramId(u64& out_program_id) override; ~AppLoader_NCA(); @@ -41,6 +40,7 @@ public: private: FileSys::ProgramMetadata metadata; + FileSys::NCAHeader header; std::unique_ptr<FileSys::NCA> nca; std::unique_ptr<AppLoader_DeconstructedRomDirectory> directory_loader; }; diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index eb4dee2c2..d3fe24419 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp @@ -26,7 +26,25 @@ namespace Loader { AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file) : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)), nca_loader(std::make_unique<AppLoader_NCA>( - xci->GetNCAFileByType(FileSys::NCAContentType::Program))) {} + xci->GetNCAFileByType(FileSys::NCAContentType::Program))) { + if (xci->GetStatus() != ResultStatus::Success) + return; + const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control); + if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) + return; + const auto romfs = FileSys::ExtractRomFS(control_nca->GetRomFS()); + if (romfs == nullptr) + return; + for (const auto& language : FileSys::LANGUAGE_NAMES) { + icon_file = romfs->GetFile("icon_" + std::string(language) + ".dat"); + if (icon_file != nullptr) + break; + } + const auto nacp_raw = romfs->GetFile("control.nacp"); + if (nacp_raw == nullptr) + return; + nacp_file = std::make_shared<FileSys::NACP>(nacp_raw); +} AppLoader_XCI::~AppLoader_XCI() = default; @@ -71,4 +89,17 @@ ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) { return nca_loader->ReadProgramId(out_program_id); } +ResultStatus AppLoader_XCI::ReadIcon(std::vector<u8>& buffer) { + if (icon_file == nullptr) + return ResultStatus::ErrorInvalidFormat; + buffer = icon_file->ReadAllBytes(); + return ResultStatus::Success; +} + +ResultStatus AppLoader_XCI::ReadTitle(std::string& title) { + if (nacp_file == nullptr) + return ResultStatus::ErrorInvalidFormat; + title = nacp_file->GetApplicationName(); + return ResultStatus::Success; +} } // namespace Loader diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h index 0dbcfbdf8..973833050 100644 --- a/src/core/loader/xci.h +++ b/src/core/loader/xci.h @@ -33,12 +33,17 @@ public: ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; ResultStatus ReadProgramId(u64& out_program_id) override; + ResultStatus ReadIcon(std::vector<u8>& buffer) override; + ResultStatus ReadTitle(std::string& title) override; private: FileSys::ProgramMetadata metadata; std::unique_ptr<FileSys::XCI> xci; std::unique_ptr<AppLoader_NCA> nca_loader; + + FileSys::VirtualFile icon_file; + std::shared_ptr<FileSys::NACP> nacp_file; }; } // namespace Loader |