diff --git a/Makefile b/Makefile index 7c80329..c6916a9 100644 --- a/Makefile +++ b/Makefile @@ -68,10 +68,10 @@ BUILD_TIMESTAMP := $(strip $(shell date --utc '+%Y-%m-%d %T UTC')) TARGET := ${APP_TITLE} BUILD := build -SOURCES := source source/core source/fatfs source/devoptab +SOURCES := source source/core source/core/fatfs source/core/devoptab source/tasks source/utils source/views DATA := data ICON := romfs/icon/${APP_TITLE}.jpg -INCLUDES := include include/core include/fatfs include/devoptab +INCLUDES := include ROMFS := romfs BOREALIS_PATH := libs/borealis diff --git a/code_templates/nxdt_rw_poc.c b/code_templates/nxdt_rw_poc.c index e4ed89b..c07aaea 100644 --- a/code_templates/nxdt_rw_poc.c +++ b/code_templates/nxdt_rw_poc.c @@ -19,16 +19,16 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "gamecard.h" -#include "title.h" -#include "cnmt.h" -#include "program_info.h" -#include "nacp.h" -#include "legal_info.h" -#include "cert.h" -#include "usb.h" -#include "nxdt_devoptab.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #define BLOCK_SIZE USB_TRANSFER_BUFFER_SIZE #define WAIT_TIME_LIMIT 30 diff --git a/include/devoptab/nxdt_devoptab.h b/include/core/devoptab/nxdt_devoptab.h similarity index 98% rename from include/devoptab/nxdt_devoptab.h rename to include/core/devoptab/nxdt_devoptab.h index 2790ea1..99120a9 100644 --- a/include/devoptab/nxdt_devoptab.h +++ b/include/core/devoptab/nxdt_devoptab.h @@ -24,9 +24,9 @@ #ifndef __NXDT_DEVOPTAB_H__ #define __NXDT_DEVOPTAB_H__ -#include "pfs.h" -#include "hfs.h" -#include "romfs.h" +#include "../pfs.h" +#include "../hfs.h" +#include "../romfs.h" #ifdef __cplusplus extern "C" { diff --git a/include/devoptab/ro_dev.h b/include/core/devoptab/ro_dev.h similarity index 100% rename from include/devoptab/ro_dev.h rename to include/core/devoptab/ro_dev.h diff --git a/include/fatfs/diskio.h b/include/core/fatfs/diskio.h similarity index 100% rename from include/fatfs/diskio.h rename to include/core/fatfs/diskio.h diff --git a/include/fatfs/ff.h b/include/core/fatfs/ff.h similarity index 100% rename from include/fatfs/ff.h rename to include/core/fatfs/ff.h diff --git a/include/fatfs/ffconf.h b/include/core/fatfs/ffconf.h similarity index 100% rename from include/fatfs/ffconf.h rename to include/core/fatfs/ffconf.h diff --git a/include/core/hos_version_structs.h b/include/core/hos_version_structs.h new file mode 100644 index 0000000..ee19b5c --- /dev/null +++ b/include/core/hos_version_structs.h @@ -0,0 +1,99 @@ +/* + * hos_version_structs.h + * + * Copyright (c) 2020-2024, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nxdumptool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#ifndef __HOS_VERSION_STRUCTS_H__ +#define __HOS_VERSION_STRUCTS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/// Used to store version numbers expressed in dot notation: "{major}.{minor}.{micro}-{major_relstep}.{minor_relstep}". +/// Used by system version fields. 16-bit long relstep values were used by system version fields prior to HOS 3.0.0. +typedef struct { + union { + u32 value; + struct { + union { + u16 relstep; + struct { + u16 minor_relstep : 8; + u16 major_relstep : 8; + }; + }; + u16 micro : 4; + u16 minor : 6; + u16 major : 6; + }; + }; +} SystemVersion; + +NXDT_ASSERT(SystemVersion, 0x4); + +/// Used to store version numbers expressed in dot notation: "{release}.{private}". +/// Used by application version fields. +typedef struct { + union { + u32 value; + struct { + u32 private_ver : 16; + u32 release_ver : 16; + }; + }; +} ApplicationVersion; + +NXDT_ASSERT(ApplicationVersion, 0x4); + +/// Used to store version numbers expressed in dot notation: "{major}.{minor}.{micro}-{relstep}". +/// Used by SDK version fields. +typedef struct { + union { + u32 value; + struct { + u32 relstep : 8; + u32 micro : 8; + u32 minor : 8; + u32 major : 8; + }; + }; +} SdkAddOnVersion; + +NXDT_ASSERT(SdkAddOnVersion, 0x4); + +/// Convenient wrapper for all version structs. +typedef struct { + union { + u32 value; + SystemVersion system_version; + ApplicationVersion application_version; + SdkAddOnVersion sdk_addon_version; + }; +} Version; + +NXDT_ASSERT(Version, 0x4); + +#ifdef __cplusplus +} +#endif + +#endif /* __HOS_VERSION_STRUCTS_H__ */ diff --git a/include/core/nxdt_includes.h b/include/core/nxdt_includes.h index 49fb21f..b5b0b9c 100644 --- a/include/core/nxdt_includes.h +++ b/include/core/nxdt_includes.h @@ -78,68 +78,7 @@ #define LZ4_STATIC_LINKING_ONLY /* Required by LZ4 to enable in-place decompression. */ #include "lz4.h" -/// Used to store version numbers expressed in dot notation: "{major}.{minor}.{micro}-{major_relstep}.{minor_relstep}". -/// Used by system version fields. 16-bit long relstep values were used by system version fields prior to HOS 3.0.0. -typedef struct { - union { - u32 value; - struct { - union { - u16 relstep; - struct { - u16 minor_relstep : 8; - u16 major_relstep : 8; - }; - }; - u16 micro : 4; - u16 minor : 6; - u16 major : 6; - }; - }; -} SystemVersion; - -NXDT_ASSERT(SystemVersion, 0x4); - -/// Used to store version numbers expressed in dot notation: "{release}.{private}". -/// Used by application version fields. -typedef struct { - union { - u32 value; - struct { - u32 private_ver : 16; - u32 release_ver : 16; - }; - }; -} ApplicationVersion; - -NXDT_ASSERT(ApplicationVersion, 0x4); - -/// Used to store version numbers expressed in dot notation: "{major}.{minor}.{micro}-{relstep}". -/// Used by SDK version fields. -typedef struct { - union { - u32 value; - struct { - u32 relstep : 8; - u32 micro : 8; - u32 minor : 8; - u32 major : 8; - }; - }; -} SdkAddOnVersion; - -NXDT_ASSERT(SdkAddOnVersion, 0x4); - -/// Convenient wrapper for all version structs. -typedef struct { - union { - u32 value; - SystemVersion system_version; - ApplicationVersion application_version; - SdkAddOnVersion sdk_addon_version; - }; -} Version; - -NXDT_ASSERT(Version, 0x4); +/* Horizon OS version structs. */ +#include "hos_version_structs.h" #endif /* __NXDT_INCLUDES_H__ */ diff --git a/include/core/title.h b/include/core/title.h index 4efe63d..4faccc2 100644 --- a/include/core/title.h +++ b/include/core/title.h @@ -51,6 +51,7 @@ typedef struct { TitleApplicationMetadata *app_metadata; ///< User application metadata. Version version; ///< Reflects the title version stored in the inserted gamecard. char display_version[32]; ///< Reflects the title display version stored in its NACP. + u32 dlc_count; ///< Reflects the number of DLCs available for this application in the inserted gamecard. } TitleGameCardApplicationMetadataEntry; /// Generated using ncm calls. diff --git a/include/defines.h b/include/defines.h index 6301dba..eba6ab1 100644 --- a/include/defines.h +++ b/include/defines.h @@ -111,6 +111,7 @@ #define FS_MAX_FILENAME_LENGTH 255 #define SDMC_MAX_FILENAME_LENGTH 128 /* Arbitrarily set, I'm tired of FS sysmodule shenanigans. */ +#define REPEATING_TASK_INTERVAL 250 /* 250 milliseconds. */ #define DATA_TRANSFER_TASK_INTERVAL 100 /* 100 milliseconds. */ #define HTTP_USER_AGENT APP_TITLE "/" APP_VERSION " (Nintendo Switch)" diff --git a/include/tasks.hpp b/include/tasks.hpp deleted file mode 100644 index 5ca0b99..0000000 --- a/include/tasks.hpp +++ /dev/null @@ -1,182 +0,0 @@ -/* - * tasks.hpp - * - * Copyright (c) 2020-2024, DarkMatterCore . - * - * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). - * - * nxdumptool is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * nxdumptool is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#ifndef __TASKS_HPP__ -#define __TASKS_HPP__ - -#include - -#include "core/nxdt_includes.h" -#include "core/gamecard.h" -#include "core/title.h" -#include "core/ums.h" -#include "core/usb.h" -#include "download_task.hpp" - -#define EVENT_SUBSCRIPTION(event_type, event_name) \ - ALWAYS_INLINE event_type::Subscription RegisterListener(event_type::Callback cb) { return this->event_name.subscribe(cb); } \ - ALWAYS_INLINE void UnregisterListener(event_type::Subscription subscription) { this->event_name.unsubscribe(subscription); } - -namespace nxdt::tasks -{ - /* Used to hold status info data. */ - typedef struct { - struct tm timeinfo; - u32 charge_percentage; - PsmChargerType charger_type; - bool connected; - NifmInternetConnectionType connection_type; - char ip_addr[16]; - } StatusInfoData; - - /* Used to hold pointers to application metadata entries. */ - typedef std::vector TitleApplicationMetadataVector; - - /* Used to hold information from UMS devices. */ - typedef std::pair UmsDeviceVectorEntry; - typedef std::vector UmsDeviceVector; - - /* Custom event types. */ - typedef brls::Event StatusInfoEvent; - typedef brls::Event GameCardStatusEvent; - typedef brls::Event UserTitleEvent; - typedef brls::Event UmsEvent; - typedef brls::Event UsbHostEvent; - - /* Status info task. */ - /* Its event returns a reference to a StatusInfoData struct. */ - class StatusInfoTask: public brls::RepeatingTask - { - private: - StatusInfoEvent status_info_event; - StatusInfoData status_info_data{}; - - protected: - void run(retro_time_t current_time) override; - - public: - StatusInfoTask(); - ~StatusInfoTask(); - - bool IsInternetConnectionAvailable(void); - - EVENT_SUBSCRIPTION(StatusInfoEvent, status_info_event); - }; - - /* Gamecard task. */ - /* Its event returns a GameCardStatus value. */ - class GameCardTask: public brls::RepeatingTask - { - private: - GameCardStatusEvent gc_status_event; - GameCardStatus cur_gc_status = GameCardStatus_NotInserted; - GameCardStatus prev_gc_status = GameCardStatus_NotInserted; - bool first_notification = true; - - protected: - void run(retro_time_t current_time) override; - - public: - GameCardTask(); - ~GameCardTask(); - - EVENT_SUBSCRIPTION(GameCardStatusEvent, gc_status_event); - }; - - /* Title task. */ - /* Its event returns a reference to a TitleApplicationMetadataVector with metadata for user titles (system titles don't change at runtime). */ - class TitleTask: public brls::RepeatingTask - { - private: - UserTitleEvent user_title_event; - - TitleApplicationMetadataVector system_metadata{}; - TitleApplicationMetadataVector user_metadata{}; - - void PopulateApplicationMetadataVector(bool is_system); - - protected: - void run(retro_time_t current_time) override; - - public: - TitleTask(); - ~TitleTask(); - - /* Intentionally left here to let views retrieve title metadata on-demand. */ - const TitleApplicationMetadataVector& GetApplicationMetadata(bool is_system); - - EVENT_SUBSCRIPTION(UserTitleEvent, user_title_event); - }; - - /* USB Mass Storage task. */ - /* Its event returns a reference to a UmsDeviceVector. */ - class UmsTask: public brls::RepeatingTask - { - private: - UmsEvent ums_event; - - UsbHsFsDevice *ums_devices = nullptr; - u32 ums_devices_count = 0; - - UmsDeviceVector ums_devices_vector{}; - - void PopulateUmsDeviceVector(void); - - protected: - void run(retro_time_t current_time) override; - - public: - UmsTask(); - ~UmsTask(); - - /* Intentionally left here to let views retrieve UMS device info on-demand. */ - const UmsDeviceVector& GetUmsDevices(void); - - EVENT_SUBSCRIPTION(UmsEvent, ums_event); - }; - - /* USB host device connection task. */ - class UsbHostTask: public brls::RepeatingTask - { - private: - UsbHostEvent usb_host_event; - UsbHostSpeed cur_usb_host_speed = UsbHostSpeed_None; - UsbHostSpeed prev_usb_host_speed = UsbHostSpeed_None; - - protected: - void run(retro_time_t current_time) override; - - public: - UsbHostTask(); - ~UsbHostTask(); - - /* Intentionally left here to let views retrieve USB host connection speed on-demand. */ - const UsbHostSpeed& GetUsbHostSpeed(void); - - EVENT_SUBSCRIPTION(UsbHostEvent, usb_host_event); - }; -} - -#undef EVENT_SUBSCRIPTION - -#endif /* __TASKS_HPP__ */ diff --git a/include/async_task.hpp b/include/tasks/async_task.hpp similarity index 100% rename from include/async_task.hpp rename to include/tasks/async_task.hpp diff --git a/include/data_transfer_task.hpp b/include/tasks/data_transfer_task.hpp similarity index 99% rename from include/data_transfer_task.hpp rename to include/tasks/data_transfer_task.hpp index 13c0c35..2fe9486 100644 --- a/include/data_transfer_task.hpp +++ b/include/tasks/data_transfer_task.hpp @@ -26,7 +26,7 @@ #include -#include "core/nxdt_utils.h" +#include "../core/nxdt_utils.h" #include "async_task.hpp" namespace nxdt::tasks diff --git a/include/tasks/download_data_task.hpp b/include/tasks/download_data_task.hpp new file mode 100644 index 0000000..7d44566 --- /dev/null +++ b/include/tasks/download_data_task.hpp @@ -0,0 +1,60 @@ +/* + * download_data_task.hpp + * + * Copyright (c) 2020-2024, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nxdumptool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#ifndef __DOWNLOAD_DATA_TASK_HPP__ +#define __DOWNLOAD_DATA_TASK_HPP__ + +#include "download_task.hpp" + +namespace nxdt::tasks +{ + /* Used to hold a buffer + size pair with downloaded data. */ + typedef std::pair DownloadDataResult; + + /* Asynchronous task used to store downloaded data into a dynamically allocated buffer using a URL. */ + /* The buffer returned by std::pair::first() must be manually freed by the caller using free(). */ + class DownloadDataTask: public DownloadTask + { + protected: + /* Set class as non-copyable and non-moveable. */ + NON_COPYABLE(DownloadDataTask); + NON_MOVEABLE(DownloadDataTask); + + /* Runs in the background thread. */ + DownloadDataResult DoInBackground(const std::string& url, const bool& force_https) override final + { + char *buf = nullptr; + size_t buf_size = 0; + + /* If the process fails or if it's cancelled, httpDownloadData() will take care of freeing up the allocated memory and returning NULL. */ + buf = httpDownloadData(&buf_size, url.c_str(), force_https, DownloadDataTask::HttpProgressCallback, this); + + return std::make_pair(buf, buf_size); + } + + public: + DownloadDataTask() = default; + }; +} + +#endif /* __DOWNLOAD_DATA_TASK_HPP__ */ diff --git a/include/tasks/download_file_task.hpp b/include/tasks/download_file_task.hpp new file mode 100644 index 0000000..463ddb9 --- /dev/null +++ b/include/tasks/download_file_task.hpp @@ -0,0 +1,51 @@ +/* + * download_file_task.hpp + * + * Copyright (c) 2020-2024, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nxdumptool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#ifndef __DOWNLOAD_FILE_TASK_HPP__ +#define __DOWNLOAD_FILE_TASK_HPP__ + +#include "download_task.hpp" + +namespace nxdt::tasks +{ + /* Asynchronous task used to download a file using an output path and a URL. */ + class DownloadFileTask: public DownloadTask + { + protected: + /* Set class as non-copyable and non-moveable. */ + NON_COPYABLE(DownloadFileTask); + NON_MOVEABLE(DownloadFileTask); + + /* Runs in the background thread. */ + bool DoInBackground(const std::string& path, const std::string& url, const bool& force_https) override final + { + /* If the process fails or if it's cancelled, httpDownloadFile() will take care of closing the incomplete output file and deleting it. */ + return httpDownloadFile(path.c_str(), url.c_str(), force_https, DownloadFileTask::HttpProgressCallback, this); + } + + public: + DownloadFileTask() = default; + }; +} + +#endif /* __DOWNLOAD_FILE_TASK_HPP__ */ diff --git a/include/download_task.hpp b/include/tasks/download_task.hpp similarity index 55% rename from include/download_task.hpp rename to include/tasks/download_task.hpp index e8e3caa..9446ed0 100644 --- a/include/download_task.hpp +++ b/include/tasks/download_task.hpp @@ -28,9 +28,6 @@ namespace nxdt::tasks { - /* Used to hold a buffer + size pair with downloaded data. */ - typedef std::pair DownloadDataResult; - /* Class template to asynchronously download data on a background thread. */ /* Uses both AsyncTask and DataTransferTask class templates. */ template @@ -68,50 +65,6 @@ namespace nxdt::tasks return 0; } }; - - /* Asynchronous task used to download a file using an output path and a URL. */ - class DownloadFileTask: public DownloadTask - { - protected: - /* Set class as non-copyable and non-moveable. */ - NON_COPYABLE(DownloadFileTask); - NON_MOVEABLE(DownloadFileTask); - - /* Runs in the background thread. */ - bool DoInBackground(const std::string& path, const std::string& url, const bool& force_https) override final - { - /* If the process fails or if it's cancelled, httpDownloadFile() will take care of closing the incomplete output file and deleting it. */ - return httpDownloadFile(path.c_str(), url.c_str(), force_https, DownloadFileTask::HttpProgressCallback, this); - } - - public: - DownloadFileTask() = default; - }; - - /* Asynchronous task used to store downloaded data into a dynamically allocated buffer using a URL. */ - /* The buffer returned by std::pair::first() must be manually freed by the caller using free(). */ - class DownloadDataTask: public DownloadTask - { - protected: - /* Set class as non-copyable and non-moveable. */ - NON_COPYABLE(DownloadDataTask); - NON_MOVEABLE(DownloadDataTask); - - /* Runs in the background thread. */ - DownloadDataResult DoInBackground(const std::string& url, const bool& force_https) override final - { - char *buf = nullptr; - size_t buf_size = 0; - - /* If the process fails or if it's cancelled, httpDownloadData() will take care of freeing up the allocated memory and returning NULL. */ - buf = httpDownloadData(&buf_size, url.c_str(), force_https, DownloadDataTask::HttpProgressCallback, this); - - return std::make_pair(buf, buf_size); - } - - public: - DownloadDataTask() = default; - }; } #endif /* __DOWNLOAD_TASK_HPP__ */ diff --git a/include/gamecard_image_dump_task.hpp b/include/tasks/gamecard_image_dump_task.hpp similarity index 100% rename from include/gamecard_image_dump_task.hpp rename to include/tasks/gamecard_image_dump_task.hpp diff --git a/include/tasks/gamecard_status_task.hpp b/include/tasks/gamecard_status_task.hpp new file mode 100644 index 0000000..c7ee3c5 --- /dev/null +++ b/include/tasks/gamecard_status_task.hpp @@ -0,0 +1,66 @@ +/* + * gamecard_status_task.hpp + * + * Copyright (c) 2020-2024, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nxdumptool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#ifndef __GAMECARD_STATUS_TASK_HPP__ +#define __GAMECARD_STATUS_TASK_HPP__ + +#include + +#include "../core/nxdt_utils.h" +#include "../core/gamecard.h" + +namespace nxdt::tasks +{ + /* Custom event type. */ + typedef brls::Event GameCardStatusEvent; + + /* Gamecard status task. */ + /* Its event provides a const reference to a GameCardStatus value. */ + class GameCardStatusTask: public brls::RepeatingTask + { + private: + GameCardStatusEvent gc_status_event; + GameCardStatus cur_gc_status = GameCardStatus_NotInserted; + GameCardStatus prev_gc_status = GameCardStatus_NotInserted; + bool first_notification = true; + + protected: + void run(retro_time_t current_time) override; + + public: + GameCardStatusTask(); + ~GameCardStatusTask(); + + ALWAYS_INLINE GameCardStatusEvent::Subscription RegisterListener(GameCardStatusEvent::Callback cb) + { + return this->gc_status_event.subscribe(cb); + } + + ALWAYS_INLINE void UnregisterListener(GameCardStatusEvent::Subscription subscription) + { + this->gc_status_event.unsubscribe(subscription); + } + }; +} + +#endif /* __GAMECARD_STATUS_TASK_HPP__ */ diff --git a/include/tasks/status_info_task.hpp b/include/tasks/status_info_task.hpp new file mode 100644 index 0000000..0c9ec8e --- /dev/null +++ b/include/tasks/status_info_task.hpp @@ -0,0 +1,75 @@ +/* + * status_info_task.hpp + * + * Copyright (c) 2020-2024, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nxdumptool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#ifndef __STATUS_INFO_TASK_HPP__ +#define __STATUS_INFO_TASK_HPP__ + +#include + +#include "../core/nxdt_utils.h" + +namespace nxdt::tasks +{ + /* Used to hold status info data. */ + typedef struct { + struct tm timeinfo; + u32 charge_percentage; + PsmChargerType charger_type; + bool connected; + NifmInternetConnectionType connection_type; + char ip_addr[16]; + } StatusInfoData; + + /* Custom event type. */ + typedef brls::Event StatusInfoEvent; + + /* Status info task. */ + /* Its event provides a const reference to a StatusInfoData struct. */ + class StatusInfoTask: public brls::RepeatingTask + { + private: + StatusInfoEvent status_info_event; + StatusInfoData status_info_data{}; + + protected: + void run(retro_time_t current_time) override; + + public: + StatusInfoTask(); + ~StatusInfoTask(); + + bool IsInternetConnectionAvailable(void); + + ALWAYS_INLINE StatusInfoEvent::Subscription RegisterListener(StatusInfoEvent::Callback cb) + { + return this->status_info_event.subscribe(cb); + } + + ALWAYS_INLINE void UnregisterListener(StatusInfoEvent::Subscription subscription) + { + this->status_info_event.unsubscribe(subscription); + } + }; +} + +#endif /* __STATUS_INFO_TASK_HPP__ */ diff --git a/include/tasks/title_metadata_task.hpp b/include/tasks/title_metadata_task.hpp new file mode 100644 index 0000000..2c15cd7 --- /dev/null +++ b/include/tasks/title_metadata_task.hpp @@ -0,0 +1,74 @@ +/* + * title_metadata_task.hpp + * + * Copyright (c) 2020-2024, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nxdumptool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#ifndef __TITLE_METADATA_TASK_HPP__ +#define __TITLE_METADATA_TASK_HPP__ + +#include + +#include "../core/nxdt_utils.h" +#include "../core/title.h" + +namespace nxdt::tasks +{ + /* Used to hold pointers to application metadata entries. */ + typedef std::vector TitleApplicationMetadataVector; + + /* Custom event type. */ + typedef brls::Event UserTitleEvent; + + /* Title metadata task. */ + /* Its event provides a const reference to a TitleApplicationMetadataVector with metadata for user titles (system titles don't change at runtime). */ + class TitleMetadataTask: public brls::RepeatingTask + { + private: + UserTitleEvent user_title_event; + + TitleApplicationMetadataVector system_metadata{}; + TitleApplicationMetadataVector user_metadata{}; + + void PopulateApplicationMetadataVector(bool is_system); + + protected: + void run(retro_time_t current_time) override; + + public: + TitleMetadataTask(); + ~TitleMetadataTask(); + + /* Intentionally left here to let views retrieve title metadata on-demand. */ + const TitleApplicationMetadataVector& GetApplicationMetadata(bool is_system); + + ALWAYS_INLINE UserTitleEvent::Subscription RegisterListener(UserTitleEvent::Callback cb) + { + return this->user_title_event.subscribe(cb); + } + + ALWAYS_INLINE void UnregisterListener(UserTitleEvent::Subscription subscription) + { + this->user_title_event.unsubscribe(subscription); + } + }; +} + +#endif /* __TITLE_METADATA_TASK_HPP__ */ diff --git a/include/tasks/ums_task.hpp b/include/tasks/ums_task.hpp new file mode 100644 index 0000000..d23db5a --- /dev/null +++ b/include/tasks/ums_task.hpp @@ -0,0 +1,77 @@ +/* + * ums_task.hpp + * + * Copyright (c) 2020-2024, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nxdumptool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#ifndef __UMS_TASK_HPP__ +#define __UMS_TASK_HPP__ + +#include + +#include "../core/nxdt_utils.h" +#include "../core/ums.h" + +namespace nxdt::tasks +{ + /* Used to hold information from UMS devices. */ + typedef std::pair UmsDeviceVectorEntry; + typedef std::vector UmsDeviceVector; + + /* Custom event type. */ + typedef brls::Event UmsEvent; + + /* USB Mass Storage task. */ + /* Its event provides a const reference to a UmsDeviceVector. */ + class UmsTask: public brls::RepeatingTask + { + private: + UmsEvent ums_event; + + UsbHsFsDevice *ums_devices = nullptr; + u32 ums_devices_count = 0; + + UmsDeviceVector ums_devices_vector{}; + + void PopulateUmsDeviceVector(void); + + protected: + void run(retro_time_t current_time) override; + + public: + UmsTask(); + ~UmsTask(); + + /* Intentionally left here to let views retrieve UMS device info on-demand. */ + const UmsDeviceVector& GetUmsDevices(void); + + ALWAYS_INLINE UmsEvent::Subscription RegisterListener(UmsEvent::Callback cb) + { + return this->ums_event.subscribe(cb); + } + + ALWAYS_INLINE void UnregisterListener(UmsEvent::Subscription subscription) + { + this->ums_event.unsubscribe(subscription); + } + }; +} + +#endif /* __UMS_TASK_HPP__ */ diff --git a/include/tasks/usb_host_task.hpp b/include/tasks/usb_host_task.hpp new file mode 100644 index 0000000..b849ad8 --- /dev/null +++ b/include/tasks/usb_host_task.hpp @@ -0,0 +1,67 @@ +/* + * usb_host_task.hpp + * + * Copyright (c) 2020-2024, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nxdumptool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#ifndef __USB_HOST_TASK_HPP__ +#define __USB_HOST_TASK_HPP__ + +#include + +#include "../core/nxdt_utils.h" +#include "../core/usb.h" + +namespace nxdt::tasks +{ + /* Custom event type. */ + typedef brls::Event UsbHostEvent; + + /* USB host device connection task. */ + class UsbHostTask: public brls::RepeatingTask + { + private: + UsbHostEvent usb_host_event; + UsbHostSpeed cur_usb_host_speed = UsbHostSpeed_None; + UsbHostSpeed prev_usb_host_speed = UsbHostSpeed_None; + + protected: + void run(retro_time_t current_time) override; + + public: + UsbHostTask(); + ~UsbHostTask(); + + /* Intentionally left here to let views retrieve USB host connection speed on-demand. */ + const UsbHostSpeed& GetUsbHostSpeed(void); + + ALWAYS_INLINE UsbHostEvent::Subscription RegisterListener(UsbHostEvent::Callback cb) + { + return this->usb_host_event.subscribe(cb); + } + + ALWAYS_INLINE void UnregisterListener(UsbHostEvent::Subscription subscription) + { + this->usb_host_event.unsubscribe(subscription); + } + }; +} + +#endif /* __USB_HOST_TASK_HPP__ */ diff --git a/include/file_writer.hpp b/include/utils/file_writer.hpp similarity index 98% rename from include/file_writer.hpp rename to include/utils/file_writer.hpp index 4ffe2fe..39c2ee2 100644 --- a/include/file_writer.hpp +++ b/include/utils/file_writer.hpp @@ -27,8 +27,8 @@ #include #include -#include "core/nxdt_utils.h" -#include "core/usb.h" +#include "../core/nxdt_utils.h" +#include "../core/usb.h" namespace nxdt::utils { diff --git a/include/is_base_of_template.hpp b/include/utils/is_base_of_template.hpp similarity index 100% rename from include/is_base_of_template.hpp rename to include/utils/is_base_of_template.hpp diff --git a/include/scope_guard.hpp b/include/utils/scope_guard.hpp similarity index 98% rename from include/scope_guard.hpp rename to include/utils/scope_guard.hpp index 6babd2e..a7ad6ed 100644 --- a/include/scope_guard.hpp +++ b/include/utils/scope_guard.hpp @@ -27,7 +27,7 @@ #ifndef __SCOPE_GUARD_HPP__ #define __SCOPE_GUARD_HPP__ -#include "defines.h" +#include "../defines.h" #define SCOPE_GUARD ::nxdt::utils::ScopeGuardOnExit() + [&]() ALWAYS_INLINE_LAMBDA #define ON_SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE_) = SCOPE_GUARD diff --git a/include/about_tab.hpp b/include/views/about_tab.hpp similarity index 99% rename from include/about_tab.hpp rename to include/views/about_tab.hpp index a7e5fbb..d01d78d 100644 --- a/include/about_tab.hpp +++ b/include/views/about_tab.hpp @@ -25,6 +25,7 @@ #define __ABOUT_TAB_HPP__ #include + #include "focusable_item.hpp" namespace nxdt::views diff --git a/include/data_transfer_progress_display.hpp b/include/views/data_transfer_progress_display.hpp similarity index 97% rename from include/data_transfer_progress_display.hpp rename to include/views/data_transfer_progress_display.hpp index 5e66447..d9f58a9 100644 --- a/include/data_transfer_progress_display.hpp +++ b/include/views/data_transfer_progress_display.hpp @@ -24,7 +24,7 @@ #ifndef __DATA_TRANSFER_PROGRESS_DISPLAY_HPP__ #define __DATA_TRANSFER_PROGRESS_DISPLAY_HPP__ -#include "data_transfer_task.hpp" +#include "../tasks/data_transfer_task.hpp" namespace nxdt::views { diff --git a/include/data_transfer_task_frame.hpp b/include/views/data_transfer_task_frame.hpp similarity index 99% rename from include/data_transfer_task_frame.hpp rename to include/views/data_transfer_task_frame.hpp index b68f174..5ecf3ab 100644 --- a/include/data_transfer_task_frame.hpp +++ b/include/views/data_transfer_task_frame.hpp @@ -24,7 +24,7 @@ #ifndef __DATA_TRANSFER_TASK_FRAME_HPP__ #define __DATA_TRANSFER_TASK_FRAME_HPP__ -#include "is_base_of_template.hpp" +#include "../utils/is_base_of_template.hpp" #include "error_frame.hpp" #include "data_transfer_progress_display.hpp" diff --git a/include/dump_options_frame.hpp b/include/views/dump_options_frame.hpp similarity index 100% rename from include/dump_options_frame.hpp rename to include/views/dump_options_frame.hpp diff --git a/include/error_frame.hpp b/include/views/error_frame.hpp similarity index 100% rename from include/error_frame.hpp rename to include/views/error_frame.hpp diff --git a/include/focusable_item.hpp b/include/views/focusable_item.hpp similarity index 100% rename from include/focusable_item.hpp rename to include/views/focusable_item.hpp diff --git a/include/gamecard_image_dump_options_frame.hpp b/include/views/gamecard_image_dump_options_frame.hpp similarity index 100% rename from include/gamecard_image_dump_options_frame.hpp rename to include/views/gamecard_image_dump_options_frame.hpp diff --git a/include/gamecard_image_dump_task_frame.hpp b/include/views/gamecard_image_dump_task_frame.hpp similarity index 97% rename from include/gamecard_image_dump_task_frame.hpp rename to include/views/gamecard_image_dump_task_frame.hpp index c5b52b7..d48cd78 100644 --- a/include/gamecard_image_dump_task_frame.hpp +++ b/include/views/gamecard_image_dump_task_frame.hpp @@ -25,7 +25,7 @@ #define __GAMECARD_IMAGE_DUMP_TASK_FRAME_HPP__ #include "data_transfer_task_frame.hpp" -#include "gamecard_image_dump_task.hpp" +#include "../tasks/gamecard_image_dump_task.hpp" namespace nxdt::views { diff --git a/include/gamecard_tab.hpp b/include/views/gamecard_tab.hpp similarity index 85% rename from include/gamecard_tab.hpp rename to include/views/gamecard_tab.hpp index 3cbf8db..cc7212f 100644 --- a/include/gamecard_tab.hpp +++ b/include/views/gamecard_tab.hpp @@ -32,9 +32,9 @@ namespace nxdt::views { class GameCardTab: public LayeredErrorFrame { - typedef bool (*GameCardSizeFunc)(u64 *out_size); - private: + typedef bool (*GameCardSizeFunc)(u64 *out_size); + RootView *root_view = nullptr; nxdt::tasks::GameCardStatusEvent::Subscription gc_status_task_sub; @@ -44,9 +44,18 @@ namespace nxdt::views std::string raw_filename_id_only = ""; void ProcessGameCardStatus(GameCardStatus gc_status); - std::string GetFormattedSizeString(GameCardSizeFunc func); - std::string GetCardIdSetString(FsGameCardIdSet *card_id_set); + + + void PopulateList(void); + void AddApplicationMetadataItems(void); + void AddPropertiesTable(void); + + void GenerateRawFilenames(void); + std::string GetFormattedSizeString(GameCardSizeFunc func); + std::string GetCardIdSetString(const FsGameCardIdSet& card_id_set); + + public: GameCardTab(RootView *root_view); diff --git a/include/layered_error_frame.hpp b/include/views/layered_error_frame.hpp similarity index 100% rename from include/layered_error_frame.hpp rename to include/views/layered_error_frame.hpp diff --git a/include/options_tab.hpp b/include/views/options_tab.hpp similarity index 97% rename from include/options_tab.hpp rename to include/views/options_tab.hpp index 0ff3a61..71bc228 100644 --- a/include/options_tab.hpp +++ b/include/views/options_tab.hpp @@ -26,6 +26,8 @@ #include "root_view.hpp" #include "data_transfer_progress_display.hpp" +#include "../tasks/download_file_task.hpp" +#include "../tasks/download_data_task.hpp" namespace nxdt::views { diff --git a/include/root_view.hpp b/include/views/root_view.hpp similarity index 87% rename from include/root_view.hpp rename to include/views/root_view.hpp index 2f173fc..6642625 100644 --- a/include/root_view.hpp +++ b/include/views/root_view.hpp @@ -24,7 +24,11 @@ #ifndef __ROOT_VIEW_HPP__ #define __ROOT_VIEW_HPP__ -#include "tasks.hpp" +#include "../tasks/status_info_task.hpp" +#include "../tasks/gamecard_status_task.hpp" +#include "../tasks/title_metadata_task.hpp" +#include "../tasks/ums_task.hpp" +#include "../tasks/usb_host_task.hpp" #define EVENT_SUBSCRIPTION(func_name, event_type, task_name) \ ALWAYS_INLINE nxdt::tasks::event_type::Subscription Register##func_name##Listener(nxdt::tasks::event_type::Callback cb) { return this->task_name->RegisterListener(cb); } \ @@ -47,8 +51,8 @@ namespace nxdt::views brls::Label *cable_icon = nullptr, *usb_host_speed_lbl = nullptr; nxdt::tasks::StatusInfoTask *status_info_task = nullptr; - nxdt::tasks::GameCardTask *gc_status_task = nullptr; - nxdt::tasks::TitleTask *title_task = nullptr; + nxdt::tasks::GameCardStatusTask *gc_status_task = nullptr; + nxdt::tasks::TitleMetadataTask *title_metadata_task = nullptr; nxdt::tasks::UmsTask *ums_task = nullptr; nxdt::tasks::UsbHostTask *usb_host_task = nullptr; @@ -88,7 +92,7 @@ namespace nxdt::views ALWAYS_INLINE const nxdt::tasks::TitleApplicationMetadataVector& GetApplicationMetadata(bool is_system) { - return this->title_task->GetApplicationMetadata(is_system); + return this->title_metadata_task->GetApplicationMetadata(is_system); } ALWAYS_INLINE const nxdt::tasks::UmsDeviceVector& GetUmsDevices(void) @@ -102,8 +106,8 @@ namespace nxdt::views } EVENT_SUBSCRIPTION(StatusInfoTask, StatusInfoEvent, status_info_task); - EVENT_SUBSCRIPTION(GameCardTask, GameCardStatusEvent, gc_status_task); - EVENT_SUBSCRIPTION(TitleTask, UserTitleEvent, title_task); + EVENT_SUBSCRIPTION(GameCardStatusTask, GameCardStatusEvent, gc_status_task); + EVENT_SUBSCRIPTION(TitleMetadataTask, UserTitleEvent, title_metadata_task); EVENT_SUBSCRIPTION(UmsTask, UmsEvent, ums_task); EVENT_SUBSCRIPTION(UsbHostTask, UsbHostEvent, usb_host_task); }; diff --git a/include/titles_tab.hpp b/include/views/titles_tab.hpp similarity index 100% rename from include/titles_tab.hpp rename to include/views/titles_tab.hpp diff --git a/libs/borealis b/libs/borealis index e5cbe0d..0846ff5 160000 --- a/libs/borealis +++ b/libs/borealis @@ -1 +1 @@ -Subproject commit e5cbe0d97c32d1102a6ea253ed68a3a8ecfdc3a9 +Subproject commit 0846ff57b72a1bdd9fc86eee348258c0b52e0ece diff --git a/source/core/aes.c b/source/core/aes.c index 10e9a4e..9b13bf9 100644 --- a/source/core/aes.c +++ b/source/core/aes.c @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" +#include void aes128EcbCrypt(void *dst, const void *src, const void *key, bool encrypt) { diff --git a/source/core/bfttf.c b/source/core/bfttf.c index fdf0f95..b9c4e22 100644 --- a/source/core/bfttf.c +++ b/source/core/bfttf.c @@ -20,10 +20,10 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "bfttf.h" -#include "romfs.h" -#include "title.h" +#include +#include +#include +#include /* Type definitions. */ diff --git a/source/core/bktr.c b/source/core/bktr.c index 3d34c9b..5212941 100644 --- a/source/core/bktr.c +++ b/source/core/bktr.c @@ -20,9 +20,9 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "bktr.h" -#include "aes.h" +#include +#include +#include /* Type definitions. */ diff --git a/source/core/cert.c b/source/core/cert.c index 3c2537a..f057ed1 100644 --- a/source/core/cert.c +++ b/source/core/cert.c @@ -19,10 +19,10 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "cert.h" -#include "save.h" -#include "gamecard.h" +#include +#include +#include +#include #define CERT_SAVEFILE_PATH BIS_SYSTEM_PARTITION_MOUNT_NAME "/save/80000000000000e0" #define CERT_SAVEFILE_STORAGE_BASE_PATH "/certificate/" diff --git a/source/core/cnmt.c b/source/core/cnmt.c index 45301ba..eeac9d5 100644 --- a/source/core/cnmt.c +++ b/source/core/cnmt.c @@ -19,9 +19,9 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "cnmt.h" -#include "title.h" +#include +#include +#include /* Helper macros. */ diff --git a/source/core/config.c b/source/core/config.c index dbc1687..1b9d6c3 100644 --- a/source/core/config.c +++ b/source/core/config.c @@ -19,9 +19,9 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "config.h" -#include "title.h" +#include +#include +#include #define CONFIG_VALIDATE_FIELD(type, name, ...) \ if (!strcmp(key, #name)) { \ diff --git a/source/devoptab/hfs_dev.c b/source/core/devoptab/hfs_dev.c similarity index 99% rename from source/devoptab/hfs_dev.c rename to source/core/devoptab/hfs_dev.c index 71bd0f6..ecc25b1 100644 --- a/source/devoptab/hfs_dev.c +++ b/source/core/devoptab/hfs_dev.c @@ -21,9 +21,9 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "nxdt_devoptab.h" -#include "ro_dev.h" +#include +#include +#include /* Helper macros. */ diff --git a/source/devoptab/nxdt_devoptab.c b/source/core/devoptab/nxdt_devoptab.c similarity index 98% rename from source/devoptab/nxdt_devoptab.c rename to source/core/devoptab/nxdt_devoptab.c index 81bc4e9..b11b7cb 100644 --- a/source/devoptab/nxdt_devoptab.c +++ b/source/core/devoptab/nxdt_devoptab.c @@ -19,8 +19,8 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "nxdt_devoptab.h" +#include +#include #define DEVOPTAB_DEVICE_COUNT 4 diff --git a/source/devoptab/nxdt_romfs_dev.c b/source/core/devoptab/nxdt_romfs_dev.c similarity index 99% rename from source/devoptab/nxdt_romfs_dev.c rename to source/core/devoptab/nxdt_romfs_dev.c index c5571df..ca298a9 100644 --- a/source/devoptab/nxdt_romfs_dev.c +++ b/source/core/devoptab/nxdt_romfs_dev.c @@ -21,9 +21,9 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "nxdt_devoptab.h" -#include "ro_dev.h" +#include +#include +#include /* Helper macros. */ diff --git a/source/devoptab/pfs_dev.c b/source/core/devoptab/pfs_dev.c similarity index 99% rename from source/devoptab/pfs_dev.c rename to source/core/devoptab/pfs_dev.c index 6d5b22d..8e70aa6 100644 --- a/source/devoptab/pfs_dev.c +++ b/source/core/devoptab/pfs_dev.c @@ -21,9 +21,9 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "nxdt_devoptab.h" -#include "ro_dev.h" +#include +#include +#include /* Helper macros. */ diff --git a/source/devoptab/ro_dev.c b/source/core/devoptab/ro_dev.c similarity index 97% rename from source/devoptab/ro_dev.c rename to source/core/devoptab/ro_dev.c index 73eb667..6afb560 100644 --- a/source/devoptab/ro_dev.c +++ b/source/core/devoptab/ro_dev.c @@ -19,8 +19,8 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "nxdt_devoptab.h" +#include +#include ssize_t rodev_write(struct _reent *r, void *fd, const char *ptr, size_t len) { diff --git a/source/core/es.c b/source/core/es.c index ac48485..ddbaa5c 100644 --- a/source/core/es.c +++ b/source/core/es.c @@ -20,9 +20,9 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "es.h" -#include "service_guard.h" +#include +#include +#include static Service g_esSrv = {0}; diff --git a/source/fatfs/diskio.c b/source/core/fatfs/diskio.c similarity index 95% rename from source/fatfs/diskio.c rename to source/core/fatfs/diskio.c index 9e985d4..271635e 100644 --- a/source/fatfs/diskio.c +++ b/source/core/fatfs/diskio.c @@ -7,12 +7,10 @@ /* storage control modules to the FatFs module with a defined API. */ /*-----------------------------------------------------------------------*/ -#include "ff.h" /* Obtains integer types */ -#include "diskio.h" /* Declarations of disk functions */ +#include -#include - -#include "nxdt_utils.h" +#include /* Obtains integer types */ +#include /* Declarations of disk functions */ /*-----------------------------------------------------------------------*/ /* Get Drive Status */ diff --git a/source/fatfs/ff.c b/source/core/fatfs/ff.c similarity index 99% rename from source/fatfs/ff.c rename to source/core/fatfs/ff.c index 6709fd1..dc957c6 100644 --- a/source/fatfs/ff.c +++ b/source/core/fatfs/ff.c @@ -20,8 +20,8 @@ #include -#include "ff.h" /* Declarations of FatFs API */ -#include "diskio.h" /* Declarations of device I/O functions */ +#include /* Declarations of FatFs API */ +#include /* Declarations of device I/O functions */ /*-------------------------------------------------------------------------- diff --git a/source/fatfs/ffsystem.c b/source/core/fatfs/ffsystem.c similarity index 99% rename from source/fatfs/ffsystem.c rename to source/core/fatfs/ffsystem.c index d23f545..fbd7bb0 100644 --- a/source/fatfs/ffsystem.c +++ b/source/core/fatfs/ffsystem.c @@ -2,7 +2,7 @@ /* A Sample Code of User Provided OS Dependent Functions for FatFs */ /*------------------------------------------------------------------------*/ -#include "ff.h" +#include #if FF_USE_LFN == 3 /* Use dynamic memory allocation */ diff --git a/source/fatfs/ffunicode.c b/source/core/fatfs/ffunicode.c similarity index 99% rename from source/fatfs/ffunicode.c rename to source/core/fatfs/ffunicode.c index e6bcaca..181c233 100644 --- a/source/fatfs/ffunicode.c +++ b/source/core/fatfs/ffunicode.c @@ -23,7 +23,7 @@ */ -#include "ff.h" +#include #if FF_USE_LFN != 0 /* This module will be blanked if in non-LFN configuration */ diff --git a/source/core/fs_ext.c b/source/core/fs_ext.c index ace2e9d..9ea8234 100644 --- a/source/core/fs_ext.c +++ b/source/core/fs_ext.c @@ -19,8 +19,8 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "fs_ext.h" +#include +#include /* IFileSystemProxy. */ Result fsOpenGameCardStorage(FsStorage *out, const FsGameCardHandle *handle, u32 partition) diff --git a/source/core/gamecard.c b/source/core/gamecard.c index 63577b7..52851f8 100644 --- a/source/core/gamecard.c +++ b/source/core/gamecard.c @@ -19,11 +19,11 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "mem.h" -#include "gamecard.h" -#include "keys.h" -#include "rsa.h" +#include +#include +#include +#include +#include #define GAMECARD_READ_BUFFER_SIZE 0x800000 /* 8 MiB. */ diff --git a/source/core/hfs.c b/source/core/hfs.c index a8c711a..4ee235e 100644 --- a/source/core/hfs.c +++ b/source/core/hfs.c @@ -19,8 +19,8 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "gamecard.h" +#include +#include #define HFS_PARTITION_NAME_INDEX(x) ((x) - 1) diff --git a/source/core/http.c b/source/core/http.c index 74df1d3..c49b7fa 100644 --- a/source/core/http.c +++ b/source/core/http.c @@ -19,8 +19,8 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "http.h" +#include +#include /* Global variables. */ diff --git a/source/core/keys.c b/source/core/keys.c index e0877f9..0e21901 100644 --- a/source/core/keys.c +++ b/source/core/keys.c @@ -21,13 +21,13 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "keys.h" -#include "nca.h" -#include "rsa.h" -#include "aes.h" -#include "smc.h" -#include "key_sources.h" +#include +#include +#include +#include +#include +#include +#include #define ETICKET_RSA_DEVICE_KEY_PUBLIC_EXPONENT 0x10001 diff --git a/source/core/legal_info.c b/source/core/legal_info.c index a972016..db06fcd 100644 --- a/source/core/legal_info.c +++ b/source/core/legal_info.c @@ -19,8 +19,8 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "legal_info.h" +#include +#include bool legalInfoInitializeContext(LegalInfoContext *out, NcaContext *nca_ctx) { diff --git a/source/core/lz4.c b/source/core/lz4.c index 654bfdf..35d7cc9 100644 --- a/source/core/lz4.c +++ b/source/core/lz4.c @@ -114,7 +114,7 @@ #endif #define LZ4_STATIC_LINKING_ONLY /* LZ4_DISTANCE_MAX */ -#include "lz4.h" +#include /* see also "memory routines" below */ diff --git a/source/core/mem.c b/source/core/mem.c index 56ac0d2..35ba478 100644 --- a/source/core/mem.c +++ b/source/core/mem.c @@ -20,8 +20,8 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "mem.h" +#include +#include #define MEMLOG_DEBUG(fmt, ...) LOG_MSG_BUF_DEBUG(&g_memLogBuf, &g_memLogBufSize, fmt, ##__VA_ARGS__) #define MEMLOG_ERROR(fmt, ...) LOG_MSG_BUF_ERROR(&g_memLogBuf, &g_memLogBufSize, fmt, ##__VA_ARGS__) diff --git a/source/core/nacp.c b/source/core/nacp.c index 6ad7ada..93cb6cd 100644 --- a/source/core/nacp.c +++ b/source/core/nacp.c @@ -19,9 +19,9 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "nacp.h" -#include "title.h" +#include +#include +#include /* Helper macros. */ diff --git a/source/core/nca.c b/source/core/nca.c index b3c47da..c253c74 100644 --- a/source/core/nca.c +++ b/source/core/nca.c @@ -19,13 +19,13 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "nca.h" -#include "keys.h" -#include "aes.h" -#include "rsa.h" -#include "gamecard.h" -#include "title.h" +#include +#include +#include +#include +#include +#include +#include #define NCA_CRYPTO_BUFFER_SIZE 0x800000 /* 8 MiB. */ diff --git a/source/core/nca_storage.c b/source/core/nca_storage.c index 92b0086..a6429ee 100644 --- a/source/core/nca_storage.c +++ b/source/core/nca_storage.c @@ -19,8 +19,8 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "nca_storage.h" +#include +#include /* Function prototypes. */ diff --git a/source/core/npdm.c b/source/core/npdm.c index a897765..b0a0c10 100644 --- a/source/core/npdm.c +++ b/source/core/npdm.c @@ -19,9 +19,9 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "npdm.h" -#include "rsa.h" +#include +#include +#include bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx) { diff --git a/source/core/nso.c b/source/core/nso.c index 80d9240..1908cc3 100644 --- a/source/core/nso.c +++ b/source/core/nso.c @@ -19,8 +19,8 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "nso.h" +#include +#include /* Function prototypes. */ diff --git a/source/core/nxdt_bfsar.c b/source/core/nxdt_bfsar.c index 01c5ecd..14879b8 100644 --- a/source/core/nxdt_bfsar.c +++ b/source/core/nxdt_bfsar.c @@ -19,10 +19,10 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "nxdt_bfsar.h" -#include "romfs.h" -#include "title.h" +#include +#include +#include +#include #define BFSAR_FILENAME "qlaunch.bfsar" #define BFSAR_ROMFS_PATH "/sound/" BFSAR_FILENAME diff --git a/source/core/nxdt_json.c b/source/core/nxdt_json.c index 48e71cb..d523267 100644 --- a/source/core/nxdt_json.c +++ b/source/core/nxdt_json.c @@ -19,8 +19,8 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "nxdt_json.h" +#include +#include #define JSON_GETTER(functype, vartype, jsontype, ...) \ vartype jsonGet##functype(const struct json_object *obj, const char *path) { \ diff --git a/source/core/nxdt_log.c b/source/core/nxdt_log.c index e28866d..71e312a 100644 --- a/source/core/nxdt_log.c +++ b/source/core/nxdt_log.c @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" +#include #if (LOG_LEVEL >= LOG_LEVEL_DEBUG) && (LOG_LEVEL < LOG_LEVEL_NONE) diff --git a/source/core/nxdt_utils.c b/source/core/nxdt_utils.c index 8828a79..1c7d052 100644 --- a/source/core/nxdt_utils.c +++ b/source/core/nxdt_utils.c @@ -21,17 +21,17 @@ #include -#include "nxdt_utils.h" -#include "keys.h" -#include "gamecard.h" -#include "services.h" -#include "nca.h" -#include "usb.h" -#include "title.h" -#include "bfttf.h" -#include "nxdt_bfsar.h" -#include "nxdt_devoptab.h" -#include "fatfs/ff.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Type definitions. */ diff --git a/source/core/pfs.c b/source/core/pfs.c index ee811f1..c4e32e2 100644 --- a/source/core/pfs.c +++ b/source/core/pfs.c @@ -19,9 +19,9 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "pfs.h" -#include "npdm.h" +#include +#include +#include #define PFS_HEADER_PADDING_ALIGNMENT 0x20 diff --git a/source/core/program_info.c b/source/core/program_info.c index c4143f0..5155d5d 100644 --- a/source/core/program_info.c +++ b/source/core/program_info.c @@ -21,9 +21,9 @@ #include -#include "nxdt_utils.h" -#include "program_info.h" -#include "elf_symbol.h" +#include +#include +#include /* Helper macros. */ diff --git a/source/core/romfs.c b/source/core/romfs.c index baea225..b4284ee 100644 --- a/source/core/romfs.c +++ b/source/core/romfs.c @@ -19,8 +19,8 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "romfs.h" +#include +#include /* Helper macros. */ diff --git a/source/core/rsa.c b/source/core/rsa.c index c45a845..6e253c8 100644 --- a/source/core/rsa.c +++ b/source/core/rsa.c @@ -20,8 +20,8 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "rsa.h" +#include +#include #include #include diff --git a/source/core/save.c b/source/core/save.c index c846b13..1a86e68 100644 --- a/source/core/save.c +++ b/source/core/save.c @@ -20,8 +20,8 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "save.h" +#include +#include static inline void save_bitmap_set_bit(void *buffer, size_t bit_offset) { diff --git a/source/core/services.c b/source/core/services.c index 5fbb311..edbc362 100644 --- a/source/core/services.c +++ b/source/core/services.c @@ -19,9 +19,9 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "services.h" -#include "es.h" +#include +#include +#include /* Type definitions. */ diff --git a/source/core/sha3.c b/source/core/sha3.c index aa41f00..f55d8d7 100644 --- a/source/core/sha3.c +++ b/source/core/sha3.c @@ -21,8 +21,8 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "sha3.h" +#include +#include #define SHA3_NUM_ROUNDS 24 diff --git a/source/core/tik.c b/source/core/tik.c index 1e608d8..e2d51ea 100644 --- a/source/core/tik.c +++ b/source/core/tik.c @@ -20,16 +20,16 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "nca.h" -#include "cert.h" -#include "save.h" -#include "es.h" -#include "keys.h" -#include "gamecard.h" -#include "mem.h" -#include "aes.h" -#include "rsa.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #define TIK_COMMON_SAVEFILE_PATH BIS_SYSTEM_PARTITION_MOUNT_NAME "/save/80000000000000e1" #define TIK_PERSONALIZED_SAVEFILE_PATH BIS_SYSTEM_PARTITION_MOUNT_NAME "/save/80000000000000e2" diff --git a/source/core/title.c b/source/core/title.c index 38fc255..11c4744 100644 --- a/source/core/title.c +++ b/source/core/title.c @@ -19,10 +19,10 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "title.h" -#include "gamecard.h" -#include "nacp.h" +#include +#include +#include +#include #define NS_APPLICATION_RECORD_BLOCK_SIZE 1024 @@ -577,6 +577,7 @@ static TitleInfo *titleDuplicateTitleInfo(TitleInfo *title_info); static int titleSystemTitleMetadataEntrySortFunction(const void *a, const void *b); static int titleUserApplicationMetadataEntrySortFunction(const void *a, const void *b); static int titleInfoEntrySortFunction(const void *a, const void *b); +static int titleGameCardApplicationMetadataSortFunction(const void *a, const void *b); static char *titleGetPatchVersionString(TitleInfo *title_info); @@ -767,6 +768,7 @@ TitleGameCardApplicationMetadataEntry *titleGetGameCardApplicationMetadataEntrie if (!app_info || app_info->meta_key.type != NcmContentMetaType_Application) continue; u32 app_version = app_info->meta_key.version; + u32 dlc_count = 0; /* Check if the inserted gamecard holds any bundled patches for the current user application. */ /* If so, we'll use the highest patch version available as part of the filename. */ @@ -782,6 +784,18 @@ TitleGameCardApplicationMetadataEntry *titleGetGameCardApplicationMetadataEntrie app_version = cur_title_info->meta_key.version; } + /* Count DLCs available for this application in the inserted gamecard. */ + for(u32 j = 0; j < title_count; j++) + { + if (j == i) continue; + + TitleInfo *cur_title_info = titles[j]; + if (!cur_title_info || cur_title_info->meta_key.type != NcmContentMetaType_AddOnContent || \ + !titleCheckIfAddOnContentIdBelongsToApplicationId(app_info->meta_key.id, cur_title_info->meta_key.id)) continue; + + dlc_count++; + } + /* Reallocate application metadata pointer array. */ tmp_gc_app_metadata = realloc(gc_app_metadata, (app_count + 1) * sizeof(TitleGameCardApplicationMetadataEntry)); if (!tmp_gc_app_metadata) @@ -801,6 +815,7 @@ TitleGameCardApplicationMetadataEntry *titleGetGameCardApplicationMetadataEntrie memset(tmp_gc_app_metadata, 0, sizeof(TitleGameCardApplicationMetadataEntry)); tmp_gc_app_metadata->app_metadata = app_info->app_metadata; tmp_gc_app_metadata->version.value = app_version; + tmp_gc_app_metadata->dlc_count = dlc_count; /* Try to retrieve the display version. */ char *version_str = titleGetPatchVersionString(patch_info ? patch_info : app_info); @@ -816,7 +831,13 @@ TitleGameCardApplicationMetadataEntry *titleGetGameCardApplicationMetadataEntrie /* Update output counter. */ *out_count = app_count; - if (!gc_app_metadata || !app_count) LOG_MSG_ERROR("No gamecard content data found for user applications!"); + if (gc_app_metadata && app_count) + { + /* Reorder title metadata entries by name. */ + if (app_count > 1) qsort(gc_app_metadata, app_count, sizeof(TitleGameCardApplicationMetadataEntry), &titleGameCardApplicationMetadataSortFunction); + } else { + LOG_MSG_ERROR("No gamecard content data found for user applications!"); + } } return gc_app_metadata; @@ -2061,7 +2082,7 @@ static bool titleGenerateTitleInfoEntriesForTitleStorage(TitleStorage *title_sto if (extra_title_count < total) titleReallocateTitleInfoFromStorage(title_storage, 0, false); /* Sort title info entries by title ID, version and storage ID. */ - qsort(title_storage->titles, title_storage->title_count, sizeof(TitleInfo*), &titleInfoEntrySortFunction); + if (title_storage->title_count > 1) qsort(title_storage->titles, title_storage->title_count, sizeof(TitleInfo*), &titleInfoEntrySortFunction); /* Update linked lists for user applications, patches and add-on contents. */ /* This will also keep track of orphan titles - titles with no available application metadata. */ @@ -2770,6 +2791,14 @@ static int titleInfoEntrySortFunction(const void *a, const void *b) return 0; } +static int titleGameCardApplicationMetadataSortFunction(const void *a, const void *b) +{ + const TitleGameCardApplicationMetadataEntry *gc_app_metadata_1 = (const TitleGameCardApplicationMetadataEntry*)a; + const TitleGameCardApplicationMetadataEntry *gc_app_metadata_2 = (const TitleGameCardApplicationMetadataEntry*)b; + + return strcasecmp(gc_app_metadata_1->app_metadata->lang_entry.name, gc_app_metadata_2->app_metadata->lang_entry.name); +} + static char *titleGetPatchVersionString(TitleInfo *title_info) { NcmContentInfo *nacp_content = NULL; diff --git a/source/core/ums.c b/source/core/ums.c index e53a557..b8a39dc 100644 --- a/source/core/ums.c +++ b/source/core/ums.c @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" +#include /* Global variables. */ diff --git a/source/core/usb.c b/source/core/usb.c index f21f25b..c7d0a0f 100644 --- a/source/core/usb.c +++ b/source/core/usb.c @@ -22,8 +22,8 @@ * along with this program. If not, see . */ -#include "nxdt_utils.h" -#include "usb.h" +#include +#include #define USB_ABI_VERSION_MAJOR 1 #define USB_ABI_VERSION_MINOR 2 diff --git a/source/main.cpp b/source/main.cpp index 265d1f1..a807c4b 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -19,9 +19,9 @@ * along with this program. If not, see . */ -#include -#include -#include +#include +#include +#include namespace i18n = brls::i18n; /* For getStr(). */ using namespace i18n::literals; /* For _i18n. */ diff --git a/source/tasks.cpp b/source/tasks.cpp deleted file mode 100644 index a2a3adb..0000000 --- a/source/tasks.cpp +++ /dev/null @@ -1,316 +0,0 @@ -/* - * tasks.cpp - * - * Copyright (c) 2020-2024, DarkMatterCore . - * - * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). - * - * nxdumptool is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * nxdumptool is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include - -#define NXDT_TASK_INTERVAL 250 /* 250 ms. */ - -using namespace brls::i18n::literals; /* For _i18n. */ - -namespace nxdt::tasks -{ - /* Status info task. */ - - StatusInfoTask::StatusInfoTask() : brls::RepeatingTask(NXDT_TASK_INTERVAL) - { - brls::RepeatingTask::start(); - LOG_MSG_DEBUG("Status info task started."); - } - - StatusInfoTask::~StatusInfoTask() - { - LOG_MSG_DEBUG("Status info task stopped."); - } - - bool StatusInfoTask::IsInternetConnectionAvailable(void) - { - return this->status_info_data.connected; - } - - void StatusInfoTask::run(retro_time_t current_time) - { - brls::RepeatingTask::run(current_time); - - StatusInfoData *status_info_data = &(this->status_info_data); - - /* Get current time. */ - time_t unix_time = time(nullptr); - localtime_r(&unix_time, &(status_info_data->timeinfo)); - - /* Get battery stats. */ - psmGetBatteryChargePercentage(&(status_info_data->charge_percentage)); - psmGetChargerType(&(status_info_data->charger_type)); - - /* Get network connection status. */ - u32 signal_strength = 0; - NifmInternetConnectionStatus connection_status{}; - char *ip_addr = nullptr; - - status_info_data->connected = false; - - Result rc = nifmGetInternetConnectionStatus(&(status_info_data->connection_type), &signal_strength, &connection_status); - if (R_SUCCEEDED(rc) && status_info_data->connection_type && connection_status == NifmInternetConnectionStatus_Connected) - { - status_info_data->connected = true; - - struct in_addr addr = { .s_addr = INADDR_NONE }; - nifmGetCurrentIpAddress(&(addr.s_addr)); - - if (addr.s_addr != INADDR_NONE && (ip_addr = inet_ntoa(addr))) snprintf(status_info_data->ip_addr, MAX_ELEMENTS(status_info_data->ip_addr), "%s", ip_addr); - } - - /* Fire task event. */ - this->status_info_event.fire(this->status_info_data); - } - - /* Gamecard task. */ - - GameCardTask::GameCardTask() : brls::RepeatingTask(NXDT_TASK_INTERVAL) - { - brls::RepeatingTask::start(); - LOG_MSG_DEBUG("Gamecard task started."); - - this->first_notification = (gamecardGetStatus() >= GameCardStatus_Processing); - } - - GameCardTask::~GameCardTask() - { - LOG_MSG_DEBUG("Gamecard task stopped."); - } - - void GameCardTask::run(retro_time_t current_time) - { - brls::RepeatingTask::run(current_time); - - this->cur_gc_status = static_cast(gamecardGetStatus()); - if (this->cur_gc_status != this->prev_gc_status) - { - LOG_MSG_DEBUG("Gamecard status change triggered: %u.", this->cur_gc_status); - - if (!this->first_notification) - { - if (this->prev_gc_status == GameCardStatus_NotInserted && this->cur_gc_status == GameCardStatus_Processing) - { - brls::Application::notify("gamecard_tab/error_frame/processing"_i18n); - } else - if (this->prev_gc_status == GameCardStatus_Processing && this->cur_gc_status > GameCardStatus_Processing) - { - brls::Application::notify("tasks/notifications/gamecard_status_updated"_i18n); - } else - if (this->cur_gc_status == GameCardStatus_NotInserted) - { - brls::Application::notify("tasks/notifications/gamecard_ejected"_i18n); - } - } else { - this->first_notification = false; - } - - /* Update previous gamecard status. */ - this->prev_gc_status = this->cur_gc_status; - - /* Fire task event. */ - this->gc_status_event.fire(this->cur_gc_status); - } - } - - /* Title task. */ - - TitleTask::TitleTask() : brls::RepeatingTask(NXDT_TASK_INTERVAL) - { - /* Get system metadata entries. */ - this->PopulateApplicationMetadataVector(true); - - /* Get user metadata entries. */ - this->PopulateApplicationMetadataVector(false); - - /* Start task. */ - brls::RepeatingTask::start(); - LOG_MSG_DEBUG("Title task started."); - } - - TitleTask::~TitleTask() - { - /* Clear application metadata vectors. */ - this->system_metadata.clear(); - this->user_metadata.clear(); - - LOG_MSG_DEBUG("Title task stopped."); - } - - void TitleTask::run(retro_time_t current_time) - { - brls::RepeatingTask::run(current_time); - - if (titleIsGameCardInfoUpdated()) - { - LOG_MSG_DEBUG("Title info updated."); - //brls::Application::notify("tasks/notifications/user_titles"_i18n); - - /* Update user metadata vector. */ - this->PopulateApplicationMetadataVector(false); - - /* Fire task event. */ - this->user_title_event.fire(this->user_metadata); - } - } - - const TitleApplicationMetadataVector& TitleTask::GetApplicationMetadata(bool is_system) - { - return (is_system ? this->system_metadata : this->user_metadata); - } - - void TitleTask::PopulateApplicationMetadataVector(bool is_system) - { - TitleApplicationMetadata **app_metadata = nullptr; - u32 app_metadata_count = 0; - - /* Get pointer to output vector. */ - TitleApplicationMetadataVector& vector = (is_system ? this->system_metadata : this->user_metadata); - vector.clear(); - - /* Get application metadata entries. */ - app_metadata = titleGetApplicationMetadataEntries(is_system, &app_metadata_count); - if (app_metadata) - { - /* Fill output vector. */ - for(u32 i = 0; i < app_metadata_count; i++) vector.push_back(app_metadata[i]); - - /* Free application metadata array. */ - free(app_metadata); - } - - LOG_MSG_DEBUG("Retrieved %u %s metadata %s.", app_metadata_count, is_system ? "system" : "user", app_metadata_count == 1 ? "entry" : "entries"); - } - - /* USB Mass Storage task. */ - - UmsTask::UmsTask() : brls::RepeatingTask(NXDT_TASK_INTERVAL) - { - brls::RepeatingTask::start(); - LOG_MSG_DEBUG("UMS task started."); - } - - UmsTask::~UmsTask() - { - /* Clear UMS device vector. */ - this->ums_devices_vector.clear(); - - /* Free UMS devices buffer. */ - if (this->ums_devices) free(this->ums_devices); - - LOG_MSG_DEBUG("UMS task stopped."); - } - - void UmsTask::run(retro_time_t current_time) - { - brls::RepeatingTask::run(current_time); - - if (umsIsDeviceInfoUpdated()) - { - LOG_MSG_DEBUG("UMS device info updated."); - brls::Application::notify("tasks/notifications/ums_device"_i18n); - - /* Update UMS device vector. */ - this->PopulateUmsDeviceVector(); - - /* Fire task event. */ - this->ums_event.fire(this->ums_devices_vector); - } - } - - const UmsDeviceVector& UmsTask::GetUmsDevices(void) - { - return this->ums_devices_vector; - } - - void UmsTask::PopulateUmsDeviceVector(void) - { - /* Clear UMS device vector. */ - this->ums_devices_vector.clear(); - - /* Free UMS devices buffer. */ - if (this->ums_devices) free(this->ums_devices); - - /* Reset UMS devices counter. */ - this->ums_devices_count = 0; - - /* Get UMS devices. */ - this->ums_devices = umsGetDevices(&(this->ums_devices_count)); - if (this->ums_devices) - { - /* Fill UMS device vector. */ - for(u32 i = 0; i < this->ums_devices_count; i++) - { - const UsbHsFsDevice *cur_ums_device = &(this->ums_devices[i]); - int name_len = static_cast(strlen(cur_ums_device->name) - 1); - std::string ums_info{}; - - if (cur_ums_device->product_name[0]) - { - ums_info = fmt::format("{1:.{0}} ({2}, LUN #{3}, FS#{4}, {5})", name_len, cur_ums_device->name, cur_ums_device->product_name, cur_ums_device->lun, cur_ums_device->fs_idx, LIBUSBHSFS_FS_TYPE_STR(cur_ums_device->fs_type)); - } else { - ums_info = fmt::format("{1:.{0}} (LUN #{2}, FS#{3}, {4})", name_len, cur_ums_device->name, cur_ums_device->lun, cur_ums_device->fs_idx, LIBUSBHSFS_FS_TYPE_STR(cur_ums_device->fs_type)); - } - - this->ums_devices_vector.push_back(std::make_pair(cur_ums_device, ums_info)); - } - } - - LOG_MSG_DEBUG("Retrieved info for %u UMS %s.", this->ums_devices_count, this->ums_devices_count == 1 ? "device" : "devices"); - } - - /* USB host device connection task. */ - - UsbHostTask::UsbHostTask() : brls::RepeatingTask(NXDT_TASK_INTERVAL) - { - brls::RepeatingTask::start(); - LOG_MSG_DEBUG("USB host task started."); - } - - UsbHostTask::~UsbHostTask() - { - LOG_MSG_DEBUG("USB host task stopped."); - } - - void UsbHostTask::run(retro_time_t current_time) - { - brls::RepeatingTask::run(current_time); - - this->cur_usb_host_speed = static_cast(usbIsReady()); - if (this->cur_usb_host_speed != this->prev_usb_host_speed) - { - LOG_MSG_DEBUG("USB host speed changed: %u.", this->cur_usb_host_speed); - brls::Application::notify(this->cur_usb_host_speed ? "tasks/notifications/usb_host_connected"_i18n : "tasks/notifications/usb_host_disconnected"_i18n); - - /* Update previous USB host speed. */ - this->prev_usb_host_speed = this->cur_usb_host_speed; - - /* Fire task event. */ - this->usb_host_event.fire(this->cur_usb_host_speed); - } - } - - const UsbHostSpeed& UsbHostTask::GetUsbHostSpeed(void) - { - return this->cur_usb_host_speed; - } -} diff --git a/source/gamecard_image_dump_task.cpp b/source/tasks/gamecard_image_dump_task.cpp similarity index 98% rename from source/gamecard_image_dump_task.cpp rename to source/tasks/gamecard_image_dump_task.cpp index 240e568..c91e78b 100644 --- a/source/gamecard_image_dump_task.cpp +++ b/source/tasks/gamecard_image_dump_task.cpp @@ -19,10 +19,10 @@ * along with this program. If not, see . */ -#include +#include +#include +#include #include -#include -#include namespace i18n = brls::i18n; /* For getStr(). */ using namespace i18n::literals; /* For _i18n. */ diff --git a/source/tasks/gamecard_status_task.cpp b/source/tasks/gamecard_status_task.cpp new file mode 100644 index 0000000..1145767 --- /dev/null +++ b/source/tasks/gamecard_status_task.cpp @@ -0,0 +1,75 @@ +/* + * gamecard_status_task.cpp + * + * Copyright (c) 2020-2024, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nxdumptool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +using namespace brls::i18n::literals; /* For _i18n. */ + +namespace nxdt::tasks +{ + GameCardStatusTask::GameCardStatusTask() : brls::RepeatingTask(REPEATING_TASK_INTERVAL) + { + brls::RepeatingTask::start(); + LOG_MSG_DEBUG("Gamecard task started."); + + this->first_notification = (gamecardGetStatus() >= GameCardStatus_Processing); + } + + GameCardStatusTask::~GameCardStatusTask() + { + LOG_MSG_DEBUG("Gamecard task stopped."); + } + + void GameCardStatusTask::run(retro_time_t current_time) + { + brls::RepeatingTask::run(current_time); + + this->cur_gc_status = static_cast(gamecardGetStatus()); + if (this->cur_gc_status != this->prev_gc_status) + { + LOG_MSG_DEBUG("Gamecard status change triggered: %u.", this->cur_gc_status); + + if (!this->first_notification) + { + if (this->prev_gc_status == GameCardStatus_NotInserted && this->cur_gc_status == GameCardStatus_Processing) + { + brls::Application::notify("gamecard_tab/error_frame/processing"_i18n); + } else + if (this->prev_gc_status == GameCardStatus_Processing && this->cur_gc_status > GameCardStatus_Processing) + { + brls::Application::notify("tasks/notifications/gamecard_status_updated"_i18n); + } else + if (this->cur_gc_status == GameCardStatus_NotInserted) + { + brls::Application::notify("tasks/notifications/gamecard_ejected"_i18n); + } + } else { + this->first_notification = false; + } + + /* Update previous gamecard status. */ + this->prev_gc_status = this->cur_gc_status; + + /* Fire task event. */ + this->gc_status_event.fire(this->cur_gc_status); + } + } +} diff --git a/source/tasks/status_info_task.cpp b/source/tasks/status_info_task.cpp new file mode 100644 index 0000000..edd1cc5 --- /dev/null +++ b/source/tasks/status_info_task.cpp @@ -0,0 +1,77 @@ +/* + * status_info_task.cpp + * + * Copyright (c) 2020-2024, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nxdumptool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +namespace nxdt::tasks +{ + StatusInfoTask::StatusInfoTask() : brls::RepeatingTask(REPEATING_TASK_INTERVAL) + { + brls::RepeatingTask::start(); + LOG_MSG_DEBUG("Status info task started."); + } + + StatusInfoTask::~StatusInfoTask() + { + LOG_MSG_DEBUG("Status info task stopped."); + } + + bool StatusInfoTask::IsInternetConnectionAvailable(void) + { + return this->status_info_data.connected; + } + + void StatusInfoTask::run(retro_time_t current_time) + { + brls::RepeatingTask::run(current_time); + + StatusInfoData *status_info_data = &(this->status_info_data); + + /* Get current time. */ + time_t unix_time = time(nullptr); + localtime_r(&unix_time, &(status_info_data->timeinfo)); + + /* Get battery stats. */ + psmGetBatteryChargePercentage(&(status_info_data->charge_percentage)); + psmGetChargerType(&(status_info_data->charger_type)); + + /* Get network connection status. */ + u32 signal_strength = 0; + NifmInternetConnectionStatus connection_status{}; + char *ip_addr = nullptr; + + status_info_data->connected = false; + + Result rc = nifmGetInternetConnectionStatus(&(status_info_data->connection_type), &signal_strength, &connection_status); + if (R_SUCCEEDED(rc) && status_info_data->connection_type && connection_status == NifmInternetConnectionStatus_Connected) + { + status_info_data->connected = true; + + struct in_addr addr = { .s_addr = INADDR_NONE }; + nifmGetCurrentIpAddress(&(addr.s_addr)); + + if (addr.s_addr != INADDR_NONE && (ip_addr = inet_ntoa(addr))) snprintf(status_info_data->ip_addr, MAX_ELEMENTS(status_info_data->ip_addr), "%s", ip_addr); + } + + /* Fire task event. */ + this->status_info_event.fire(this->status_info_data); + } +} diff --git a/source/tasks/title_metadata_task.cpp b/source/tasks/title_metadata_task.cpp new file mode 100644 index 0000000..3df6f46 --- /dev/null +++ b/source/tasks/title_metadata_task.cpp @@ -0,0 +1,94 @@ +/* + * title_metadata_task.cpp + * + * Copyright (c) 2020-2024, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nxdumptool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +using namespace brls::i18n::literals; /* For _i18n. */ + +namespace nxdt::tasks +{ + TitleMetadataTask::TitleMetadataTask() : brls::RepeatingTask(REPEATING_TASK_INTERVAL) + { + /* Get system metadata entries. */ + this->PopulateApplicationMetadataVector(true); + + /* Get user metadata entries. */ + this->PopulateApplicationMetadataVector(false); + + /* Start task. */ + brls::RepeatingTask::start(); + LOG_MSG_DEBUG("Title metadata task started."); + } + + TitleMetadataTask::~TitleMetadataTask() + { + /* Clear application metadata vectors. */ + this->system_metadata.clear(); + this->user_metadata.clear(); + + LOG_MSG_DEBUG("Title metadata task stopped."); + } + + void TitleMetadataTask::run(retro_time_t current_time) + { + brls::RepeatingTask::run(current_time); + + if (titleIsGameCardInfoUpdated()) + { + LOG_MSG_DEBUG("Title info updated."); + //brls::Application::notify("tasks/notifications/user_titles"_i18n); + + /* Update user metadata vector. */ + this->PopulateApplicationMetadataVector(false); + + /* Fire task event. */ + this->user_title_event.fire(this->user_metadata); + } + } + + const TitleApplicationMetadataVector& TitleMetadataTask::GetApplicationMetadata(bool is_system) + { + return (is_system ? this->system_metadata : this->user_metadata); + } + + void TitleMetadataTask::PopulateApplicationMetadataVector(bool is_system) + { + TitleApplicationMetadata **app_metadata = nullptr; + u32 app_metadata_count = 0; + + /* Get pointer to output vector. */ + TitleApplicationMetadataVector& vector = (is_system ? this->system_metadata : this->user_metadata); + vector.clear(); + + /* Get application metadata entries. */ + app_metadata = titleGetApplicationMetadataEntries(is_system, &app_metadata_count); + if (app_metadata) + { + /* Fill output vector. */ + for(u32 i = 0; i < app_metadata_count; i++) vector.push_back(app_metadata[i]); + + /* Free application metadata array. */ + free(app_metadata); + } + + LOG_MSG_DEBUG("Retrieved %u %s metadata %s.", app_metadata_count, is_system ? "system" : "user", app_metadata_count == 1 ? "entry" : "entries"); + } +} diff --git a/source/tasks/ums_task.cpp b/source/tasks/ums_task.cpp new file mode 100644 index 0000000..29a69c5 --- /dev/null +++ b/source/tasks/ums_task.cpp @@ -0,0 +1,102 @@ +/* + * ums_task.cpp + * + * Copyright (c) 2020-2024, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nxdumptool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +using namespace brls::i18n::literals; /* For _i18n. */ + +namespace nxdt::tasks +{ + UmsTask::UmsTask() : brls::RepeatingTask(REPEATING_TASK_INTERVAL) + { + brls::RepeatingTask::start(); + LOG_MSG_DEBUG("UMS task started."); + } + + UmsTask::~UmsTask() + { + /* Clear UMS device vector. */ + this->ums_devices_vector.clear(); + + /* Free UMS devices buffer. */ + if (this->ums_devices) free(this->ums_devices); + + LOG_MSG_DEBUG("UMS task stopped."); + } + + void UmsTask::run(retro_time_t current_time) + { + brls::RepeatingTask::run(current_time); + + if (umsIsDeviceInfoUpdated()) + { + LOG_MSG_DEBUG("UMS device info updated."); + brls::Application::notify("tasks/notifications/ums_device"_i18n); + + /* Update UMS device vector. */ + this->PopulateUmsDeviceVector(); + + /* Fire task event. */ + this->ums_event.fire(this->ums_devices_vector); + } + } + + const UmsDeviceVector& UmsTask::GetUmsDevices(void) + { + return this->ums_devices_vector; + } + + void UmsTask::PopulateUmsDeviceVector(void) + { + /* Clear UMS device vector. */ + this->ums_devices_vector.clear(); + + /* Free UMS devices buffer. */ + if (this->ums_devices) free(this->ums_devices); + + /* Reset UMS devices counter. */ + this->ums_devices_count = 0; + + /* Get UMS devices. */ + this->ums_devices = umsGetDevices(&(this->ums_devices_count)); + if (this->ums_devices) + { + /* Fill UMS device vector. */ + for(u32 i = 0; i < this->ums_devices_count; i++) + { + const UsbHsFsDevice *cur_ums_device = &(this->ums_devices[i]); + int name_len = static_cast(strlen(cur_ums_device->name) - 1); + std::string ums_info{}; + + if (cur_ums_device->product_name[0]) + { + ums_info = fmt::format("{1:.{0}} ({2}, LUN #{3}, FS#{4}, {5})", name_len, cur_ums_device->name, cur_ums_device->product_name, cur_ums_device->lun, cur_ums_device->fs_idx, LIBUSBHSFS_FS_TYPE_STR(cur_ums_device->fs_type)); + } else { + ums_info = fmt::format("{1:.{0}} (LUN #{2}, FS#{3}, {4})", name_len, cur_ums_device->name, cur_ums_device->lun, cur_ums_device->fs_idx, LIBUSBHSFS_FS_TYPE_STR(cur_ums_device->fs_type)); + } + + this->ums_devices_vector.push_back(std::make_pair(cur_ums_device, ums_info)); + } + } + + LOG_MSG_DEBUG("Retrieved info for %u UMS %s.", this->ums_devices_count, this->ums_devices_count == 1 ? "device" : "devices"); + } +} diff --git a/source/tasks/usb_host_task.cpp b/source/tasks/usb_host_task.cpp new file mode 100644 index 0000000..19f9a7b --- /dev/null +++ b/source/tasks/usb_host_task.cpp @@ -0,0 +1,61 @@ +/* + * usb_host_task.cpp + * + * Copyright (c) 2020-2024, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nxdumptool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +using namespace brls::i18n::literals; /* For _i18n. */ + +namespace nxdt::tasks +{ + UsbHostTask::UsbHostTask() : brls::RepeatingTask(REPEATING_TASK_INTERVAL) + { + brls::RepeatingTask::start(); + LOG_MSG_DEBUG("USB host task started."); + } + + UsbHostTask::~UsbHostTask() + { + LOG_MSG_DEBUG("USB host task stopped."); + } + + void UsbHostTask::run(retro_time_t current_time) + { + brls::RepeatingTask::run(current_time); + + this->cur_usb_host_speed = static_cast(usbIsReady()); + if (this->cur_usb_host_speed != this->prev_usb_host_speed) + { + LOG_MSG_DEBUG("USB host speed changed: %u.", this->cur_usb_host_speed); + brls::Application::notify(this->cur_usb_host_speed ? "tasks/notifications/usb_host_connected"_i18n : "tasks/notifications/usb_host_disconnected"_i18n); + + /* Update previous USB host speed. */ + this->prev_usb_host_speed = this->cur_usb_host_speed; + + /* Fire task event. */ + this->usb_host_event.fire(this->cur_usb_host_speed); + } + } + + const UsbHostSpeed& UsbHostTask::GetUsbHostSpeed(void) + { + return this->cur_usb_host_speed; + } +} diff --git a/source/exception_handler.cpp b/source/utils/exception_handler.cpp similarity index 99% rename from source/exception_handler.cpp rename to source/utils/exception_handler.cpp index 9a0ca54..4be6f1b 100644 --- a/source/exception_handler.cpp +++ b/source/utils/exception_handler.cpp @@ -21,7 +21,7 @@ * along with this program. If not, see . */ -#include +#include #include /* Helper macros. */ diff --git a/source/file_writer.cpp b/source/utils/file_writer.cpp similarity index 99% rename from source/file_writer.cpp rename to source/utils/file_writer.cpp index 181f205..e9ddd70 100644 --- a/source/file_writer.cpp +++ b/source/utils/file_writer.cpp @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -#include +#include namespace i18n = brls::i18n; /* For getStr(). */ using namespace i18n::literals; /* For _i18n. */ diff --git a/source/about_tab.cpp b/source/views/about_tab.cpp similarity index 98% rename from source/about_tab.cpp rename to source/views/about_tab.cpp index 508563f..3ed621d 100644 --- a/source/about_tab.cpp +++ b/source/views/about_tab.cpp @@ -19,8 +19,8 @@ * along with this program. If not, see . */ -#include -#include +#include +#include #define LOGO_SIZE 256 diff --git a/source/data_transfer_progress_display.cpp b/source/views/data_transfer_progress_display.cpp similarity index 98% rename from source/data_transfer_progress_display.cpp rename to source/views/data_transfer_progress_display.cpp index a3c4482..0604ccd 100644 --- a/source/data_transfer_progress_display.cpp +++ b/source/views/data_transfer_progress_display.cpp @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -#include +#include namespace nxdt::views { diff --git a/source/dump_options_frame.cpp b/source/views/dump_options_frame.cpp similarity index 99% rename from source/dump_options_frame.cpp rename to source/views/dump_options_frame.cpp index ac63b49..d25faa4 100644 --- a/source/dump_options_frame.cpp +++ b/source/views/dump_options_frame.cpp @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -#include +#include namespace i18n = brls::i18n; /* For getStr(). */ using namespace i18n::literals; /* For _i18n. */ diff --git a/source/error_frame.cpp b/source/views/error_frame.cpp similarity index 98% rename from source/error_frame.cpp rename to source/views/error_frame.cpp index 64859fa..337a674 100644 --- a/source/error_frame.cpp +++ b/source/views/error_frame.cpp @@ -21,8 +21,8 @@ * along with this program. If not, see . */ -#include -#include +#include +#include namespace nxdt::views { diff --git a/source/gamecard_image_dump_options_frame.cpp b/source/views/gamecard_image_dump_options_frame.cpp similarity index 94% rename from source/gamecard_image_dump_options_frame.cpp rename to source/views/gamecard_image_dump_options_frame.cpp index 8cbc6e0..14a49ba 100644 --- a/source/gamecard_image_dump_options_frame.cpp +++ b/source/views/gamecard_image_dump_options_frame.cpp @@ -19,8 +19,8 @@ * along with this program. If not, see . */ -#include -#include +#include +#include namespace i18n = brls::i18n; /* For getStr(). */ using namespace i18n::literals; /* For _i18n. */ @@ -43,7 +43,7 @@ namespace nxdt::views DumpOptionsFrame(root_view, "gamecard_tab/list/dump_card_image/label"_i18n, std::string(GAMECARD_SUBDIR), raw_filename) { /* Subscribe to the gamecard task event. */ - this->gc_task_sub = this->root_view->RegisterGameCardTaskListener([this](const GameCardStatus& gc_status) { + this->gc_task_sub = this->root_view->RegisterGameCardStatusTaskListener([this](const GameCardStatus& gc_status) { /* Realistically speaking, this should always match a NotInserted status, but it's always better to be safe than sorry. */ if (gc_status != GameCardStatus_NotInserted) return; @@ -113,6 +113,6 @@ namespace nxdt::views this->gc_ejected_event.unsubscribeAll(); /* Unregister gamecard task listener. */ - this->root_view->UnregisterGameCardTaskListener(this->gc_task_sub); + this->root_view->UnregisterGameCardStatusTaskListener(this->gc_task_sub); } } diff --git a/source/gamecard_tab.cpp b/source/views/gamecard_tab.cpp similarity index 58% rename from source/gamecard_tab.cpp rename to source/views/gamecard_tab.cpp index 295fde5..e1c13e6 100644 --- a/source/gamecard_tab.cpp +++ b/source/views/gamecard_tab.cpp @@ -19,10 +19,17 @@ * along with this program. If not, see . */ -#include -#include -#include -#include +#include +#include +#include +#include +#include + +#define GAMECARD_TAB_TABLE_PROPERTY(name) brls::TableRow *name = properties_table->addRow(brls::TableRowType::BODY, i18n::getStr("gamecard_tab/list/properties_table/" #name)) + +#define GAMECARD_TAB_LISTITEM_ELEMENT(name, ...) \ +brls::ListItem *name = new brls::ListItem(i18n::getStr("gamecard_tab/list/" #name "/label"), i18n::getStr("gamecard_tab/list/" #name "/description", ##__VA_ARGS__)); \ +this->list->addView(name) namespace i18n = brls::i18n; /* For getStr(). */ using namespace i18n::literals; /* For _i18n. */ @@ -36,7 +43,7 @@ namespace nxdt::views this->list->setMarginBottom(20); /* Subscribe to the gamecard status event. */ - this->gc_status_task_sub = this->root_view->RegisterGameCardTaskListener([this](GameCardStatus gc_status) { + this->gc_status_task_sub = this->root_view->RegisterGameCardStatusTaskListener([this](GameCardStatus gc_status) { /* Process gamecard status. */ this->ProcessGameCardStatus(gc_status); }); @@ -48,7 +55,7 @@ namespace nxdt::views GameCardTab::~GameCardTab() { /* Unregister task listener. */ - this->root_view->UnregisterGameCardTaskListener(this->gc_status_task_sub); + this->root_view->UnregisterGameCardStatusTaskListener(this->gc_status_task_sub); } void GameCardTab::ProcessGameCardStatus(GameCardStatus gc_status) @@ -85,41 +92,8 @@ namespace nxdt::views this->gc_status = gc_status; } - std::string GameCardTab::GetFormattedSizeString(GameCardSizeFunc func) - { - u64 size = 0; - char strbuf[0x40] = {0}; - - func(&size); - utilsGenerateFormattedSizeString(static_cast(size), strbuf, sizeof(strbuf)); - - return std::string(strbuf); - } - - std::string GameCardTab::GetCardIdSetString(FsGameCardIdSet *card_id_set) - { - char card_id_set_str[0x20] = {0}; - - utilsGenerateHexString(card_id_set_str, sizeof(card_id_set_str), &(card_id_set->id1), sizeof(card_id_set->id1), true); - - card_id_set_str[8] = ' '; - utilsGenerateHexString(card_id_set_str + 9, sizeof(card_id_set_str) - 9, &(card_id_set->id2), sizeof(card_id_set->id2), true); - - card_id_set_str[17] = ' '; - utilsGenerateHexString(card_id_set_str + 18, sizeof(card_id_set_str) - 18, &(card_id_set->id3), sizeof(card_id_set->id3), true); - - return std::string(card_id_set_str); - } - void GameCardTab::PopulateList(void) { - TitleGameCardApplicationMetadataEntry *gc_app_metadata = nullptr; - u32 gc_app_metadata_count = 0; - GameCardHeader card_header = {0}; - GameCardInfo card_info = {0}; - FsGameCardIdSet card_id_set = {0}; - char *raw_filename = nullptr; - bool update_focused_view = this->IsListItemFocused(); int focus_stack_index = this->GetFocusStackViewIndex(); @@ -127,83 +101,147 @@ namespace nxdt::views this->list->clear(); this->list->invalidate(true); + /* Generate and store raw filenames. */ + this->GenerateRawFilenames(); + /* Information about how to handle HOS launch errors. */ /* TODO: remove this if we ever find a way to fix this issue. */ FocusableLabel *launch_error_info = new FocusableLabel(true, false, brls::LabelStyle::DESCRIPTION, "gamecard_tab/list/launch_error_info"_i18n, true); launch_error_info->setHorizontalAlign(NVG_ALIGN_CENTER); this->list->addView(launch_error_info); + /* Add gamecard application metadata information. */ + this->AddApplicationMetadataItems(); + + /* Add gamecard properties table. */ + this->AddPropertiesTable(); + + /* Add ListItem elements. */ + this->list->addView(new brls::Header("gamecard_tab/list/dump_options"_i18n)); + + GAMECARD_TAB_LISTITEM_ELEMENT(dump_card_image); + + this->list->addView(new brls::ListItemGroupSpacing(true)); + + brls::Label *advanced_disclaimer = new brls::Label(brls::LabelStyle::DESCRIPTION, "gamecard_tab/list/advanced_disclaimer"_i18n, true); + advanced_disclaimer->setHorizontalAlign(NVG_ALIGN_CENTER); + this->list->addView(advanced_disclaimer); + + GAMECARD_TAB_LISTITEM_ELEMENT(dump_initial_data); + GAMECARD_TAB_LISTITEM_ELEMENT(dump_certificate, GAMECARD_CERT_OFFSET / GAMECARD_PAGE_SIZE); + GAMECARD_TAB_LISTITEM_ELEMENT(dump_card_id_set); + GAMECARD_TAB_LISTITEM_ELEMENT(dump_card_uid); + GAMECARD_TAB_LISTITEM_ELEMENT(dump_header, 0); + GAMECARD_TAB_LISTITEM_ELEMENT(dump_plaintext_cardinfo); + GAMECARD_TAB_LISTITEM_ELEMENT(dump_specific_data); + GAMECARD_TAB_LISTITEM_ELEMENT(dump_hfs_partitions); + GAMECARD_TAB_LISTITEM_ELEMENT(browse_hfs_partitions); + GAMECARD_TAB_LISTITEM_ELEMENT(dump_lafw); + + /* Set ListItem callbacks. */ + dump_card_image->getClickEvent()->subscribe([this](brls::View *view) { + /* Display gamecard image dump options. */ + std::string& raw_filename = (configGetInteger("naming_convention") == TitleNamingConvention_Full ? raw_filename_full : raw_filename_id_only); + brls::Application::pushView(new GameCardImageDumpOptionsFrame(this->root_view, raw_filename), brls::ViewAnimation::SLIDE_LEFT); + }); + + /* Update focus stack, if needed. */ + if (focus_stack_index > -1) this->UpdateFocusStackViewAtIndex(focus_stack_index, this->GetListFirstFocusableChild()); + + /* Switch to the list view. */ + this->list->invalidate(true); + this->SwitchLayerView(false, update_focused_view, focus_stack_index < 0); + } + + void GameCardTab::AddApplicationMetadataItems(void) + { + TitleGameCardApplicationMetadataEntry *gc_app_metadata = nullptr; + u32 gc_app_metadata_count = 0; + /* Retrieve gamecard application metadata. */ gc_app_metadata = titleGetGameCardApplicationMetadataEntries(&gc_app_metadata_count); - if (gc_app_metadata) + if (!gc_app_metadata) return; + + ON_SCOPE_EXIT { free(gc_app_metadata); }; + + /* Display the applications that are part of the inserted gamecard. */ + this->list->addView(new brls::Header("gamecard_tab/list/user_titles/header"_i18n)); + + /* Add information about how to work with individual user titles. */ + brls::Label *user_titles_info = new brls::Label(brls::LabelStyle::DESCRIPTION, i18n::getStr("gamecard_tab/list/user_titles/info"_i18n, \ + "root_view/tabs/user_titles"_i18n), true); + user_titles_info->setHorizontalAlign(NVG_ALIGN_CENTER); + this->list->addView(user_titles_info); + + /* Add gamecard application metadata items. */ + for(u32 i = 0; i < gc_app_metadata_count; i++) { - /* Display the applications that are part of the inserted gamecard. */ - this->list->addView(new brls::Header("gamecard_tab/list/user_titles/header"_i18n)); + TitleGameCardApplicationMetadataEntry *cur_gc_app_metadata = &(gc_app_metadata[i]); - /* Information about how to handle user titles. */ - brls::Label *user_titles_info = new brls::Label(brls::LabelStyle::DESCRIPTION, i18n::getStr("gamecard_tab/list/user_titles/info"_i18n, \ - "root_view/tabs/user_titles"_i18n), true); - user_titles_info->setHorizontalAlign(NVG_ALIGN_CENTER); - this->list->addView(user_titles_info); + /* Create item. */ + TitlesTabItem *title = new TitlesTabItem(cur_gc_app_metadata->app_metadata, false, false); - /* Populate list. */ - for(u32 i = 0; i < gc_app_metadata_count; i++) + /* Unregister A button action. */ + title->unregisterAction(brls::Key::A); + + /* Set version information as the item sublabel instead of the title author. */ + std::string sublabel = fmt::format("v{}", cur_gc_app_metadata->version.value); + + if (cur_gc_app_metadata->display_version[0]) sublabel += fmt::format(" ({})", cur_gc_app_metadata->display_version); + + if (cur_gc_app_metadata->dlc_count > 1) { - TitleGameCardApplicationMetadataEntry *cur_gc_app_metadata = &(gc_app_metadata[i]); - - /* Create item. */ - TitlesTabItem *title = new TitlesTabItem(cur_gc_app_metadata->app_metadata, false, false); - - /* Unregister A button action. */ - title->unregisterAction(brls::Key::A); - - /* Set version information as the item sublabel instead of the title author. */ - std::string sublabel{}; - if (cur_gc_app_metadata->display_version[0]) - { - sublabel = fmt::format("v{} ({})", cur_gc_app_metadata->version.value, cur_gc_app_metadata->display_version); - } else { - sublabel = fmt::format("v{}", cur_gc_app_metadata->version.value); - } - - title->setSubLabel(sublabel); - - /* Add view to item list. */ - this->list->addView(title); + sublabel += fmt::format(" (+{} DLCs)", cur_gc_app_metadata->dlc_count); + } else + if (cur_gc_app_metadata->dlc_count == 1) + { + sublabel += " (+1 DLC)"; } - /* Free gamecard application metadata array. */ - free(gc_app_metadata); + title->setSubLabel(sublabel); + + /* Add view to item list. */ + this->list->addView(title); } + } + + void GameCardTab::AddPropertiesTable(void) + { + GameCardHeader card_header{}; + GameCardInfo card_info{}; + FsGameCardIdSet card_id_set_data{}; + + /* Get gamecard data. */ + gamecardGetHeader(&card_header); + gamecardGetPlaintextCardInfoArea(&card_info); + gamecardGetCardIdSet(&card_id_set_data); /* Populate gamecard properties table. */ this->list->addView(new brls::Header("gamecard_tab/list/properties_table/header"_i18n)); FocusableTable *properties_table = new FocusableTable(true, false); - brls::TableRow *capacity = properties_table->addRow(brls::TableRowType::BODY, "gamecard_tab/list/properties_table/capacity"_i18n); - brls::TableRow *total_size = properties_table->addRow(brls::TableRowType::BODY, "gamecard_tab/list/properties_table/total_size"_i18n); - brls::TableRow *trimmed_size = properties_table->addRow(brls::TableRowType::BODY, "gamecard_tab/list/properties_table/trimmed_size"_i18n); - brls::TableRow *update_version = properties_table->addRow(brls::TableRowType::BODY, "gamecard_tab/list/properties_table/update_version"_i18n); - brls::TableRow *lafw_version = properties_table->addRow(brls::TableRowType::BODY, "gamecard_tab/list/properties_table/lafw_version"_i18n); - brls::TableRow *sdk_version = properties_table->addRow(brls::TableRowType::BODY, "gamecard_tab/list/properties_table/sdk_version"_i18n); - brls::TableRow *compatibility_type = properties_table->addRow(brls::TableRowType::BODY, "gamecard_tab/list/properties_table/compatibility_type"_i18n); - brls::TableRow *package_id = properties_table->addRow(brls::TableRowType::BODY, "gamecard_tab/list/properties_table/package_id"_i18n); - brls::TableRow *card_id_set_row = properties_table->addRow(brls::TableRowType::BODY, "gamecard_tab/list/properties_table/card_id_set"_i18n); + GAMECARD_TAB_TABLE_PROPERTY(capacity); + GAMECARD_TAB_TABLE_PROPERTY(total_size); + GAMECARD_TAB_TABLE_PROPERTY(trimmed_size); + GAMECARD_TAB_TABLE_PROPERTY(update_version); + GAMECARD_TAB_TABLE_PROPERTY(lafw_version); + GAMECARD_TAB_TABLE_PROPERTY(sdk_version); + GAMECARD_TAB_TABLE_PROPERTY(compatibility_type); + GAMECARD_TAB_TABLE_PROPERTY(package_id); + GAMECARD_TAB_TABLE_PROPERTY(card_id_set); + /* Set table row values. */ capacity->setValue(this->GetFormattedSizeString(&gamecardGetRomCapacity)); total_size->setValue(this->GetFormattedSizeString(&gamecardGetTotalSize)); trimmed_size->setValue(this->GetFormattedSizeString(&gamecardGetTrimmedSize)); - gamecardGetHeader(&card_header); - gamecardGetPlaintextCardInfoArea(&card_info); - gamecardGetCardIdSet(&card_id_set); - const SystemVersion upp_version = card_info.upp_version.system_version; - /* TODO: move somewhere else? */ if (upp_version.major == 0 && upp_version.minor == 0) { - std::string upp_version_display = ""; + /* Nintendo didn't start matching SystemVersion fields to the system version displayed in the Settings menu until HOS 3.0.0. */ + /* So we need to manually handle those exceptions. */ + std::string upp_version_display{}; switch(upp_version.micro) { @@ -228,38 +266,39 @@ namespace nxdt::views if (upp_version_display != "") { - update_version->setValue(fmt::format("{} ({}.{}.{}-{}) (v{})", upp_version_display, upp_version.major, upp_version.minor, upp_version.micro, \ + update_version->setValue(fmt::format("{} ({}.{}.{}-{}) (v{})", upp_version_display, upp_version.major, upp_version.minor, upp_version.micro, upp_version.relstep, upp_version.value)); } else { - update_version->setValue(fmt::format("{}.{}.{}-{} (v{})", upp_version.major, upp_version.minor, upp_version.micro, \ + update_version->setValue(fmt::format("{}.{}.{}-{} (v{})", upp_version.major, upp_version.minor, upp_version.micro, upp_version.relstep, upp_version.value)); } } else { - update_version->setValue(fmt::format("{}.{}.{}-{}.{} (v{})", upp_version.major, upp_version.minor, upp_version.micro, \ + update_version->setValue(fmt::format("{}.{}.{}-{}.{} (v{})", upp_version.major, upp_version.minor, upp_version.micro, upp_version.major_relstep, upp_version.minor_relstep, upp_version.value)); } - u64 fw_version = card_info.fw_version; + const u64 fw_version = card_info.fw_version; lafw_version->setValue(fmt::format("{} ({})", fw_version, fw_version >= GameCardFwVersion_Count ? "generic/unknown"_i18n : gamecardGetRequiredHosVersionString(fw_version))); const SdkAddOnVersion fw_mode = card_info.fw_mode.sdk_addon_version; sdk_version->setValue(fmt::format("{}.{}.{}-{} (v{})", fw_mode.major, fw_mode.minor, fw_mode.micro, fw_mode.relstep, fw_mode.value)); u8 compat_type = card_info.compatibility_type; - compatibility_type->setValue(fmt::format("{} ({})", \ - compat_type >= GameCardCompatibilityType_Count ? "generic/unknown"_i18n : gamecardGetCompatibilityTypeString(compat_type), \ - compat_type)); + compatibility_type->setValue(fmt::format("{} ({})", + compat_type >= GameCardCompatibilityType_Count ? "generic/unknown"_i18n : gamecardGetCompatibilityTypeString(compat_type), compat_type)); char package_id_str[0x11] = {0}; utilsGenerateHexString(package_id_str, sizeof(package_id_str), card_header.package_id, sizeof(card_header.package_id), true); package_id->setValue(std::string(package_id_str)); - card_id_set_row->setValue(this->GetCardIdSetString(&card_id_set)); + card_id_set->setValue(this->GetCardIdSetString(card_id_set_data)); this->list->addView(properties_table); + } - /* ListItem elements. */ - this->list->addView(new brls::Header("gamecard_tab/list/dump_options"_i18n)); + void GameCardTab::GenerateRawFilenames(void) + { + char *raw_filename = nullptr; raw_filename = titleGenerateGameCardFileName(TitleNamingConvention_Full, TitleFileNameIllegalCharReplaceType_None); this->raw_filename_full = std::string(raw_filename); @@ -270,58 +309,31 @@ namespace nxdt::views if (raw_filename) free(raw_filename); raw_filename = nullptr; + } - brls::ListItem *dump_card_image = new brls::ListItem("gamecard_tab/list/dump_card_image/label"_i18n, "gamecard_tab/list/dump_card_image/description"_i18n); + std::string GameCardTab::GetFormattedSizeString(GameCardSizeFunc func) + { + u64 size = 0; + char strbuf[0x40] = {0}; - dump_card_image->getClickEvent()->subscribe([this](brls::View *view) { - /* Display gamecard image dump options. */ - std::string& raw_filename = (configGetInteger("naming_convention") == TitleNamingConvention_Full ? raw_filename_full : raw_filename_id_only); - brls::Application::pushView(new GameCardImageDumpOptionsFrame(this->root_view, raw_filename), brls::ViewAnimation::SLIDE_LEFT); - }); + func(&size); + utilsGenerateFormattedSizeString(static_cast(size), strbuf, sizeof(strbuf)); - this->list->addView(dump_card_image); + return std::string(strbuf); + } - this->list->addView(new brls::ListItemGroupSpacing(true)); + std::string GameCardTab::GetCardIdSetString(const FsGameCardIdSet& card_id_set) + { + char card_id_set_str[0x20] = {0}; - brls::Label *advanced_disclaimer = new brls::Label(brls::LabelStyle::DESCRIPTION, "gamecard_tab/list/advanced_disclaimer"_i18n, true); - advanced_disclaimer->setHorizontalAlign(NVG_ALIGN_CENTER); - this->list->addView(advanced_disclaimer); + utilsGenerateHexString(card_id_set_str, sizeof(card_id_set_str), &(card_id_set.id1), sizeof(card_id_set.id1), true); - brls::ListItem *dump_initial_data = new brls::ListItem("gamecard_tab/list/dump_initial_data/label"_i18n, "gamecard_tab/list/dump_initial_data/description"_i18n); - this->list->addView(dump_initial_data); + card_id_set_str[8] = ' '; + utilsGenerateHexString(card_id_set_str + 9, sizeof(card_id_set_str) - 9, &(card_id_set.id2), sizeof(card_id_set.id2), true); - brls::ListItem *dump_certificate = new brls::ListItem("gamecard_tab/list/dump_certificate/label"_i18n, i18n::getStr("gamecard_tab/list/dump_certificate/description", GAMECARD_CERT_OFFSET / GAMECARD_PAGE_SIZE)); - this->list->addView(dump_certificate); + card_id_set_str[17] = ' '; + utilsGenerateHexString(card_id_set_str + 18, sizeof(card_id_set_str) - 18, &(card_id_set.id3), sizeof(card_id_set.id3), true); - brls::ListItem *dump_card_id_set = new brls::ListItem("gamecard_tab/list/dump_card_id_set/label"_i18n, "gamecard_tab/list/dump_card_id_set/description"_i18n); - this->list->addView(dump_card_id_set); - - brls::ListItem *dump_card_uid = new brls::ListItem("gamecard_tab/list/dump_card_uid/label"_i18n, "gamecard_tab/list/dump_card_uid/description"_i18n); - this->list->addView(dump_card_uid); - - brls::ListItem *dump_header = new brls::ListItem("gamecard_tab/list/dump_header/label"_i18n, i18n::getStr("gamecard_tab/list/dump_header/description", 0)); - this->list->addView(dump_header); - - brls::ListItem *dump_plaintext_cardinfo = new brls::ListItem("gamecard_tab/list/dump_plaintext_cardinfo/label"_i18n, "gamecard_tab/list/dump_plaintext_cardinfo/description"_i18n); - this->list->addView(dump_plaintext_cardinfo); - - brls::ListItem *dump_specific_data = new brls::ListItem("gamecard_tab/list/dump_specific_data/label"_i18n, "gamecard_tab/list/dump_specific_data/description"_i18n); - this->list->addView(dump_specific_data); - - brls::ListItem *dump_hfs_partitions = new brls::ListItem("gamecard_tab/list/dump_hfs_partitions/label"_i18n, "gamecard_tab/list/dump_hfs_partitions/description"_i18n); - this->list->addView(dump_hfs_partitions); - - brls::ListItem *browse_hfs_partitions = new brls::ListItem("gamecard_tab/list/browse_hfs_partitions/label"_i18n, "gamecard_tab/list/browse_hfs_partitions/description"_i18n); - this->list->addView(browse_hfs_partitions); - - brls::ListItem *dump_lafw = new brls::ListItem("gamecard_tab/list/dump_lafw/label"_i18n, "gamecard_tab/list/dump_lafw/description"_i18n); - this->list->addView(dump_lafw); - - /* Update focus stack, if needed. */ - if (focus_stack_index > -1) this->UpdateFocusStackViewAtIndex(focus_stack_index, this->GetListFirstFocusableChild()); - - /* Switch to the list view. */ - this->list->invalidate(true); - this->SwitchLayerView(false, update_focused_view, focus_stack_index < 0); + return std::string(card_id_set_str); } } diff --git a/source/layered_error_frame.cpp b/source/views/layered_error_frame.cpp similarity index 99% rename from source/layered_error_frame.cpp rename to source/views/layered_error_frame.cpp index db2c14d..cade26a 100644 --- a/source/layered_error_frame.cpp +++ b/source/views/layered_error_frame.cpp @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -#include +#include namespace nxdt::views { diff --git a/source/options_tab.cpp b/source/views/options_tab.cpp similarity index 99% rename from source/options_tab.cpp rename to source/views/options_tab.cpp index 6c31f99..c64fce8 100644 --- a/source/options_tab.cpp +++ b/source/views/options_tab.cpp @@ -19,10 +19,10 @@ * along with this program. If not, see . */ -#include -#include -#include #include +#include +#include +#include namespace i18n = brls::i18n; /* For getStr(). */ using namespace i18n::literals; /* For _i18n. */ diff --git a/source/root_view.cpp b/source/views/root_view.cpp similarity index 97% rename from source/root_view.cpp rename to source/views/root_view.cpp index f063bd1..2e1ba84 100644 --- a/source/root_view.cpp +++ b/source/views/root_view.cpp @@ -19,12 +19,11 @@ * along with this program. If not, see . */ -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace i18n = brls::i18n; /* For getStr(). */ using namespace i18n::literals; /* For _i18n. */ @@ -103,8 +102,8 @@ namespace nxdt::views /* Start background tasks. */ this->status_info_task = new nxdt::tasks::StatusInfoTask(); - this->gc_status_task = new nxdt::tasks::GameCardTask(); - this->title_task = new nxdt::tasks::TitleTask(); + this->gc_status_task = new nxdt::tasks::GameCardStatusTask(); + this->title_metadata_task = new nxdt::tasks::TitleMetadataTask(); this->ums_task = new nxdt::tasks::UmsTask(); this->usb_host_task = new nxdt::tasks::UsbHostTask(); @@ -185,7 +184,7 @@ namespace nxdt::views /* Stop background tasks. */ this->status_info_task->stop(); this->gc_status_task->stop(); - this->title_task->stop(); + this->title_metadata_task->stop(); this->ums_task->stop(); this->usb_host_task->stop(); diff --git a/source/titles_tab.cpp b/source/views/titles_tab.cpp similarity index 96% rename from source/titles_tab.cpp rename to source/views/titles_tab.cpp index cde0249..cd0deb3 100644 --- a/source/titles_tab.cpp +++ b/source/views/titles_tab.cpp @@ -19,9 +19,7 @@ * along with this program. If not, see . */ -#include -#include -#include +#include using namespace brls::i18n::literals; /* For _i18n. */ @@ -89,7 +87,7 @@ namespace nxdt::views /* Subscribe to the title event if this is the user titles tab. */ if (!this->is_system) { - this->title_task_sub = this->root_view->RegisterTitleTaskListener([this](const nxdt::tasks::TitleApplicationMetadataVector& app_metadata) { + this->title_task_sub = this->root_view->RegisterTitleMetadataTaskListener([this](const nxdt::tasks::TitleApplicationMetadataVector& app_metadata) { /* Update list. */ this->PopulateList(app_metadata); }); @@ -99,7 +97,7 @@ namespace nxdt::views TitlesTab::~TitlesTab() { /* Unregister task listener if this is the user titles tab. */ - if (!this->is_system) this->root_view->UnregisterTitleTaskListener(this->title_task_sub); + if (!this->is_system) this->root_view->UnregisterTitleMetadataTaskListener(this->title_task_sub); } void TitlesTab::PopulateList(const nxdt::tasks::TitleApplicationMetadataVector& app_metadata)