diff --git a/.gitignore b/.gitignore index 63d56ab..220bab4 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ JKSV.pfs0 #sometimes I give jksv to people and forget about this. JKSV.zip +JKSV.nro.zip \ No newline at end of file diff --git a/Libraries/FsLib b/Libraries/FsLib index f948cec..30f5674 160000 --- a/Libraries/FsLib +++ b/Libraries/FsLib @@ -1 +1 @@ -Subproject commit f948cecb43c4f1e089442a8c0fd58df7deefb955 +Subproject commit 30f56742733a350a1f4788d6fa2bcf26712ae669 diff --git a/Libraries/SDLLib b/Libraries/SDLLib index fa7d0f4..779fc5b 160000 --- a/Libraries/SDLLib +++ b/Libraries/SDLLib @@ -1 +1 @@ -Subproject commit fa7d0f456c78d7f94b8519260978419b564610b8 +Subproject commit 779fc5bd8aa4782e376fbce3baa146837f7d4825 diff --git a/Makefile b/Makefile index 875af9d..785b013 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,7 @@ ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE # NOTE: For some reason, devkitpro no longer has freetype-config included? Also, using pkg-config causes conflicts with # my local pkg-config and I don't feel like dealing with CMake for all of this right now. CFLAGS := $(INCLUDE) -D__SWITCH__ `sdl2-config --cflags` `curl-config --cflags`\ - -g -Wall -O2 -ffunction-sections -ffast-math -fmax-errors=1 \ + -g -Wall -O3 -ffunction-sections -ffast-math -fmax-errors=1 \ $(ARCH) $(DEFINES) CXXFLAGS:= $(CFLAGS) -fno-rtti -fno-exceptions -std=c++23 @@ -172,11 +172,12 @@ clean: @$(MAKE) -C ./Libraries/SDLLib/SDL clean @rm -fr $(BUILD) $(TARGET).pfs0 $(TARGET).nso $(TARGET).nro $(TARGET).nacp $(TARGET).elf - #--------------------------------------------------------------------------------- send: $(BUILD) @nxlink $(TARGET).nro +#--------------------------------------------------------------------------------- + debug: $(BUILD) @nxlink -s $(TARGET).nro diff --git a/include/JKSV.hpp b/include/JKSV.hpp index f8fbbb5..cc2fe2f 100644 --- a/include/JKSV.hpp +++ b/include/JKSV.hpp @@ -17,7 +17,7 @@ class JKSV /// @brief Returns if initializing was successful and JKSV is running. /// @return True or false. - bool is_running() const; + bool is_running() const noexcept; /// @brief Runs JKSV's update routine. void update(); diff --git a/include/appstates/BaseState.hpp b/include/appstates/BaseState.hpp index 506ef7a..264f013 100644 --- a/include/appstates/BaseState.hpp +++ b/include/appstates/BaseState.hpp @@ -16,6 +16,9 @@ class BaseState /// @brief Every derived class is required to have this function. virtual void update() = 0; + /// @brief Sub update routine. Meant to handle minor background tasks. Not meant for full update routines. + virtual void sub_update() {}; + /// @brief Every derived class is required to have this function. virtual void render() = 0; @@ -45,7 +48,7 @@ class BaseState private: /// @brief Stores whether or not the state is currently active. - bool m_isActive = true; + bool m_isActive{true}; /// @brief Stores whether or not the state has focus. bool m_hasFocus{}; diff --git a/include/appstates/ExtrasMenuState.hpp b/include/appstates/ExtrasMenuState.hpp index 6a252ff..5746ef1 100644 --- a/include/appstates/ExtrasMenuState.hpp +++ b/include/appstates/ExtrasMenuState.hpp @@ -34,4 +34,22 @@ class ExtrasMenuState final : public BaseState /// @brief This function is called when Reinitialize data is selected. void reinitialize_data(); + + /// @brief Opens an SD to SD file browser. + void sd_to_sd_browser(); + + /// @brief Opens the prodinfo-f to sd. + void prodinfof_to_sd(); + + /// @brief Opens the safe partition to SD. + void safe_to_sd(); + + /// @brief Opens the system partition to SD. + void system_to_sd(); + + /// @brief Opens the user partition to SD. + void user_to_sd(); + + /// @brief Terminates a process. + void terminate_process(); }; diff --git a/include/appstates/FileModeState.hpp b/include/appstates/FileModeState.hpp new file mode 100644 index 0000000..a801291 --- /dev/null +++ b/include/appstates/FileModeState.hpp @@ -0,0 +1,160 @@ +#pragma once +#include "StateManager.hpp" +#include "appstates/BaseState.hpp" +#include "fslib.hpp" +#include "sdl.hpp" +#include "ui/ui.hpp" + +#include + +class FileModeState final : public BaseState +{ + public: + /// @brief Constructs a new FileModeState. + FileModeState(std::string_view mountA, std::string_view mountB, int64_t journalSize = 0); + + /// @brief Destructor. Closes the filesystems passed. + ~FileModeState() {}; + + static inline std::shared_ptr create(std::string_view mountA, + std::string_view mountB, + int64_t journalSize = 0) + { + return std::make_shared(mountA, mountB, journalSize); + } + + static inline std::shared_ptr create_and_push(std::string_view mountA, + std::string_view mountB, + int64_t journalSize = 0) + { + auto newState = std::make_shared(mountA, mountB, journalSize); + StateManager::push_state(newState); + return newState; + } + + /// @brief Update override. + void update() override; + + /// @brief Render override. + void render() override; + + /// @brief This thing is a headache without this. + friend class FileOptionState; + + private: + /// @brief These store the mount points to close the filesystems upon construction. + std::string m_mountA; + std::string m_mountB; + + /// @brief These are the actual target paths. + fslib::Path m_pathA{}; + fslib::Path m_pathB{}; + + /// @brief Directory listings for each respective path. + fslib::Directory m_dirA{}; + fslib::Directory m_dirB{}; + + /// @brief Menus for the directory listings. + std::shared_ptr m_dirMenuA{}; + std::shared_ptr m_dirMenuB{}; + + /// @brief Controls which menu/filesystem is currently targetted. + bool m_target{}; + + /// @brief Stores the size for committing data (if needed) to mountA. + int64_t m_journalSize{}; + + /// @brief The beginning Y coord of the dialog. + double m_y{720.0f}; + + /// @brief This is the targetY. Used for the opening and hiding effect. + double m_targetY{91.0f}; + + /// @brief Config scaling for the "transition" + double m_scaling{}; + + /// @brief Stores whether or not the dialog has reached its targetted position. + bool m_inPlace{}; + + /// @brief Frame shared by all instances. + static inline std::shared_ptr sm_frame{}; + + /// @brief This is the render target the browsers are rendered to. + static inline sdl::SharedTexture sm_renderTarget{}; + + /// @brief Stores a pointer to the guide in the bottom-right corner. + static inline const char *sm_controlGuide{}; + + /// @brief Calculated X coordinate of the control guide text. + static inline int sm_controlGuideX{}; + + /// @brief Initializes the members shared by all instances of FileModeState. + void initialize_static_members(); + + /// @brief Creates valid paths with the mounts passed. + void initialize_paths(); + + /// @brief Ensures the menus are allocated and setup properly. + void initialize_menus(); + + /// @brief Loads the current directory listings and menus. + void initialize_directory_menu(const fslib::Path &path, fslib::Directory &directory, ui::Menu &menu); + + /// @brief Updates the dialog's coordinates in the beginning. + void update_y_coord() noexcept; + + /// @brief Starts the dialog hiding process. + void hide_dialog() noexcept; + + /// @brief Returns whether or not the dialog is hidden. + bool is_hidden() noexcept; + + /// @brief Handles changing the current directory or opening the options. + void enter_selected(fslib::Path &path, fslib::Directory &directory, ui::Menu &menu); + + /// @brief Opens the little option pop-up thingy. + void open_option_menu(fslib::Directory &directory, ui::Menu &menu); + + /// @brief Changes the current target/controllable menu. + void change_target() noexcept; + + /// @brief Function executed when '..' is selected. + void up_one_directory(fslib::Path &path, fslib::Directory &directory, ui::Menu &menu); + + /// @brief Appends the entry passed to the path passed and "enters" the directory. + /// @param path Working path. + /// @param directory Working directory. + /// @param menu Working menu. + /// @param entry Target entry. + void enter_directory(fslib::Path &path, + fslib::Directory &directory, + ui::Menu &menu, + const fslib::DirectoryEntry &entry); + + /// @brief Renders the control guide string on the bottom of the screen. + void render_control_guide(); + + /// @brief Returns a reference to the currently active menu. + ui::Menu &get_source_menu() noexcept; + + /// @brief Returns a reference to the currently inactive menu. + ui::Menu &get_destination_menu() noexcept; + + /// @brief Returns a reference to the current "active" path. + fslib::Path &get_source_path() noexcept; + + /// @brief Returns a reference to the currently "inactive" path. + fslib::Path &get_destination_path() noexcept; + + /// @brief Returns a reference to the "active" directory. + fslib::Directory &get_source_directory() noexcept; + + /// @brief Returns a reference ot the currently "inactive" directory. + fslib::Directory &get_destination_directory() noexcept; + + /// @brief Returns whether or not a path is at the root. + inline bool path_is_root(fslib::Path &path) const { return std::char_traits::length(path.get_path()) <= 1; } + + /// @brief Closes the filesystems passed and deactivates the state. + void deactivate_state() noexcept; +}; \ No newline at end of file diff --git a/include/appstates/FileOptionState.hpp b/include/appstates/FileOptionState.hpp new file mode 100644 index 0000000..9a3a22a --- /dev/null +++ b/include/appstates/FileOptionState.hpp @@ -0,0 +1,135 @@ +#pragma once +#include "StateManager.hpp" +#include "appstates/BaseState.hpp" +#include "appstates/FileModeState.hpp" +#include "fslib.hpp" +#include "ui/ui.hpp" + +#include + +class FileOptionState final : public BaseState +{ + public: + /// @brief FileOptionState. + /// @param spawningState Pointer to spawning state to grab its goodies. + FileOptionState(FileModeState *spawningState); + + ~FileOptionState() {}; + + /// @brief Inline creation function. + static inline std::shared_ptr create(FileModeState *spawningState) + { + return std::make_shared(spawningState); + } + + /// @brief Same as above. Pushes state before returning it. + static inline std::shared_ptr create_and_push(FileModeState *spawningState) + { + auto newState = FileOptionState::create(spawningState); + StateManager::push_state(newState); + return newState; + } + + /// @brief Update routine. + void update() override; + + /// @brief Render routine. + void render() override; + + /// @brief Signals to this state to update the source/target menu on the next update() call. + void update_source(); + + /// @brief Signals to this state to update the destination. Very rarely used. + void update_destination(); + + // clang-format off + struct DataStruct + { + fslib::Path sourcePath{}; + fslib::Path destPath{}; + int64_t journalSize{}; + FileOptionState *spawningState{}; + }; + // clang-format on + + /// @brief This makes some other stuff easier to read and type. + using TaskData = std::shared_ptr; + + private: + /// @brief Pointer to spawning FileMode state. + FileModeState *m_spawningState{}; + + /// @brief X coordinate. This is set at construction according to the target from the spawning state. + int m_x{}; + + /// @brief X coordinate for the target to reach. + int m_targetX{}; + + /// @brief Whether or not the dialog/menu is in place. + bool m_inPlace{}; + + /// @brief Whether or not the state should be closed. + bool m_close{}; + + /// @brief Stores whether or not an update is needed on the next update(). + std::atomic m_updateSource{}; + std::atomic m_updateDest{}; + + /// @brief This is the data struct passed to tasks. + std::shared_ptr m_dataStruct{}; + + /// @brief This is shared by all instances. + static inline std::shared_ptr sm_copyMenu{}; + + /// @brief This is shared by all instances. + static inline std::shared_ptr sm_dialog{}; + + /// @brief Ensures static members of all instances are allocated. + void initialize_static_members(); + + /// @brief Sets whether the dialog/menu are positioned left or right depending on the menu active in the spawning state. + void set_menu_side(); + + /// @brief Assigns the pointer to this. + void initialize_data_struct(); + + /// @brief Updates the FileModeState's source data. + void update_filemode_source(); + + /// @brief Updates the FileModeState's destination data. + void update_filemode_dest(); + + /// @brief Updates the Y coordinate + void update_x_coord(); + + /// @brief Sets up and begins the copy task. + void copy_target(); + + /// @brief Sets up and begins the delete task. + void delete_target(); + + /// @brief Attempts to rename the target. + void rename_target(); + + /// @brief Attempts to create a new directory. + void create_directory(); + + /// @brief Gets the properties of a file/folder. + void get_show_target_properties(); + + /// @brief Gets info and creates a MessageState displaying the properties of the target directory. + void get_show_directory_properties(const fslib::Path &path); + + /// @brief Gets info and creates a message displaying the properties of the target file. + /// @param path + void get_show_file_properties(const fslib::Path &path); + + /// @brief Closes and hides the state. + void close(); + + /// @brief Returns whether or not the state is closed. + bool is_closed(); + + /// @brief Sets the menu index back to 0 and deactivates the state. + void deactivate_state(); +}; \ No newline at end of file diff --git a/include/appstates/TitleOptionState.hpp b/include/appstates/TitleOptionState.hpp index 8c81110..f987cda 100644 --- a/include/appstates/TitleOptionState.hpp +++ b/include/appstates/TitleOptionState.hpp @@ -39,6 +39,9 @@ class TitleOptionState final : public BaseState /// @brief Runs update routine. void update() override; + /// @brief Handles hiding the panel. + void sub_update() override; + /// @brief Runs the render routine. void render() override; diff --git a/include/appstates/UserOptionState.hpp b/include/appstates/UserOptionState.hpp index 3e57c61..c5dd62c 100644 --- a/include/appstates/UserOptionState.hpp +++ b/include/appstates/UserOptionState.hpp @@ -36,6 +36,9 @@ class UserOptionState final : public BaseState /// @brief Runs the render routine. void update() override; + /// @brief Handles hiding the panel. + void sub_update() override; + /// @brief Runs the render routine. void render() override; diff --git a/include/config/ConfigContext.hpp b/include/config/ConfigContext.hpp index dc615e0..b066d2f 100644 --- a/include/config/ConfigContext.hpp +++ b/include/config/ConfigContext.hpp @@ -27,52 +27,52 @@ namespace config void save(); /// @brief Attempts to find and return the value of the key passed. - uint8_t get_by_key(std::string_view key) const; + uint8_t get_by_key(std::string_view key) const noexcept; /// @brief Attempts to toggle the value for the key passed. For simple 1 and 0. - void toggle_by_key(std::string_view key); + void toggle_by_key(std::string_view key) noexcept; /// @brief Attempts to set the key passed to the value passd. - void set_by_key(std::string_view key, uint8_t value); + void set_by_key(std::string_view key, uint8_t value) noexcept; /// @brief Returns the current working directory. fslib::Path get_working_directory() const; /// @brief Sets the current work directory if the path passed is valid. - bool set_working_directory(const fslib::Path &workDir); + bool set_working_directory(const fslib::Path &workDir) noexcept; /// @brief Returns the transition scaling speed. - double get_animation_scaling() const; + double get_animation_scaling() const noexcept; /// @brief Sets the current animation scaling speed. - void set_animation_scaling(double scaling); + void set_animation_scaling(double scaling) noexcept; /// @brief Adds a favorite to the favorite titles. void add_favorite(uint64_t applicationID); /// @brief Removes a title from the favorites. - void remove_favorite(uint64_t applicationID); + void remove_favorite(uint64_t applicationID) noexcept; /// @brief Returns if the application ID passed is a favorite. - bool is_favorite(uint64_t applicationID) const; + bool is_favorite(uint64_t applicationID) const noexcept; /// @brief Adds the application ID passed to the blacklist. void add_to_blacklist(uint64_t applicationID); /// @brief Removes the application ID passed from the blacklist. - void remove_from_blacklist(uint64_t applicationID); + void remove_from_blacklist(uint64_t applicationID) noexcept; /// @brief Writes all of the currently blacklisted titles to the vector passed. void get_blacklist(std::vector &listOut); /// @brief Returns if the application ID passed is found in the blacklist. - bool is_blacklisted(uint64_t applicationID) const; + bool is_blacklisted(uint64_t applicationID) const noexcept; /// @brief Returns if the blacklist is empty. - bool blacklist_empty() const; + bool blacklist_empty() const noexcept; /// @brief Returns if the application ID passed has a custom output path. - bool has_custom_path(uint64_t applicationID) const; + bool has_custom_path(uint64_t applicationID) const noexcept; /// @brief Adds a new output path. void add_custom_path(uint64_t applicationID, std::string_view newPath); diff --git a/include/config/config.hpp b/include/config/config.hpp index 0d5ac8c..d7525db 100644 --- a/include/config/config.hpp +++ b/include/config/config.hpp @@ -19,16 +19,16 @@ namespace config /// @brief Retrieves the config value according to the key passed. /// @param key Key to retrieve. See config::keys /// @return Key's value if found. 0 if it is not. - uint8_t get_by_key(std::string_view key); + uint8_t get_by_key(std::string_view key) noexcept; /// @brief Toggles the key. This is only for basic true or false settings. /// @param key Key to toggle. - void toggle_by_key(std::string_view key); + void toggle_by_key(std::string_view key) noexcept; /// @brief Sets the key according /// @param key Key to set. /// @param value Value to set the key to. - void set_by_key(std::string_view key, uint8_t value); + void set_by_key(std::string_view key, uint8_t value) noexcept; /// @brief Returns the working directory. /// @return Working directory. @@ -36,15 +36,15 @@ namespace config /// @brief Attempts to set the working directory to the one passed. /// @param path Path for JKSV to use. - bool set_working_directory(const fslib::Path &path); + bool set_working_directory(const fslib::Path &path) noexcept; /// @brief Returns the scaling speed of UI transitions and animations. /// @return Scaling variable. - double get_animation_scaling(); + double get_animation_scaling() noexcept; /// @brief Sets the UI animation scaling. /// @param newScale New value to set the scaling to. - void set_animation_scaling(double newScale); + void set_animation_scaling(double newScale) noexcept; /// @brief Adds or removes a title from the favorites list. /// @param applicationID Application ID of title to add or remove. @@ -53,11 +53,11 @@ namespace config /// @brief Returns if the title is found in the favorites list. /// @param applicationID Application ID to search for. /// @return True if found. False if not. - bool is_favorite(uint64_t applicationID); + bool is_favorite(uint64_t applicationID) noexcept; /// @brief Adds or removes title from blacklist. /// @param applicationID Application ID to add or remove. - void add_remove_blacklist(uint64_t applicationID); + void add_remove_blacklist(uint64_t applicationID) noexcept; /// @brief Gets the currently blacklisted application IDs. /// @param listOut Vector to store application IDs to. @@ -66,10 +66,10 @@ namespace config /// @brief Returns if the title is found in the blacklist. /// @param applicationID Application ID to search for. /// @return True if found. False if not. - bool is_blacklisted(uint64_t applicationID); + bool is_blacklisted(uint64_t applicationID) noexcept; /// @brief Returns whether or not the blacklist is empty. - bool blacklist_is_empty(); + bool blacklist_is_empty() noexcept; /// @brief Adds a custom output path for the title. /// @param applicationID Application ID of title to add a path for. @@ -79,7 +79,7 @@ namespace config /// @brief Searches to see if the application ID passed has a custom output path. /// @param applicationID Application ID to check. /// @return True if it does. False if it doesn't. - bool has_custom_path(uint64_t applicationID); + bool has_custom_path(uint64_t applicationID) noexcept; /// @brief Gets the custom, defined path for the title. /// @param applicationID Application ID of title to get. diff --git a/include/config/keys.hpp b/include/config/keys.hpp index 23991a3..2f2cb26 100644 --- a/include/config/keys.hpp +++ b/include/config/keys.hpp @@ -1,34 +1,31 @@ #pragma once #include -namespace config +namespace config::keys { - namespace keys - { - inline constexpr std::string_view WORKING_DIRECTORY = "WorkingDirectory"; - inline constexpr std::string_view INCLUDE_DEVICE_SAVES = "IncludeDeviceSaves"; - inline constexpr std::string_view AUTO_BACKUP_ON_RESTORE = "AutoBackupOnRestore"; - inline constexpr std::string_view AUTO_NAME_BACKUPS = "AutoNameBackups"; - inline constexpr std::string_view AUTO_UPLOAD = "AutoUploadToRemote"; - inline constexpr std::string_view USE_TITLE_IDS = "AlwaysUseTitleID"; - inline constexpr std::string_view HOLD_FOR_DELETION = "HoldForDeletion"; - inline constexpr std::string_view HOLD_FOR_RESTORATION = "HoldForRestoration"; - inline constexpr std::string_view HOLD_FOR_OVERWRITE = "HoldForOverWrite"; - inline constexpr std::string_view ONLY_LIST_MOUNTABLE = "OnlyListMountable"; - inline constexpr std::string_view LIST_ACCOUNT_SYS_SAVES = "ListAccountSystemSaves"; - inline constexpr std::string_view ALLOW_WRITING_TO_SYSTEM = "AllowSystemSaveWriting"; - inline constexpr std::string_view EXPORT_TO_ZIP = "ExportToZip"; - inline constexpr std::string_view ZIP_COMPRESSION_LEVEL = "ZipCompressionLevel"; - inline constexpr std::string_view TITLE_SORT_TYPE = "TitleSortType"; - inline constexpr std::string_view JKSM_TEXT_MODE = "JKSMTextMode"; - inline constexpr std::string_view FORCE_ENGLISH = "ForceEnglish"; - inline constexpr std::string_view SHOW_DEVICE_USER = "ShowDevice"; - inline constexpr std::string_view SHOW_BCAT_USER = "ShowBCAT"; - inline constexpr std::string_view SHOW_CACHE_USER = "ShowCache"; - inline constexpr std::string_view SHOW_SYSTEM_USER = "ShowSystem"; - inline constexpr std::string_view ENABLE_TRASH_BIN = "EnableTrash"; - inline constexpr std::string_view UI_ANIMATION_SCALE = "UIAnimationScaling"; - inline constexpr std::string_view FAVORITES = "Favorites"; - inline constexpr std::string_view BLACKLIST = "BlackList"; - } // namespace keys -} + inline constexpr std::string_view WORKING_DIRECTORY = "WorkingDirectory"; + inline constexpr std::string_view INCLUDE_DEVICE_SAVES = "IncludeDeviceSaves"; + inline constexpr std::string_view AUTO_BACKUP_ON_RESTORE = "AutoBackupOnRestore"; + inline constexpr std::string_view AUTO_NAME_BACKUPS = "AutoNameBackups"; + inline constexpr std::string_view AUTO_UPLOAD = "AutoUploadToRemote"; + inline constexpr std::string_view USE_TITLE_IDS = "AlwaysUseTitleID"; + inline constexpr std::string_view HOLD_FOR_DELETION = "HoldForDeletion"; + inline constexpr std::string_view HOLD_FOR_RESTORATION = "HoldForRestoration"; + inline constexpr std::string_view HOLD_FOR_OVERWRITE = "HoldForOverWrite"; + inline constexpr std::string_view ONLY_LIST_MOUNTABLE = "OnlyListMountable"; + inline constexpr std::string_view LIST_ACCOUNT_SYS_SAVES = "ListAccountSystemSaves"; + inline constexpr std::string_view ALLOW_WRITING_TO_SYSTEM = "AllowSystemSaveWriting"; + inline constexpr std::string_view EXPORT_TO_ZIP = "ExportToZip"; + inline constexpr std::string_view ZIP_COMPRESSION_LEVEL = "ZipCompressionLevel"; + inline constexpr std::string_view TITLE_SORT_TYPE = "TitleSortType"; + inline constexpr std::string_view JKSM_TEXT_MODE = "JKSMTextMode"; + inline constexpr std::string_view FORCE_ENGLISH = "ForceEnglish"; + inline constexpr std::string_view SHOW_DEVICE_USER = "ShowDevice"; + inline constexpr std::string_view SHOW_BCAT_USER = "ShowBCAT"; + inline constexpr std::string_view SHOW_CACHE_USER = "ShowCache"; + inline constexpr std::string_view SHOW_SYSTEM_USER = "ShowSystem"; + inline constexpr std::string_view ENABLE_TRASH_BIN = "EnableTrash"; + inline constexpr std::string_view UI_ANIMATION_SCALE = "UIAnimationScaling"; + inline constexpr std::string_view FAVORITES = "Favorites"; + inline constexpr std::string_view BLACKLIST = "BlackList"; +} \ No newline at end of file diff --git a/include/curl/DownloadStruct.hpp b/include/curl/DownloadStruct.hpp index 419dc2c..e83292c 100644 --- a/include/curl/DownloadStruct.hpp +++ b/include/curl/DownloadStruct.hpp @@ -13,18 +13,25 @@ namespace curl { /// @brief Buffer mutex. std::mutex lock{}; + /// @brief Conditional for when the buffer is full. std::condition_variable condition{}; + /// @brief Shared buffer that is read into. std::vector sharedBuffer{}; + /// @brief Bool to signal when the buffer is ready/empty. bool bufferReady{}; + /// @brief Destination file to write to. fslib::File *dest{}; + /// @brief Optional. Task to update with progress. sys::ProgressTask *task{}; + /// @brief Current offset in the file. size_t offset{}; + /// @brief Size of the file being downloaded. int64_t fileSize{}; }; diff --git a/include/curl/UploadStruct.hpp b/include/curl/UploadStruct.hpp index e3dd921..0cadc8a 100644 --- a/include/curl/UploadStruct.hpp +++ b/include/curl/UploadStruct.hpp @@ -9,6 +9,7 @@ namespace curl { /// @brief Source file to upload from. fslib::File *source{}; + /// @brief Optional. Task to update with progress. sys::ProgressTask *task{}; }; diff --git a/include/data/DataContext.hpp b/include/data/DataContext.hpp index 93bb3aa..16ce0d7 100644 --- a/include/data/DataContext.hpp +++ b/include/data/DataContext.hpp @@ -35,7 +35,7 @@ namespace data void load_title(uint64_t applicationID); /// @brief Returns the title info mapped to applicationID. nullptr on not found. - data::TitleInfo *get_title_by_id(uint64_t applicationID); + data::TitleInfo *get_title_by_id(uint64_t applicationID) noexcept; /// @brief Gets a vector of pointers to all of the current title info instances. void get_title_info_list(data::TitleInfoList &listOut); diff --git a/include/data/TitleInfo.hpp b/include/data/TitleInfo.hpp index c86cca1..135b004 100644 --- a/include/data/TitleInfo.hpp +++ b/include/data/TitleInfo.hpp @@ -20,79 +20,76 @@ namespace data public: /// @brief Constructs a TitleInfo instance. Loads control data, icon. /// @param applicationID Application ID of title to load. - TitleInfo(uint64_t applicationID); + TitleInfo(uint64_t applicationID) noexcept; /// @brief Initializes a TitleInfo instance using external (cached) NsApplicationControlData /// @param applicationID Application ID of the title loaded from cache. /// @param controlData Reference to the control data to init from. - TitleInfo(uint64_t applicationID, std::unique_ptr &controlData); + TitleInfo(uint64_t applicationID, NsApplicationControlData &controlData) noexcept; - /// @brief Move constructor and operator. - TitleInfo(TitleInfo &&titleInfo); - TitleInfo &operator=(TitleInfo &&TitleInfo); - - // None of this nonesense around these parts.TitleInfo(const TitleInfo &) = delete; + // None of this nonesense around these parts. + TitleInfo(const TitleInfo &) = delete; TitleInfo &operator=(const TitleInfo &) = delete; /// @brief Returns the application ID of the title. /// @return Title's application ID. - uint64_t get_application_id() const; + uint64_t get_application_id() const noexcept; /// @brief Returns a pointer to the control data for the title. /// @return Pointer to control data. - NsApplicationControlData *get_control_data(); + const NsApplicationControlData *get_control_data() const noexcept; /// @brief Returns whether or not the title has control data. /// @return Whether or not the title has control data. - bool has_control_data() const; + bool has_control_data() const noexcept; /// @brief Returns the title of the title? /// @return Title directly from the NACP. - const char *get_title(); + const char *get_title() const noexcept; /// @brief Returns the path safe version of the title for file system usage. /// @return Path safe version of the title. - const char *get_path_safe_title() const; + const char *get_path_safe_title() const noexcept; /// @brief Returns the publisher of the title. /// @return Publisher string from NACP. - const char *get_publisher(); + const char *get_publisher() const noexcept; /// @brief Returns the owner ID of the save data. - uint64_t get_save_data_owner_id() const; + uint64_t get_save_data_owner_id() const noexcept; /// @brief Returns the save data container's base size. /// @param saveType Type of save data to return. /// @return Size of baseline save data if applicable. If not, 0. - int64_t get_save_data_size(uint8_t saveType) const; + int64_t get_save_data_size(uint8_t saveType) const noexcept; /// @brief Returns the maximum size of the save data container. /// @param saveType Type of save data to return. /// @return Maximum size of the save container if applicable. If not, 0. - int64_t get_save_data_size_max(uint8_t saveType) const; + int64_t get_save_data_size_max(uint8_t saveType) const noexcept; /// @brief Returns the journaling size for the save type passed. /// @param saveType Save type to return. /// @return Journal size if applicable. If not, 0. - int64_t get_journal_size(uint8_t saveType) const; + int64_t get_journal_size(uint8_t saveType) const noexcept; /// @brief Returns the maximum journal size for the save type passed. /// @param saveType Save type to return. /// @return Maximum journal size if applicable. If not, 0. - int64_t get_journal_size_max(uint8_t saveType) const; + int64_t get_journal_size_max(uint8_t saveType) const noexcept; /// @brief Returns if a title uses the save type passed. /// @param saveType Save type to check for. /// @return True on success. False on failure. - bool has_save_data_type(uint8_t saveType) const; + bool has_save_data_type(uint8_t saveType) const noexcept; /// @brief Returns a pointer to the icon texture. /// @return Icon - sdl::SharedTexture get_icon() const; + sdl::SharedTexture get_icon() const noexcept; /// @brief Allows the path safe title to be set to a new path. /// @param newPathSafe Buffer containing the new safe path to use. - void set_path_safe_title(const char *newPathSafe); + void set_path_safe_title(const char *newPathSafe) noexcept; /// @brief Loads the icon from the nacp. void load_icon() override; @@ -104,8 +101,11 @@ namespace data /// @brief Stores application ID for easier grabbing since JKSV is all pointers. uint64_t m_applicationID{}; - /// @brief This contains the NACP and the icon. - std::unique_ptr m_data{}; + /// @brief Where all the good stuff is. + NsApplicationControlData m_data{}; + + /// @brief Stores the pointer to the language entry of the title. + NacpLanguageEntry *m_entry{}; /// @brief Saves whether or not the title has control data. bool m_hasData{}; @@ -117,6 +117,6 @@ namespace data sdl::SharedTexture m_icon{}; /// @brief Private function to get/create the path safe title. - void get_create_path_safe_title(); + void get_create_path_safe_title() noexcept; }; } // namespace data diff --git a/include/data/User.hpp b/include/data/User.hpp index c5eb486..143036f 100644 --- a/include/data/User.hpp +++ b/include/data/User.hpp @@ -29,18 +29,21 @@ namespace data /// @brief Constructs a new user with accountID /// @param accountID AccountID of user. /// @param saveType Save data type account uses. - User(AccountUid accountID, FsSaveDataType saveType); + User(AccountUid accountID, FsSaveDataType saveType) noexcept; /// @brief This is the constructor used to create the fake system users. /// @param accountID AccountID to associate with saveType. /// @param pathSafeNickname The path safe version of the save data since JKSV is in everything the Switch supports. /// @param iconPath Path to the icon to load for account. /// @param saveType Save data type of user. - User(AccountUid accountID, std::string_view nickname, std::string_view pathSafeNickname, FsSaveDataType saveType); + User(AccountUid accountID, + std::string_view nickname, + std::string_view pathSafeNickname, + FsSaveDataType saveType) noexcept; /// @brief Move constructor and operator. - User(User &&user); - User &operator=(User &&user); + User(User &&user) noexcept; + User &operator=(User &&user) noexcept; // Non of this around these parts. User(const User &) = delete; @@ -52,47 +55,47 @@ namespace data void add_data(const FsSaveDataInfo *saveInfo, const PdmPlayStatistics *playStats); /// @brief Clears the user save info vector. - void clear_data_entries(); + void clear_data_entries() noexcept; /// @brief Erases data at index. /// @param index Index of save data info to erase. void erase_data(int index); /// @brief Runs the sort algo on the vector. - void sort_data(); + void sort_data() noexcept; /// @brief Returns the account ID of the user - AccountUid get_account_id() const; + AccountUid get_account_id() const noexcept; /// @brief Returns the primary save data type o - FsSaveDataType get_account_save_type() const; + FsSaveDataType get_account_save_type() const noexcept; /// @brief Returns the user's full UTF-8 nickname. - const char *get_nickname() const; + const char *get_nickname() const noexcept; /// @brief Returns the path safe version of the user's nickname. - const char *get_path_safe_nickname() const; + const char *get_path_safe_nickname() const noexcept; /// @brief Returns the total data entries. - size_t get_total_data_entries() const; + size_t get_total_data_entries() const noexcept; /// @brief Returns the application ID of the title at index. - uint64_t get_application_id_at(int index) const; + uint64_t get_application_id_at(int index) const noexcept; /// @brief Returns a pointer to the save data info at index. - FsSaveDataInfo *get_save_info_at(int index); + FsSaveDataInfo *get_save_info_at(int index) noexcept; /// @brief Returns a pointer to the play statistics at index. - PdmPlayStatistics *get_play_stats_at(int index); + PdmPlayStatistics *get_play_stats_at(int index) noexcept; /// @brief Returns a pointer to the save info of applicationID. - FsSaveDataInfo *get_save_info_by_id(uint64_t applicationID); + FsSaveDataInfo *get_save_info_by_id(uint64_t applicationID) noexcept; /// @brief Returns a reference to the internal map for range based loops. - data::UserSaveInfoList &get_user_save_info_list(); + data::UserSaveInfoList &get_user_save_info_list() noexcept; /// @brief Returns a pointer to the play statistics of applicationID - PdmPlayStatistics *get_play_stats_by_id(uint64_t applicationID); + PdmPlayStatistics *get_play_stats_by_id(uint64_t applicationID) noexcept; /// @brief Erases a UserDataEntry according to the application ID passed. /// @param applicationID ID of the save to erase. diff --git a/include/data/accountUID.hpp b/include/data/accountUID.hpp index 03e051e..5273a77 100644 --- a/include/data/accountUID.hpp +++ b/include/data/accountUID.hpp @@ -11,7 +11,7 @@ namespace data /// @param accountIDA First account to compare. /// @param accountIDB Second account to compare. /// @return True if both account IDs match. -static inline bool operator==(AccountUid accountIDA, AccountUid accountIDB) +static inline bool operator==(AccountUid accountIDA, AccountUid accountIDB) noexcept { return (accountIDA.uid[0] == accountIDB.uid[0]) && (accountIDA.uid[1] == accountIDB.uid[1]); } @@ -22,7 +22,7 @@ static inline bool operator==(AccountUid accountIDA, AccountUid accountIDB) /// @return True if they match. False if they don't. /// @note I'm not 100% sure which uint64_t in the AccountUid struct comes first. I don't know if it's [0][1] or [1][0]. To do: /// Figure that out. -static inline bool operator==(AccountUid accountIDA, u128 accountIDB) +static inline bool operator==(AccountUid accountIDA, u128 accountIDB) noexcept { return accountIDA.uid[0] == (accountIDB >> 64 & 0xFFFFFFFFFFFFFFFF) && accountIDA.uid[1] == (accountIDB & 0xFFFFFFFFFFFFFFFF); diff --git a/include/data/data.hpp b/include/data/data.hpp index c252bcb..d573559 100644 --- a/include/data/data.hpp +++ b/include/data/data.hpp @@ -21,7 +21,7 @@ namespace data /// @brief Returns a pointer to the title mapped to applicationID. /// @param applicationID ApplicationID of title to retrieve. /// @return Pointer to data. nullptr if it's not found. - data::TitleInfo *get_title_info_by_id(uint64_t applicationID); + data::TitleInfo *get_title_info_by_id(uint64_t applicationID) noexcept; /// @brief Gets a vector of pointers to the title info. /// @param listOut List to store pointers in. @@ -34,7 +34,7 @@ namespace data /// @brief Returns if the title with applicationID is already loaded to the map. /// @param applicationID Application ID of the title to search for. /// @return True if it has been. False if it hasn't. - bool title_exists_in_map(uint64_t applicationID); + bool title_exists_in_map(uint64_t applicationID) noexcept; /// @brief Gets a vector of pointers with all titles with saveType. /// @param saveType Save data type to check for. diff --git a/include/logging/error.hpp b/include/error.hpp similarity index 77% rename from include/logging/error.hpp rename to include/error.hpp index aabbfc9..f83a55b 100644 --- a/include/logging/error.hpp +++ b/include/error.hpp @@ -5,11 +5,11 @@ namespace error { /// @brief Logs and returns if a call from libnx fails. - bool libnx(Result code, const std::source_location &location = std::source_location::current()); + bool libnx(Result code, const std::source_location &location = std::source_location::current()) noexcept; /// @brief Logs and returns if an fslib function fails. - bool fslib(bool result, const std::source_location &location = std::source_location::current()); + bool fslib(bool result, const std::source_location &location = std::source_location::current()) noexcept; /// @brief Returns whether or not the pointer passed is null. Records the location in which this occurred. - bool is_null(const void *pointer, const std::source_location &location = std::source_location::current()); + bool is_null(const void *pointer, const std::source_location &location = std::source_location::current()) noexcept; } diff --git a/include/fs/MiniUnzip.hpp b/include/fs/MiniUnzip.hpp index f2fe873..92639ba 100644 --- a/include/fs/MiniUnzip.hpp +++ b/include/fs/MiniUnzip.hpp @@ -6,7 +6,7 @@ namespace fs { - class MiniUnzip + class MiniUnzip final { public: MiniUnzip() = default; diff --git a/include/fs/MiniZip.hpp b/include/fs/MiniZip.hpp index 87636b4..616e2f1 100644 --- a/include/fs/MiniZip.hpp +++ b/include/fs/MiniZip.hpp @@ -6,7 +6,7 @@ namespace fs { - class MiniZip + class MiniZip final { public: MiniZip() = default; @@ -41,6 +41,9 @@ namespace fs /// @brief Stores whether or not the zipFile was opened successfully. bool m_isOpen{}; + /// @brief Stores the compression level from config to avoid repeated calls. + int m_level{}; + /// @brief Underlying ZIP file. zipFile m_zip{}; }; diff --git a/include/fs/PathFilter.hpp b/include/fs/PathFilter.hpp index 05cfc2b..2a9b8a0 100644 --- a/include/fs/PathFilter.hpp +++ b/include/fs/PathFilter.hpp @@ -13,13 +13,13 @@ namespace fs PathFilter(const fslib::Path &filterPath); /// @brief Returns whether or not the filter has valid paths. - bool has_paths() const; + bool has_paths() const noexcept; /// @brief Returns whether or not the path passed is filtered. - bool is_filtered(const fslib::Path &path); + bool is_filtered(const fslib::Path &path) const noexcept; private: /// @brief Vector of paths to filter from deletion and backup. - std::vector m_paths{}; + std::vector m_paths{}; }; } diff --git a/include/fs/SaveMetaData.hpp b/include/fs/SaveMetaData.hpp index b5a128a..359a0fd 100644 --- a/include/fs/SaveMetaData.hpp +++ b/include/fs/SaveMetaData.hpp @@ -32,15 +32,11 @@ namespace fs } __attribute__((packed)); // clang-format on - // I didn't want a separate file for this. - bool read_save_data_extra_info(const FsSaveDataInfo *saveInfo, FsSaveDataExtraData &dataOut); - /// @brief Didn't feel like a whole new file just for this. Fills an fs::SaveMetaData struct. - bool fill_save_meta_data(const FsSaveDataInfo *saveInfo, SaveMetaData &meta); + bool fill_save_meta_data(const FsSaveDataInfo *saveInfo, SaveMetaData &meta) noexcept; /// @brief Processes the save meta data and applies it to the passed saveInfo pointer. /// @param saveInfo FsSaveDataInfo to apply the meta to. /// @param meta Save meta data to apply. - bool process_save_meta_data(const FsSaveDataInfo *saveInfo, const SaveMetaData &meta); - + bool process_save_meta_data(const FsSaveDataInfo *saveInfo, const SaveMetaData &meta) noexcept; } // namespace fs diff --git a/include/fs/ScopedSaveMount.hpp b/include/fs/ScopedSaveMount.hpp index 46163ac..91c18ee 100644 --- a/include/fs/ScopedSaveMount.hpp +++ b/include/fs/ScopedSaveMount.hpp @@ -13,8 +13,8 @@ namespace fs /// @param log Optional. Whether or not logging errors is wanted. True by default. ScopedSaveMount(std::string_view mount, const FsSaveDataInfo *saveInfo, bool log = true); - ScopedSaveMount(ScopedSaveMount &&scopedSaveMount); - ScopedSaveMount &operator=(ScopedSaveMount &&scopedSaveMount); + ScopedSaveMount(ScopedSaveMount &&scopedSaveMount) noexcept; + ScopedSaveMount &operator=(ScopedSaveMount &&scopedSaveMount) noexcept; ScopedSaveMount(const ScopedSaveMount &) = delete; ScopedSaveMount &operator=(const ScopedSaveMount &) = delete; @@ -23,7 +23,7 @@ namespace fs ~ScopedSaveMount(); /// @brief Returns whether or not mounting the data was successful. - bool is_open() const; + bool is_open() const noexcept; private: /// @brief Saves a copy of the mount point for destruction. diff --git a/include/fs/directory_functions.hpp b/include/fs/directory_functions.hpp index 03f4bf1..634a95e 100644 --- a/include/fs/directory_functions.hpp +++ b/include/fs/directory_functions.hpp @@ -3,9 +3,16 @@ namespace fs { - /// @brief Retrieves the total size of the contents of the directory at targetPath. - /// @param targetPath Directory to calculate. - uint64_t get_directory_total_size(const fslib::Path &targetPath); + /// @brief Recursively runs through the path passed and retrieves information. + /// @param directoryPath Path of directory. + /// @param subDirCount Int64_t to track number of subdirectories with. + /// @param fileCount Int64_t to track the number of files. + /// @param totalSize Int64_t to track the size of everything. + /// @return True on success. False or crash on what I would assume is a stack overflow. + bool get_directory_information(const fslib::Path &directoryPath, + int64_t &subDirCount, + int64_t &fileCount, + int64_t &totalSize); /// @brief Checks if directory is empty. Didn't feel like this needs its own source file. /// @param directoryPath Path to directory to check. diff --git a/include/fs/io.hpp b/include/fs/io.hpp index 469c122..ebb1de8 100644 --- a/include/fs/io.hpp +++ b/include/fs/io.hpp @@ -19,7 +19,6 @@ namespace fs /// @param journalSize Size of the journal area of the save data. void copy_file_commit(const fslib::Path &source, const fslib::Path &destination, - std::string_view device, int64_t journalSize, sys::ProgressTask *task = nullptr); @@ -36,7 +35,6 @@ namespace fs /// @param journalSize Size of the journaling area of the save. void copy_directory_commit(const fslib::Path &source, const fslib::Path &destination, - std::string_view device, int64_t journalSize, sys::ProgressTask *task = nullptr); diff --git a/include/fs/save_data_functions.hpp b/include/fs/save_data_functions.hpp index 8d83fbb..d452b7f 100644 --- a/include/fs/save_data_functions.hpp +++ b/include/fs/save_data_functions.hpp @@ -1,5 +1,6 @@ #pragma once #include "data/data.hpp" + #include namespace fs @@ -8,23 +9,29 @@ namespace fs /// @param targetUser User to create save data for. /// @param titleInfo Title to create save data for. /// @return True on success. False on failure. - bool create_save_data_for(data::User *targetUser, data::TitleInfo *titleInfo); + bool create_save_data_for(data::User *targetUser, data::TitleInfo *titleInfo) noexcept; /// @brief Deletes the save data of the FsSaveDataInfo passed. /// @param saveInfo Save data to delete. /// @return True on success. False on failure. - bool delete_save_data(const FsSaveDataInfo *saveInfo); + bool delete_save_data(const FsSaveDataInfo *saveInfo) noexcept; /// @brief Extends the save data of the FsSaveDataInfo struct passed. /// @param saveInfo Pointer to the FsSaveDataInfo struct of the save to extend. /// @param size Size (in MB) to extend the save data to. /// @param journalSize Size of the journaling space. /// @return True on success. False on failure. - bool extend_save_data(const FsSaveDataInfo *saveInfo, int64_t size, int64_t journalSize); + bool extend_save_data(const FsSaveDataInfo *saveInfo, int64_t size, int64_t journalSize) noexcept; /// @brief Returns whether or not the saveInfo passed is system type. /// @param saveInfo FsSaveDataInfo to check. /// @return True if it is. False if it isn't. /// @note The config setting overrides this. - bool is_system_save_data(const FsSaveDataInfo *saveInfo); + bool is_system_save_data(const FsSaveDataInfo *saveInfo) noexcept; + + /// @brief Reads the extra info of the save container according to the FsSaveDataInfo passed. + /// @param saveInfo Pointer to the save info to read. + /// @param extraOut Reference to the FsSaveDataExtraData to read to. + /// @return True on success. False on failure. + bool read_save_extra_data(const FsSaveDataInfo *saveInfo, FsSaveDataExtraData &extraOut) noexcept; } // namespace fs diff --git a/include/fs/save_mount.hpp b/include/fs/save_mount.hpp index d44a322..b2f8377 100644 --- a/include/fs/save_mount.hpp +++ b/include/fs/save_mount.hpp @@ -5,8 +5,8 @@ namespace fs { /// @brief Default mount point used for JKSV for saves. - static constexpr std::string_view DEFAULT_SAVE_MOUNT = "save"; + inline constexpr std::string_view DEFAULT_SAVE_MOUNT = "save"; /// @brief Same as above, but as a root directory. - static constexpr std::string_view DEFAULT_SAVE_ROOT = "save:/"; + inline constexpr std::string_view DEFAULT_SAVE_ROOT = "save:/"; } // namespace fs diff --git a/include/fs/zip.hpp b/include/fs/zip.hpp index b1bc19c..59477d6 100644 --- a/include/fs/zip.hpp +++ b/include/fs/zip.hpp @@ -18,7 +18,6 @@ namespace fs void copy_zip_to_directory(fs::MiniUnzip &source, const fslib::Path &dest, int64_t journalSize, - std::string_view commitDevice, sys::ProgressTask *Task = nullptr); /// @brief Returns whether or not zip has files inside besides the save meta. diff --git a/include/graphics/colors.hpp b/include/graphics/colors.hpp index cc2c68c..0734167 100644 --- a/include/graphics/colors.hpp +++ b/include/graphics/colors.hpp @@ -13,6 +13,7 @@ namespace colors inline constexpr sdl::Color PINK = {0xFF4444FF}; inline constexpr sdl::Color BLUE_GREEN = {0x00FFC5FF}; inline constexpr sdl::Color CLEAR_COLOR = {0x2D2D2DFF}; + inline constexpr sdl::Color CLEAR_PANEL = {0x0D0D0DFF}; inline constexpr sdl::Color DIALOG_DARK = {0x505050FF}; inline constexpr sdl::Color DIALOG_LIGHT = {0xDCDCDCFF}; inline constexpr sdl::Color DIM_BACKGROUND = {0x00000088}; diff --git a/include/input.hpp b/include/input.hpp index 1d08bb6..00fef10 100644 --- a/include/input.hpp +++ b/include/input.hpp @@ -7,17 +7,17 @@ namespace input void initialize(); /// @brief Updates the PadState. - void update(); + void update() noexcept; /// @brief Returns if a button was pressed the current frame, but not the previous. /// @param button Button to check. - bool button_pressed(HidNpadButton button); + bool button_pressed(HidNpadButton button) noexcept; /// @brief Returns if the button was pressed or held the previous and current frame. /// @param button Button to check. - bool button_held(HidNpadButton button); + bool button_held(HidNpadButton button) noexcept; /// @brief Returns if the button was pressed or held the previous frame, but not the current. /// @param button Button to check. - bool button_released(HidNpadButton button); + bool button_released(HidNpadButton button) noexcept; } // namespace input diff --git a/include/logging/logger.hpp b/include/logging/logger.hpp index b50a4a5..635bd37 100644 --- a/include/logging/logger.hpp +++ b/include/logging/logger.hpp @@ -9,5 +9,5 @@ namespace logger /// @brief Logs a formatted string. /// @param format Format of string. /// @param arguments Va arguments. - void log(const char *format, ...); + void log(const char *format, ...) noexcept; } // namespace logger diff --git a/include/mathutil.hpp b/include/mathutil.hpp index cfc78b9..bfcb06f 100644 --- a/include/mathutil.hpp +++ b/include/mathutil.hpp @@ -6,6 +6,6 @@ namespace math class Util { public: - static inline Type absolute_distance(Type a, Type b) { return a > b ? a - b : b - a; } + static inline Type absolute_distance(Type a, Type b) noexcept { return a > b ? a - b : b - a; } }; } diff --git a/include/remote/Form.hpp b/include/remote/Form.hpp index c38d72d..9a9a345 100644 --- a/include/remote/Form.hpp +++ b/include/remote/Form.hpp @@ -15,11 +15,11 @@ namespace remote /// @brief Move constructor. /// @param form Form to copy from. - Form(Form &&form); + Form(Form &&form) noexcept; /// @brief = Operator. /// @param form Form to copy. - Form &operator=(const Form &form); + Form &operator=(const Form &form) noexcept; /// @brief = Move operator. /// @param form Form to rob of its life. @@ -31,10 +31,10 @@ namespace remote Form &append_parameter(std::string_view param, std::string_view value); /// @brief Returns the C string of the form string. - const char *get() const; + const char *get() const noexcept; /// @brief Returns m_form.length() - size_t length() const; + size_t length() const noexcept; private: /// @brief String containing the actual data posted. diff --git a/include/remote/GoogleDrive.hpp b/include/remote/GoogleDrive.hpp index 279b2be..838ef65 100644 --- a/include/remote/GoogleDrive.hpp +++ b/include/remote/GoogleDrive.hpp @@ -79,7 +79,7 @@ namespace remote bool get_root_id(); /// @brief Returns whether or not the auth token is still valid for use or needs to be refreshed. - bool token_is_valid() const; + bool token_is_valid() const noexcept; /// @brief Attempts to refresh the auth token if needed. bool refresh_token(); @@ -95,6 +95,6 @@ namespace remote /// @param json Json object to check. /// @param log Whether or not to log the error. /// @note This doesn't catch every error. Google's errors aren't consistent. - bool error_occurred(json::Object &json, bool log = true); + bool error_occurred(json::Object &json, bool log = true) noexcept; }; } // namespace remote diff --git a/include/remote/Item.hpp b/include/remote/Item.hpp index 820ac29..673d145 100644 --- a/include/remote/Item.hpp +++ b/include/remote/Item.hpp @@ -16,23 +16,23 @@ namespace remote /// @brief Returns the name of the item. /// @return Name of the item. - std::string_view get_name() const; + std::string_view get_name() const noexcept; /// @brief Returns the id of the item. /// @return ID of the item. - std::string_view get_id() const; + std::string_view get_id() const noexcept; /// @brief Returns the parent id of the item. /// @return Parent ID of the item. - std::string_view get_parent_id() const; + std::string_view get_parent_id() const noexcept; /// @brief Gets the size of the item. /// @return Size of the item in bytes. - size_t get_size() const; + size_t get_size() const noexcept; /// @brief Returns whether or not the item is a directory. /// @return Whether or not the item is a directory. - bool is_directory() const; + bool is_directory() const noexcept; /// @brief Sets the name of the item. /// @param name New name of the item. @@ -48,26 +48,26 @@ namespace remote /// @brief Sets the size of the item. /// @param size Size of the item. - void set_size(size_t size); + void set_size(size_t size) noexcept; /// @brief Sets whether or not the item is a directory. /// @param directory Whether or not the item is a directory. - void set_is_directory(bool directory); + void set_is_directory(bool directory) noexcept; private: /// @brief The name of the item. - std::string m_name; + std::string m_name{}; /// @brief The ID of the item. - std::string m_id; + std::string m_id{}; /// @brief Parent ID of the item. - std::string m_parent; + std::string m_parent{}; /// @brief Size of the item. - size_t m_size; + size_t m_size{}; /// @brief Whether or not the item is a directory. - bool m_isDirectory; + bool m_isDirectory{}; }; } // namespace remote diff --git a/include/remote/Storage.hpp b/include/remote/Storage.hpp index ce8fb91..0923058 100644 --- a/include/remote/Storage.hpp +++ b/include/remote/Storage.hpp @@ -23,12 +23,12 @@ namespace remote Storage(std::string_view prefix, bool supportsUtf8 = false); /// @brief Returns whether or not the Storage type was successfully. initialized. - bool is_initialized() const; + bool is_initialized() const noexcept; // Directory functions. /// @brief Returns whether or not a directory with name exists within the current parent. /// @param name Name of the directory to search for. - bool directory_exists(std::string_view name); + bool directory_exists(std::string_view name) const noexcept; /// @brief Returns the parent to the root directory. void return_to_root(); @@ -48,7 +48,7 @@ namespace remote /// @brief Searches the list for a directory matching name and the current parent. /// @param name Name of the directory to search for. /// @return Pointer to the item representing the directory on success. nullptr on failure/not found. - remote::Item *get_directory_by_name(std::string_view name); + remote::Item *get_directory_by_name(std::string_view name) noexcept; /// @brief Retrieves a listing of the items in the current parent directory. /// @param listOut List to fill. @@ -62,7 +62,7 @@ namespace remote // File functions. /// @brief Returns whether a file with name exists within the current directory. /// @param name Name of the file. - bool file_exists(std::string_view name); + bool file_exists(std::string_view name) const noexcept; /// @brief Uploads a file from the SD card to the remote. /// @param source Path to the file to upload. @@ -83,7 +83,7 @@ namespace remote /// @brief Searches the list for a file matching name and the current parent. /// @param name Name of the file to search for. /// @return Pointer to the item if located. nullptr if not. - remote::Item *get_file_by_name(std::string_view name); + remote::Item *get_file_by_name(std::string_view name) noexcept; // General functions that apply to both. /// @brief Deletes a file or folder from the remote. @@ -96,10 +96,10 @@ namespace remote virtual bool rename_item(remote::Item *item, std::string_view newName) = 0; /// @brief Returns whether or not the remote storage type supports UTF-8 for names or requires path safe titles. - bool supports_utf8() const; + bool supports_utf8() const noexcept; /// @brief Returns the prefix for menus. - std::string_view get_prefix() const; + std::string_view get_prefix() const noexcept; protected: /// @brief This is the size of the buffers used for snprintf'ing URLs together. @@ -131,27 +131,34 @@ namespace remote /// @brief Searches the list for a directory matching name and the current parent. /// @param name Name to search for. - Storage::List::iterator find_directory_by_name(std::string_view name); + Storage::List::iterator find_directory_by_name(std::string_view name) noexcept; + Storage::List::const_iterator find_directory_by_name(std::string_view name) const noexcept; /// @brief Searches the list for a directory matching ID. /// @param id ID of the directory to search for. - Storage::List::iterator find_directory_by_id(std::string_view id); + Storage::List::iterator find_directory_by_id(std::string_view id) noexcept; + Storage::List::const_iterator find_directory_by_id(std::string_view id) const noexcept; /// @brief Searches to find if a file with name exists within the current parent. /// @param name Name of the file to search for. - Storage::List::iterator find_file_by_name(std::string_view name); + Storage::List::iterator find_file_by_name(std::string_view name) noexcept; + Storage::List::const_iterator find_file_by_name(std::string_view name) const noexcept; /// @brief Searches the list for a file matching ID. /// @param id ID to search for.s - Storage::List::iterator find_file_by_id(std::string_view id); + Storage::List::iterator find_file_by_id(std::string_view id) noexcept; + Storage::List::const_iterator find_file_by_id(std::string_view id) const noexcept; /// @brief Locates any item (directory/file) by the id passed. /// @param id ID to search for. - Storage::List::iterator find_item_by_id(std::string_view id); + Storage::List::iterator find_item_by_id(std::string_view id) noexcept; + Storage::List::const_iterator find_item_by_id(std::string_view id) const noexcept; /// @brief Searches starting with the iterator start for items that belong to parentID /// @param start Beginning iterator for search. /// @param parentID ParentID to match. - Storage::List::iterator find_by_parent_id(Storage::List::iterator start, std::string_view parentID); + Storage::List::iterator find_by_parent_id(Storage::List::iterator start, std::string_view parentID) noexcept; + Storage::List::const_iterator find_by_parent_id(Storage::List::const_iterator start, + std::string_view parentID) const noexcept; }; } // namespace remote diff --git a/include/remote/URL.hpp b/include/remote/URL.hpp index 87d74ff..bc661c2 100644 --- a/include/remote/URL.hpp +++ b/include/remote/URL.hpp @@ -21,7 +21,7 @@ namespace remote /// @brief Move constructor. /// @param url URL to move. - URL(URL &&url); + URL(URL &&url) noexcept; /// @brief Makes a copy of the URL passed. /// @param url remote::URL instance to make a copy of. @@ -29,7 +29,7 @@ namespace remote /// @brief Move operator. /// @param url URL to move. - URL &operator=(URL &&url); + URL &operator=(URL &&url) noexcept; /// @brief Sets the base URL. Basically resets the string back to square 0. /// @param base Base URL to start with. @@ -48,7 +48,7 @@ namespace remote URL &append_slash(); /// @brief Returns the C string of the url string. - const char *get() const; + const char *get() const noexcept; private: /// @brief This is where the actual URL is held. diff --git a/include/remote/remote.hpp b/include/remote/remote.hpp index 18c4911..df7c224 100644 --- a/include/remote/remote.hpp +++ b/include/remote/remote.hpp @@ -10,7 +10,7 @@ namespace remote static constexpr std::string_view PATH_WEBDAV_CONFIG = "sdmc:/config/JKSV/webdav.json"; /// @brief Returns whether or not the console has an active internet connection. - bool has_internet_connection(); + bool has_internet_connection() noexcept; /// @brief Initializes the Storage instance to Google Drive. void initialize_google_drive(); @@ -19,5 +19,5 @@ namespace remote void initialize_webdav(); /// @brief Returns the pointer to the Storage instance. - remote::Storage *get_remote_storage(); + remote::Storage *get_remote_storage() noexcept; } // namespace remote diff --git a/include/strings/names.hpp b/include/strings/names.hpp index 09df553..062bc50 100644 --- a/include/strings/names.hpp +++ b/include/strings/names.hpp @@ -1,44 +1,46 @@ #pragma once #include -namespace strings +namespace strings::names { - namespace names - { - inline constexpr std::string_view BACKUPMENU_MENU = "BackupMenu"; - inline constexpr std::string_view BACKUPMENU_CONFS = "BackupMenuConfirmations"; - inline constexpr std::string_view BACKUPMENU_POPS = "BackupMenuPops"; - inline constexpr std::string_view BACKUPMENU_STATUS = "BackupMenuStatus"; - inline constexpr std::string_view CONTROL_GUIDES = "ControlGuides"; - inline constexpr std::string_view DATA_LOADING_STATUS = "DataLoadingStatus"; - inline constexpr std::string_view EXTRASMENU_MENU = "ExtrasMenu"; - inline constexpr std::string_view EXTRASMENU_POPS = "ExtrasPops"; - inline constexpr std::string_view GENERAL_POPS = "GeneralPops"; - inline constexpr std::string_view GOOGLE_DRIVE = "GoogleDriveStrings"; - inline constexpr std::string_view HOLDING_STRINGS = "HoldingStrings"; - inline constexpr std::string_view IO_STATUSES = "IOStatuses"; - inline constexpr std::string_view IO_POPS = "IOPops"; - inline constexpr std::string_view KEYBOARD = "KeyboardStrings"; - inline constexpr std::string_view MAINMENU_CONFS = "MainMenuConfs"; - inline constexpr std::string_view MAINMENU_POPS = "MainMenuPops"; - inline constexpr std::string_view ON_OFF = "OnOff"; - inline constexpr std::string_view REMOTE_POPS = "RemotePops"; - inline constexpr std::string_view SAVECREATE_POPS = "SaveCreatePops"; - inline constexpr std::string_view SAVE_DATA_TYPES = "SaveDataTypes"; - inline constexpr std::string_view SETTINGS_DESCRIPTIONS = "SettingsDescriptions"; - inline constexpr std::string_view SETTINGS_MENU = "SettingsMenu"; - inline constexpr std::string_view SETTINGS_POPS = "SettingsPops"; - inline constexpr std::string_view SORT_TYPES = "SortTypes"; - inline constexpr std::string_view TITLEINFO = "TitleInfo"; - inline constexpr std::string_view TITLEOPTION_CONFS = "TitleOptionConfirmations"; - inline constexpr std::string_view TITLEOPTION_POPS = "TitleOptionPops"; - inline constexpr std::string_view TITLEOPTION_STATUS = "TitleOptionStatus"; - inline constexpr std::string_view TITLEOPTION = "TitleOptions"; - inline constexpr std::string_view TRANSLATION = "TranslationInfo"; - inline constexpr std::string_view USEROPTION_CONFS = "UserOptionConfirmations"; - inline constexpr std::string_view USEROPTION_STATUS = "UserOptionStatus"; - inline constexpr std::string_view USEROPTION_MENU = "UserOptions"; - inline constexpr std::string_view WEBDAV = "WebDavStrings"; - inline constexpr std::string_view YES_NO_OK = "YesNoOK"; - } + inline constexpr std::string_view BACKUPMENU_MENU = "BackupMenu"; + inline constexpr std::string_view BACKUPMENU_CONFS = "BackupMenuConfirmations"; + inline constexpr std::string_view BACKUPMENU_POPS = "BackupMenuPops"; + inline constexpr std::string_view BACKUPMENU_STATUS = "BackupMenuStatus"; + inline constexpr std::string_view CONTROL_GUIDES = "ControlGuides"; + inline constexpr std::string_view DATA_LOADING_STATUS = "DataLoadingStatus"; + inline constexpr std::string_view EXTRASMENU_MENU = "ExtrasMenu"; + inline constexpr std::string_view EXTRASMENU_POPS = "ExtrasPops"; + inline constexpr std::string_view FILEOPTION_MENU = "FileOptionMenu"; + inline constexpr std::string_view FILEOPTION_CONFS = "FileOptionConfs"; + inline constexpr std::string_view FILEOPTION_MESSAGES = "FileOptionMessages"; + inline constexpr std::string_view FILEOPTION_STATUS = "FileOptionStatus"; + inline constexpr std::string_view FILEMODE_POPS = "FileModePops"; + inline constexpr std::string_view GENERAL_POPS = "GeneralPops"; + inline constexpr std::string_view GOOGLE_DRIVE = "GoogleDriveStrings"; + inline constexpr std::string_view HOLDING_STRINGS = "HoldingStrings"; + inline constexpr std::string_view IO_STATUSES = "IOStatuses"; + inline constexpr std::string_view IO_POPS = "IOPops"; + inline constexpr std::string_view KEYBOARD = "KeyboardStrings"; + inline constexpr std::string_view MAINMENU_CONFS = "MainMenuConfs"; + inline constexpr std::string_view MAINMENU_POPS = "MainMenuPops"; + inline constexpr std::string_view ON_OFF = "OnOff"; + inline constexpr std::string_view REMOTE_POPS = "RemotePops"; + inline constexpr std::string_view SAVECREATE_POPS = "SaveCreatePops"; + inline constexpr std::string_view SAVE_DATA_TYPES = "SaveDataTypes"; + inline constexpr std::string_view SETTINGS_DESCRIPTIONS = "SettingsDescriptions"; + inline constexpr std::string_view SETTINGS_MENU = "SettingsMenu"; + inline constexpr std::string_view SETTINGS_POPS = "SettingsPops"; + inline constexpr std::string_view SORT_TYPES = "SortTypes"; + inline constexpr std::string_view TITLEINFO = "TitleInfo"; + inline constexpr std::string_view TITLEOPTION_CONFS = "TitleOptionConfirmations"; + inline constexpr std::string_view TITLEOPTION_POPS = "TitleOptionPops"; + inline constexpr std::string_view TITLEOPTION_STATUS = "TitleOptionStatus"; + inline constexpr std::string_view TITLEOPTION = "TitleOptions"; + inline constexpr std::string_view TRANSLATION = "TranslationInfo"; + inline constexpr std::string_view USEROPTION_CONFS = "UserOptionConfirmations"; + inline constexpr std::string_view USEROPTION_STATUS = "UserOptionStatus"; + inline constexpr std::string_view USEROPTION_MENU = "UserOptions"; + inline constexpr std::string_view WEBDAV = "WebDavStrings"; + inline constexpr std::string_view YES_NO_OK = "YesNoOK"; } diff --git a/include/strings/strings.hpp b/include/strings/strings.hpp index 3d9ae9e..2eb2231 100644 --- a/include/strings/strings.hpp +++ b/include/strings/strings.hpp @@ -9,5 +9,5 @@ namespace strings bool initialize(); // Returns string with name and index. Returns nullptr if string doesn't exist. - const char *get_by_name(std::string_view name, int index); + const char *get_by_name(std::string_view name, int index) noexcept; } // namespace strings diff --git a/include/sys/ProgressTask.hpp b/include/sys/ProgressTask.hpp index b5cfc30..27c5bed 100644 --- a/include/sys/ProgressTask.hpp +++ b/include/sys/ProgressTask.hpp @@ -24,22 +24,22 @@ namespace sys /// @brief Resets the progress and sets a new goal. /// @param goal The goal we all strive for. - void reset(double goal); + void reset(double goal) noexcept; /// @brief Updates the current progress. /// @param current The current progress value. - void update_current(double current); + void update_current(double current) noexcept; /// @brief Increases the current progress by a set amount. - void increase_current(double amount); + void increase_current(double amount) noexcept; /// @brief Returns the goal value. /// @return Goal - double get_goal() const; + double get_goal() const noexcept; /// @brief Returns the current progress. /// @return Current progress. - double get_progress() const; + double get_progress() const noexcept; private: // Current value and goal diff --git a/include/sys/Task.hpp b/include/sys/Task.hpp index 6fb43a5..fd3c855 100644 --- a/include/sys/Task.hpp +++ b/include/sys/Task.hpp @@ -31,18 +31,18 @@ namespace sys /// @brief Returns if the thread has signaled it's finished running. /// @return True if the thread is still running. False if it isn't. - bool is_running() const; + bool is_running() const noexcept; /// @brief Allows thread to signal it's finished. /// @note Spawned task threads must call this when their work is finished. - void complete(); + void complete() noexcept; /// @brief Sets the task/threads current status string. Thread safe. void set_status(std::string_view status); /// @brief Returns the status string. Thread safe. /// @return Copy of the status string. - std::string get_status(); + std::string get_status() noexcept; protected: // Whether task is still running. diff --git a/include/sys/Timer.hpp b/include/sys/Timer.hpp index d156b25..299c347 100644 --- a/include/sys/Timer.hpp +++ b/include/sys/Timer.hpp @@ -13,18 +13,18 @@ namespace sys /// @brief Constructs a new timer. /// @param triggerTicks Number of ticks the timer is triggered at. - Timer(uint64_t triggerTicks); + Timer(uint64_t triggerTicks) noexcept; /// @brief Starts the timer. /// @param triggerTicks Number of ticks to trigger at. - void start(uint64_t triggerTicks); + void start(uint64_t triggerTicks) noexcept; /// @brief Updates and returns if the timer was triggered. /// @return True if timer is triggered. False if it isn't. - bool is_triggered(); + bool is_triggered() noexcept; /// @brief Forces the timer to restart. - void restart(); + void restart() noexcept; private: /// @brief Tick count when the timer starts. diff --git a/include/tasks/backup.hpp b/include/tasks/backup.hpp index a405b65..1559275 100644 --- a/include/tasks/backup.hpp +++ b/include/tasks/backup.hpp @@ -4,40 +4,37 @@ #include -namespace tasks +namespace tasks::backup { - namespace backup - { - /// @brief Task/thread function executed when a new backup is created. - void create_new_backup_local(sys::ProgressTask *task, - data::User *user, - data::TitleInfo *titleInfo, - fslib::Path target, - BackupMenuState *spawningState, - bool killTask = true); - void create_new_backup_remote(sys::ProgressTask *task, - data::User *user, - data::TitleInfo *titleInfo, - std::string remoteName, - BackupMenuState *spawningState, - bool killTask = true); + /// @brief Task/thread function executed when a new backup is created. + void create_new_backup_local(sys::ProgressTask *task, + data::User *user, + data::TitleInfo *titleInfo, + fslib::Path target, + BackupMenuState *spawningState, + bool killTask = true); + void create_new_backup_remote(sys::ProgressTask *task, + data::User *user, + data::TitleInfo *titleInfo, + std::string remoteName, + BackupMenuState *spawningState, + bool killTask = true); - /// @brief Overwrites a pre-existing backup. - void overwrite_backup_local(sys::ProgressTask *task, BackupMenuState::TaskData taskData); - void overwrite_backup_remote(sys::ProgressTask *task, BackupMenuState::TaskData taskData); + /// @brief Overwrites a pre-existing backup. + void overwrite_backup_local(sys::ProgressTask *task, BackupMenuState::TaskData taskData); + void overwrite_backup_remote(sys::ProgressTask *task, BackupMenuState::TaskData taskData); - /// @brief Restores a backup - void restore_backup_local(sys::ProgressTask *task, BackupMenuState::TaskData taskData); - void restore_backup_remote(sys::ProgressTask *task, BackupMenuState::TaskData taskData); + /// @brief Restores a backup + void restore_backup_local(sys::ProgressTask *task, BackupMenuState::TaskData taskData); + void restore_backup_remote(sys::ProgressTask *task, BackupMenuState::TaskData taskData); - /// @brief Deletes a backup - void delete_backup_local(sys::Task *task, BackupMenuState::TaskData taskData); - void delete_backup_remote(sys::Task *task, BackupMenuState::TaskData taskData); + /// @brief Deletes a backup + void delete_backup_local(sys::Task *task, BackupMenuState::TaskData taskData); + void delete_backup_remote(sys::Task *task, BackupMenuState::TaskData taskData); - /// @brief Uploads a backup - void upload_backup(sys::ProgressTask *task, BackupMenuState::TaskData taskData); + /// @brief Uploads a backup + void upload_backup(sys::ProgressTask *task, BackupMenuState::TaskData taskData); - /// @brief Patches a pre-existing backup on the remote storage. - void patch_backup(sys::ProgressTask *task, BackupMenuState::TaskData taskData); - } + /// @brief Patches a pre-existing backup on the remote storage. + void patch_backup(sys::ProgressTask *task, BackupMenuState::TaskData taskData); } diff --git a/include/tasks/fileoptions.hpp b/include/tasks/fileoptions.hpp new file mode 100644 index 0000000..bf7b922 --- /dev/null +++ b/include/tasks/fileoptions.hpp @@ -0,0 +1,12 @@ +#pragma once +#include "appstates/FileOptionState.hpp" +#include "sys/sys.hpp" + +namespace tasks::fileoptions +{ + /// @brief Copies the source to destination passed through taskData. + void copy_source_to_destination(sys::ProgressTask *task, FileOptionState::TaskData taskData); + + /// @brief Deletes the source path passed through taskData + void delete_target(sys::Task *task, FileOptionState::TaskData taskData); +} \ No newline at end of file diff --git a/include/tasks/mainmenu.hpp b/include/tasks/mainmenu.hpp index 1e1fac4..9696ccb 100644 --- a/include/tasks/mainmenu.hpp +++ b/include/tasks/mainmenu.hpp @@ -2,11 +2,8 @@ #include "appstates/MainMenuState.hpp" #include "sys/sys.hpp" -namespace tasks +namespace tasks::mainmenu { - namespace mainmenu - { - void backup_all_for_all_local(sys::ProgressTask *task, MainMenuState::TaskData taskData); - void backup_all_for_all_remote(sys::ProgressTask *task, MainMenuState::TaskData taskData); - } + void backup_all_for_all_local(sys::ProgressTask *task, MainMenuState::TaskData taskData); + void backup_all_for_all_remote(sys::ProgressTask *task, MainMenuState::TaskData taskData); } diff --git a/include/tasks/savecreate.hpp b/include/tasks/savecreate.hpp index e3ba05b..468df2f 100644 --- a/include/tasks/savecreate.hpp +++ b/include/tasks/savecreate.hpp @@ -3,13 +3,7 @@ #include "data/data.hpp" #include "sys/sys.hpp" -namespace tasks +namespace tasks::savecreate { - namespace savecreate - { - void create_save_data_for(sys::Task *task, - data::User *user, - data::TitleInfo *titleInfo, - SaveCreateState *spawningState); - } + void create_save_data_for(sys::Task *task, data::User *user, data::TitleInfo *titleInfo, SaveCreateState *spawningState); } diff --git a/include/tasks/titleoptions.hpp b/include/tasks/titleoptions.hpp index b6b29d3..bc9e364 100644 --- a/include/tasks/titleoptions.hpp +++ b/include/tasks/titleoptions.hpp @@ -3,26 +3,23 @@ #include "appstates/TitleOptionState.hpp" #include "sys/sys.hpp" -namespace tasks +namespace tasks::titleoptions { - namespace titleoptions - { - /// @brief Adds a title to the blacklist. Needs to be task formatted to work with confirmations. - void blacklist_title(sys::Task *task, TitleOptionState::TaskData taskData); + /// @brief Adds a title to the blacklist. Needs to be task formatted to work with confirmations. + void blacklist_title(sys::Task *task, TitleOptionState::TaskData taskData); - /// @brief Wipes deletes all local backups for the current title. - void delete_all_local_backups_for_title(sys::Task *task, TitleOptionState::TaskData taskData); + /// @brief Wipes deletes all local backups for the current title. + void delete_all_local_backups_for_title(sys::Task *task, TitleOptionState::TaskData taskData); - /// @brief Deletes all backups found on the remote storage service. - void delete_all_remote_backups_for_title(sys::Task *task, TitleOptionState::TaskData taskData); + /// @brief Deletes all backups found on the remote storage service. + void delete_all_remote_backups_for_title(sys::Task *task, TitleOptionState::TaskData taskData); - /// @brief Resets save data for the current title. - void reset_save_data(sys::Task *task, TitleOptionState::TaskData taskData); + /// @brief Resets save data for the current title. + void reset_save_data(sys::Task *task, TitleOptionState::TaskData taskData); - /// @brief Deletes the save data from the system the same way Data Management does. - void delete_save_data_from_system(sys::Task *task, TitleOptionState::TaskData taskData); + /// @brief Deletes the save data from the system the same way Data Management does. + void delete_save_data_from_system(sys::Task *task, TitleOptionState::TaskData taskData); - /// @brief Extends the save container for the current save info. - void extend_save_data(sys::Task *task, TitleOptionState::TaskData taskData); - } + /// @brief Extends the save container for the current save info. + void extend_save_data(sys::Task *task, TitleOptionState::TaskData taskData); } diff --git a/include/tasks/useroptions.hpp b/include/tasks/useroptions.hpp index 048e314..fbdefc8 100644 --- a/include/tasks/useroptions.hpp +++ b/include/tasks/useroptions.hpp @@ -2,13 +2,10 @@ #include "appstates/UserOptionState.hpp" #include "sys/sys.hpp" -namespace tasks +namespace tasks::useroptions { - namespace useroptions - { - void backup_all_for_user_local(sys::ProgressTask *task, UserOptionState::TaskData taskData); - void backup_all_for_user_remote(sys::ProgressTask *task, UserOptionState::TaskData taskData); - void create_all_save_data_for_user(sys::Task *task, UserOptionState::TaskData taskData); - void delete_all_save_data_for_user(sys::Task *task, UserOptionState::TaskData taskData); - } + void backup_all_for_user_local(sys::ProgressTask *task, UserOptionState::TaskData taskData); + void backup_all_for_user_remote(sys::ProgressTask *task, UserOptionState::TaskData taskData); + void create_all_save_data_for_user(sys::Task *task, UserOptionState::TaskData taskData); + void delete_all_save_data_for_user(sys::Task *task, UserOptionState::TaskData taskData); } diff --git a/include/ui/BoundingBox.hpp b/include/ui/BoundingBox.hpp index bf7db12..ec45566 100644 --- a/include/ui/BoundingBox.hpp +++ b/include/ui/BoundingBox.hpp @@ -17,9 +17,6 @@ namespace ui /// @param height Height of the box in pixels. BoundingBox(int x, int y, int width, int height); - /// @brief Required destructor. - ~BoundingBox() {}; - /// @brief Creates a returns a new BoundingBox. See constructor. static inline std::shared_ptr create(int x, int y, int width, int height) { @@ -32,18 +29,17 @@ namespace ui /// @brief Render override. void render(sdl::SharedTexture &target, bool hasFocus) override; - /// @brief Sets the X and Y coord. - /// @param x New X coord. - /// @param y New Y coord. - void set_xy(int x, int y); + /// @brief Sets the X coord. + void set_x(int x) noexcept; - /// @brief Sets the width and height of the bounding box. - /// @param width New width. - /// @param height New height. - void set_width_height(int width, int height); + /// @brief Sets the Y coord. + void set_y(int y) noexcept; - /// @brief Passing this to the set functions will keep the same coord. - static inline constexpr int NO_SET = -1; + /// @brief Sets the width. + void set_width(int width) noexcept; + + /// @brief Sets the height. + void set_height(int height) noexcept; private: /// @brief X coord to render to. diff --git a/include/ui/ColorMod.hpp b/include/ui/ColorMod.hpp index 2a6915e..5883a99 100644 --- a/include/ui/ColorMod.hpp +++ b/include/ui/ColorMod.hpp @@ -1,5 +1,6 @@ #pragma once #include "sdl.hpp" + #include namespace ui @@ -12,11 +13,11 @@ namespace ui ColorMod() = default; /// @brief Updates the color modification variable. - void update(); + void update() noexcept; /// @brief Operator that allows using this as an sdl::Color directly. /// @note Since all of these pulse the same color, no sense in not doing this. - operator sdl::Color() const; + operator sdl::Color() const noexcept; private: /// @brief Whether we're adding or subtracting from the color value. diff --git a/include/ui/DialogBox.hpp b/include/ui/DialogBox.hpp index cfb0e4b..e7cfc50 100644 --- a/include/ui/DialogBox.hpp +++ b/include/ui/DialogBox.hpp @@ -22,9 +22,6 @@ namespace ui /// @param type Optional. The type of box. Default is dark since JKSV rewrite doesn't do theme detection. DialogBox(int x, int y, int width, int height, DialogBox::Type type = DialogBox::Type::Dark); - /// @brief Required destructor. - ~DialogBox() {}; - /// @brief Creates and returns a new DialogBox instance. See constructor. static inline std::shared_ptr create(int x, int y, @@ -43,14 +40,17 @@ namespace ui /// @param hasFocus This is ignored. void render(sdl::SharedTexture &target, bool hasFocus) override; - /// @brief Sets the X and coords for the dialog box. - void set_xy(int x, int y); + /// @brief Sets the X render coord. + void set_x(int x) noexcept; - /// @brief Sets the width and height of the dialog. - void set_width_height(int width, int height); + /// @brief Sets the X render coord. + void set_y(int y) noexcept; - /// @brief Pass with the set functions to not change. - static inline constexpr int NO_SET = -1; + /// @brief Sets the width. + void set_width(int width) noexcept; + + /// @brief Sets the height. + void set_height(int height) noexcept; private: /// @brief X render coord. diff --git a/include/ui/Element.hpp b/include/ui/Element.hpp index cb8b76d..4535f31 100644 --- a/include/ui/Element.hpp +++ b/include/ui/Element.hpp @@ -11,7 +11,7 @@ namespace ui Element() = default; /// @brief Virtual destructor. - virtual ~Element() {}; + virtual ~Element() noexcept {}; /// @brief Virtual update method. All derived classes must have this. /// @param HasFocus Whether or not the state containing the element currently has focus. diff --git a/include/ui/Frame.hpp b/include/ui/Frame.hpp new file mode 100644 index 0000000..b90d8d2 --- /dev/null +++ b/include/ui/Frame.hpp @@ -0,0 +1,58 @@ +#pragma once +#include "sdl.hpp" +#include "ui/Element.hpp" + +#include + +namespace ui +{ + class Frame final : public ui::Element + { + public: + /// @brief Constructs a new frame. + Frame(int x, int y, int width, int height); + + /// @brief Inline function to make constructing nicer. + static inline std::shared_ptr create(int x, int y, int width, int height) + { + return std::make_shared(x, y, width, height); + } + + /// @brief Doesn't need to do anything for this. + void update(bool hasFocus) override {}; + + /// @brief Renders the frame to the target passed. + void render(sdl::SharedTexture &target, bool hasFocus) override; + + /// @brief Sets the X coord. + void set_x(int x) noexcept; + + /// @brief Sets the Y coord. + void set_y(int y) noexcept; + + /// @brief Sets the width of the frame. + void set_width(int width) noexcept; + + /// @brief Sets the height of the frame. + void set_height(int height) noexcept; + + private: + /// @brief X rendering coord. + int m_x{}; + + /// @brief Y rendering coord. + int m_y{}; + + /// @brief Rendering width. + int m_width{}; + + /// @brief Rendering height. + int m_height{}; + + /// @brief This texture is shared by all instances. + static inline sdl::SharedTexture sm_frameCorners{}; + + /// @brief Ensures the texture is loading if it hasn't been. + void initialize_static_members(); + }; +} \ No newline at end of file diff --git a/include/ui/IconMenu.hpp b/include/ui/IconMenu.hpp index 0d8565f..7821b4b 100644 --- a/include/ui/IconMenu.hpp +++ b/include/ui/IconMenu.hpp @@ -18,9 +18,6 @@ namespace ui /// @param renderTargetHeight Height of the render target to calculate how many options can be displayed at once. IconMenu(int x, int y, int renderTargetHeight); - /// @brief Required destructor. - ~IconMenu() {}; - /// @brief Creates and returns a new IconMenu instance. static inline std::shared_ptr create(int x, int y, int renderTargetHeight) { diff --git a/include/ui/Menu.hpp b/include/ui/Menu.hpp index 70daaec..e2bf6f9 100644 --- a/include/ui/Menu.hpp +++ b/include/ui/Menu.hpp @@ -51,15 +51,24 @@ namespace ui /// @brief Returns the index of the currently selected menu option. /// @return Index of currently selected option. - int get_selected() const; + int get_selected() const noexcept; /// @brief Sets the selected item. /// @param selected Value to set selected to. void set_selected(int selected); + /// @brief Updates the X render coordinate. + void set_x(int x) noexcept; + + /// @brief Updates the Y render coordinate. + void set_y(int y) noexcept; + /// @brief This is a workaround function until I find something better. /// @param width New width of the menu in pixels. - void set_width(int width); + void set_width(int width) noexcept; + + /// @brief Returns if the menu has no options. + bool is_empty() const noexcept; /// @brief Resets the menu and returns it to an empty, default state. void reset(); diff --git a/include/ui/PopMessage.hpp b/include/ui/PopMessage.hpp index 34c7bf8..f75d3fd 100644 --- a/include/ui/PopMessage.hpp +++ b/include/ui/PopMessage.hpp @@ -19,10 +19,10 @@ namespace ui void render(); /// @brief Returns whether or not the message can be purged. - bool finished() const; + bool finished() const noexcept; /// @brief Returns the text of the message. - std::string_view get_message() const; + std::string_view get_message() const noexcept; private: // Every message begins off screen. @@ -65,9 +65,9 @@ namespace ui std::shared_ptr m_dialog{}; /// @brief Updates the Y Coord to match the target passed. - void update_y(double targetY); + void update_y(double targetY) noexcept; /// @brief Updates the current end offset of the text. - void update_text_offset(); + void update_text_offset() noexcept; }; } diff --git a/include/ui/SlideOutPanel.hpp b/include/ui/SlideOutPanel.hpp index c56ed03..37e8e60 100644 --- a/include/ui/SlideOutPanel.hpp +++ b/include/ui/SlideOutPanel.hpp @@ -35,6 +35,9 @@ namespace ui /// @param hasFocus Whether or not the calling state has focus. void update(bool hasFocus) override; + /// @brief Sub update routine. Allows the panel to hide and unhide itself even when not in focus. + void sub_update(); + /// @brief Runs the render routine. /// @param target Target to render to. /// @param hasFocus Whether or the the calling state has focus. @@ -44,18 +47,27 @@ namespace ui void clear_target(); /// @brief Resets the panel back to its default state. - void reset(); + void reset() noexcept; /// @brief Closes the panel. - void close(); + void close() noexcept; + + /// @brief Hides the panel temporarily. + void hide() noexcept; + + /// @brief Unhides the panel. + void unhide() noexcept; /// @brief Returns if the panel is fully open. /// @return If the panel is fully open. - bool is_open() const; + bool is_open() const noexcept; /// @brief Returns if the panel is fully closed. /// @return If the panel is fully closed. - bool is_closed(); + bool is_closed() noexcept; + + /// @brief Returns whether or not the panel is hidden. + bool is_hidden() const noexcept; /// @brief Pushes a new element to the element vector. /// @param newElement New element to push. @@ -66,7 +78,7 @@ namespace ui /// @brief Returns a pointer to the render target of the panel. /// @return Raw SDL_Texture pointer to target. - sdl::SharedTexture &get_target(); + sdl::SharedTexture &get_target() noexcept; private: /// @brief Bool for whether panel is fully open or not. @@ -75,6 +87,9 @@ namespace ui /// @brief Whether or not to close panel. bool m_closePanel{}; + /// @brief Whether or not to hide the panel. + bool m_hidePanel{}; + /// @brief Current X coordinate to render to. Panels are always 720 pixels in height so no Y is required. double m_x{}; @@ -93,10 +108,16 @@ namespace ui /// @brief Vector of elements. std::vector> m_elements{}; - void slide_out_left(); + /// @brief Handles sliding out logic. + void slide_out() noexcept; - void slide_out_right(); + /// @brief Slides the panel out from the left side. + void slide_out_left() noexcept; - int get_absolute_x_distance(); + /// @brief Slides the panel out from the right side. + void slide_out_right() noexcept; + + /// @brief Contains the logic for hiding/closing the panel. + void close_hide_panel() noexcept; }; } // namespace ui diff --git a/include/ui/TextScroll.hpp b/include/ui/TextScroll.hpp index 2bc64a2..9512f9a 100644 --- a/include/ui/TextScroll.hpp +++ b/include/ui/TextScroll.hpp @@ -32,9 +32,6 @@ namespace ui sdl::Color clearColor, bool center = true); - /// @brief Required destructor. - ~TextScroll() {}; - /// @brief Creates and returns a new TextScroll. See constructor. static inline std::shared_ptr create(std::string_view text, int x, @@ -76,14 +73,11 @@ namespace ui void render(sdl::SharedTexture &target, bool hasFocus) override; /// @brief Returns the current text being used for scrolling. - std::string_view get_text() const; + std::string_view get_text() const noexcept; /// @brief Sets and allows changing the text scrolled. void set_text(std::string_view text, bool center); - /// @brief Allows setting of the X and Y render coordinates. - void set_xy(int x, int y); - private: /// @brief Text to display. std::string m_text{}; diff --git a/include/ui/TitleTile.hpp b/include/ui/TitleTile.hpp index 133ac7c..8db9f29 100644 --- a/include/ui/TitleTile.hpp +++ b/include/ui/TitleTile.hpp @@ -23,22 +23,22 @@ namespace ui void render(sdl::SharedTexture &target, int x, int y); /// @brief Resets the width and height of the tile. - void reset(); + void reset() noexcept; /// @brief Returns the render width in pixels. /// @return Render width. - int get_width() const; + int get_width() const noexcept; /// @brief Returns the render height in pixels. /// @return Render height. - int get_height() const; + int get_height() const noexcept; private: /// @brief Width in pixels to render icon at. - int m_renderWidth = 128; + int m_renderWidth{128}; /// @brief Height in pixels to render icon at. - int m_renderHeight = 128; + int m_renderHeight{128}; /// @brief Whether or not the title is a favorite. bool m_isFavorite{}; diff --git a/include/ui/TitleView.hpp b/include/ui/TitleView.hpp index dc5aa4e..0c33d88 100644 --- a/include/ui/TitleView.hpp +++ b/include/ui/TitleView.hpp @@ -18,9 +18,6 @@ namespace ui /// @param user User to use. TitleView(data::User *user); - /// @brief Required destructor. - ~TitleView() {}; - static inline std::shared_ptr create(data::User *user) { return std::make_shared(user); @@ -37,10 +34,10 @@ namespace ui /// @brief Returns index of the currently selected tile. /// @return Index of currently selected tile. - int get_selected() const; + int get_selected() const noexcept; /// @brief Sets the currently selected item. - void set_selected(int selected); + void set_selected(int selected) noexcept; /// @brief Forces a refresh of the view. void refresh(); diff --git a/include/ui/ui.hpp b/include/ui/ui.hpp index ea55e48..7427b18 100644 --- a/include/ui/ui.hpp +++ b/include/ui/ui.hpp @@ -3,6 +3,7 @@ #include "ui/ColorMod.hpp" #include "ui/DialogBox.hpp" #include "ui/Element.hpp" +#include "ui/Frame.hpp" #include "ui/IconMenu.hpp" #include "ui/Menu.hpp" #include "ui/PopMessageManager.hpp" diff --git a/romfs/Text/ENUS.json b/romfs/Text/ENUS.json index a9ca782..2c4ad0c 100644 --- a/romfs/Text/ENUS.json +++ b/romfs/Text/ENUS.json @@ -33,7 +33,8 @@ "0: [A] Select [Y] Dump All Saves [X] User Options", "1: [A] Select [L] [R] Jump [Y] Favorite [X] Title Options [B] Back", "2: [A] Select [Y] Restore [X] Delete [ZR] Upload [B] Close", - "3: [A] Toggle [-] Description [X] Defaults [B] Back" + "3: [A] Toggle [-] Description [X] Defaults [B] Back", + "4: [A] Enter [B] Back/Up [X] Options [ZL]/[ZR] Change Target [-] Close" ], "DataLoadingStatus": [ "0: Loading user accounts from system...", @@ -58,6 +59,35 @@ "0: Data reinitialized!", "1: Data reinitialization failed!" ], + "FileOptionMenu": [ + "0: Copy", + "1: Delete", + "2: Rename", + "3: Create Folder", + "4: Properties", + "5: Close" + ], + "FileOptionConfs": [ + "0: Are you sure you want to copy #%s# to #%s#?", + "1: Are you sure you want to delete #%s#?" + ], + "FileOptionMessages": [ + "0: #%s#:\n\t\tSub Directories: %lli\n\t\tFile count: %lli\n\t\tTotal Size: %s", + "1: #%s#:\n\t\tSize: %s\n\t\tFirst created: %s\n\t\tLast modified: %s\n\t\tLast Accessed: %s" + ], + "FileOptionStatus": [ + "0: Reading #%s#'s data..." + ], + "FileModePops": [ + "0: Copied #%s#!", + "1: Failed to copy #%s#!", + "2: Deleted #%s#!", + "3: Failed to delete #%s#!", + "4: Renamed #%s# to #%s#!", + "5: Failed to rename #%s#!", + "6: Created #%s#!", + "7: Failed to create #%s#!" + ], "GeneralPops": [ "0: Unable to exit JKSV while tasks are running!" ], @@ -92,7 +122,8 @@ "5: Enter a new name for the target item.", "6: Enter a name for the new folder.", "7: Enter a new output folder name for %s.", - "8: Enter how much to expand (in MB)." + "8: Enter how much to expand (in MB).", + "9: Enter a new name for %s." ], "MainMenuConfs": [ "0: Are you sure you want to backup the save data for every user on this system? This can take an *extremely* long time!" @@ -258,4 +289,4 @@ "1: No [B]", "2: OK [A]" ] -} +} \ No newline at end of file diff --git a/romfs/Textures/Frame.png b/romfs/Textures/Frame.png new file mode 100644 index 0000000..5f5003e Binary files /dev/null and b/romfs/Textures/Frame.png differ diff --git a/source/JKSV.cpp b/source/JKSV.cpp index 0cb08bc..176c459 100644 --- a/source/JKSV.cpp +++ b/source/JKSV.cpp @@ -1,15 +1,16 @@ #include "JKSV.hpp" #include "StateManager.hpp" +#include "appstates/FileModeState.hpp" #include "appstates/MainMenuState.hpp" #include "appstates/TaskState.hpp" #include "config/config.hpp" #include "curl/curl.hpp" #include "data/data.hpp" +#include "error.hpp" #include "fslib.hpp" #include "graphics/colors.hpp" #include "input.hpp" -#include "logging/error.hpp" #include "logging/logger.hpp" #include "remote/remote.hpp" #include "sdl.hpp" @@ -30,9 +31,21 @@ namespace /// @brief Build month. constexpr uint8_t BUILD_MON = 8; /// @brief Build day. - constexpr uint8_t BUILD_DAY = 25; + constexpr uint8_t BUILD_DAY = 29; /// @brief Year. constexpr uint16_t BUILD_YEAR = 2025; + + /// @brief Config for socket. + constexpr SocketInitConfig SOCKET_INIT_CONFIG = {.tcp_tx_buf_size = 0x20000, + .tcp_rx_buf_size = 0x20000, + .tcp_tx_buf_max_size = 0x80000, + .tcp_rx_buf_max_size = 0x80000, + .udp_tx_buf_size = 0x2400, + .udp_rx_buf_size = 0xA500, + .sb_efficiency = 8, + .num_bsd_sessions = 3, + .bsd_service_type = BsdServiceType_User}; + } // namespace template @@ -86,11 +99,11 @@ JKSV::~JKSV() JKSV::exit_services(); sdl::text::exit(); sdl::exit(); - fslib::exit(); + appletSetCpuBoostMode(ApmCpuBoostMode_Normal); } -bool JKSV::is_running() const { return m_isRunning; } +bool JKSV::is_running() const noexcept { return m_isRunning; } void JKSV::update() { @@ -133,10 +146,11 @@ void JKSV::render() bool JKSV::initialize_filesystem() { // This needs to be in this specific order - const bool fslib = fslib::initialize(); + const bool fslib = fslib::is_initialized(); const bool romfs = initialize_service(romfsInit, "RomFS"); const bool fslibDev = fslib && fslib::dev::initialize_sdmc(); if (!fslib || !romfs || !fslibDev) { return false; } + return true; } @@ -150,7 +164,7 @@ bool JKSV::initialize_services() serviceInit = serviceInit && initialize_service(pmshellInitialize, "PMShell"); serviceInit = serviceInit && initialize_service(setInitialize, "Set"); serviceInit = serviceInit && initialize_service(setsysInitialize, "SetSys"); - serviceInit = serviceInit && initialize_service(socketInitializeDefault, "Socket"); + serviceInit = serviceInit && initialize_service(socketInitialize, "Socket", &SOCKET_INIT_CONFIG); serviceInit = serviceInit && initialize_service(nifmInitialize, "NIFM", NifmServiceType_User); return serviceInit; } diff --git a/source/StateManager.cpp b/source/StateManager.cpp index 2e5a43a..0d74e3b 100644 --- a/source/StateManager.cpp +++ b/source/StateManager.cpp @@ -24,6 +24,9 @@ void StateManager::update() if (stateVector.empty()) { return; } + // Run sub update routines. + for (auto &state : stateVector) { state->sub_update(); } + std::shared_ptr &back = stateVector.back(); if (!back->has_focus()) { back->give_focus(); } back->update(); diff --git a/source/appstates/BackupMenuState.cpp b/source/appstates/BackupMenuState.cpp index 58a0d68..62b7fe7 100644 --- a/source/appstates/BackupMenuState.cpp +++ b/source/appstates/BackupMenuState.cpp @@ -5,12 +5,12 @@ #include "appstates/FadeState.hpp" #include "appstates/ProgressState.hpp" #include "config/config.hpp" +#include "error.hpp" #include "fs/fs.hpp" #include "fslib.hpp" #include "graphics/colors.hpp" #include "input.hpp" #include "keyboard.hpp" -#include "logging/error.hpp" #include "sdl.hpp" #include "strings/strings.hpp" #include "stringutil.hpp" @@ -127,7 +127,7 @@ void BackupMenuState::refresh() } int index{}; - for (const fslib::DirectoryEntry &entry : m_directoryListing.list()) + for (const fslib::DirectoryEntry &entry : m_directoryListing) { sm_backupMenu->add_option(entry.get_filename()); m_menuEntries.push_back({MenuEntryType::Local, index++}); diff --git a/source/appstates/BaseState.cpp b/source/appstates/BaseState.cpp index 615929a..c7f1d20 100644 --- a/source/appstates/BaseState.cpp +++ b/source/appstates/BaseState.cpp @@ -1,6 +1,6 @@ #include "appstates/BaseState.hpp" -#include "logging/error.hpp" +#include "error.hpp" #include diff --git a/source/appstates/BlacklistEditState.cpp b/source/appstates/BlacklistEditState.cpp index b663e67..1962ce3 100644 --- a/source/appstates/BlacklistEditState.cpp +++ b/source/appstates/BlacklistEditState.cpp @@ -4,8 +4,8 @@ #include "appstates/MainMenuState.hpp" #include "config/config.hpp" #include "data/data.hpp" +#include "error.hpp" #include "input.hpp" -#include "logging/error.hpp" BlacklistEditState::BlacklistEditState() : BaseState() diff --git a/source/appstates/ExtrasMenuState.cpp b/source/appstates/ExtrasMenuState.cpp index 81e1f7d..c0c970a 100644 --- a/source/appstates/ExtrasMenuState.cpp +++ b/source/appstates/ExtrasMenuState.cpp @@ -1,7 +1,9 @@ #include "appstates/ExtrasMenuState.hpp" +#include "appstates/FileModeState.hpp" #include "appstates/MainMenuState.hpp" #include "data/data.hpp" +#include "error.hpp" #include "graphics/colors.hpp" #include "input.hpp" #include "keyboard.hpp" @@ -50,7 +52,13 @@ void ExtrasMenuState::update() { switch (m_extrasMenu.get_selected()) { - case REINIT_DATA: ExtrasMenuState::reinitialize_data(); break; + case REINIT_DATA: ExtrasMenuState::reinitialize_data(); break; + case SD_TO_SD_BROWSER: ExtrasMenuState::sd_to_sd_browser(); break; + case BIS_PRODINFO_F: ExtrasMenuState::prodinfof_to_sd(); break; + case BIS_SAFE: ExtrasMenuState::safe_to_sd(); break; + case BIS_SYSTEM: ExtrasMenuState::system_to_sd(); break; + case BIS_USER: ExtrasMenuState::user_to_sd(); break; + case TERMINATE_PROCESS: ExtrasMenuState::terminate_process(); break; } } else if (bPressed) { BaseState::deactivate(); } @@ -75,6 +83,42 @@ void ExtrasMenuState::initialize_menu() void ExtrasMenuState::reinitialize_data() { data::launch_initialization(true, finish_reinitialization); } +void ExtrasMenuState::sd_to_sd_browser() { FileModeState::create_and_push("sdmc", "sdmc", false); } + +void ExtrasMenuState::prodinfof_to_sd() +{ + const bool mountError = error::fslib(fslib::open_bis_filesystem("prodinfo-f", FsBisPartitionId_CalibrationFile)); + if (mountError) { return; } + + FileModeState::create_and_push("prodinfo-f", "sdmc", false); +} + +void ExtrasMenuState::safe_to_sd() +{ + const bool mountError = error::fslib(fslib::open_bis_filesystem("safe", FsBisPartitionId_SafeMode)); + if (mountError) { return; } + + FileModeState::create_and_push("safe", "sdmc", false); +} + +void ExtrasMenuState::system_to_sd() +{ + const bool mountError = error::fslib(fslib::open_bis_filesystem("system", FsBisPartitionId_System)); + if (mountError) { return; } + + FileModeState::create_and_push("system", "sdmc", false); +} + +void ExtrasMenuState::user_to_sd() +{ + const bool mountError = error::fslib(fslib::open_bis_filesystem("user", FsBisPartitionId_User)); + if (mountError) { return; } + + FileModeState::create_and_push("user", "sdmc", false); +} + +void ExtrasMenuState::terminate_process() {} + static void finish_reinitialization() { const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; diff --git a/source/appstates/FileModeState.cpp b/source/appstates/FileModeState.cpp new file mode 100644 index 0000000..5545b22 --- /dev/null +++ b/source/appstates/FileModeState.cpp @@ -0,0 +1,223 @@ +#include "appstates/FileModeState.hpp" + +#include "appstates/FileOptionState.hpp" +#include "config/config.hpp" +#include "graphics/colors.hpp" +#include "input.hpp" +#include "logging/logger.hpp" +#include "mathutil.hpp" +#include "strings/strings.hpp" +#include "stringutil.hpp" + +#include + +FileModeState::FileModeState(std::string_view mountA, std::string_view mountB, int64_t journalSize) + : m_mountA(mountA) + , m_mountB(mountB) + , m_journalSize(journalSize) + , m_y(720.f) + , m_targetY(91.0f) + , m_scaling(config::get_animation_scaling()) +{ + FileModeState::initialize_static_members(); + FileModeState::initialize_paths(); + FileModeState::initialize_menus(); +} + +void FileModeState::update() +{ + FileModeState::update_y_coord(); + if (!m_inPlace) { return; } + + const bool hasFocus = BaseState::has_focus(); + + ui::Menu &menu = FileModeState::get_source_menu(); + fslib::Path &path = FileModeState::get_source_path(); + fslib::Directory &directory = FileModeState::get_source_directory(); + + const bool aPressed = input::button_pressed(HidNpadButton_A); + const bool bPressed = input::button_pressed(HidNpadButton_B); + const bool xPressed = input::button_pressed(HidNpadButton_X); + const bool zlZRPressed = input::button_pressed(HidNpadButton_ZL) || input::button_pressed(HidNpadButton_ZR); + const bool minusPressed = input::button_pressed(HidNpadButton_Minus); + + if (aPressed) { FileModeState::enter_selected(path, directory, menu); } + else if (bPressed) { FileModeState::up_one_directory(path, directory, menu); } + else if (xPressed) { FileModeState::open_option_menu(directory, menu); } + else if (zlZRPressed) { FileModeState::change_target(); } + else if (minusPressed) { FileModeState::hide_dialog(); } + else if (FileModeState::is_hidden()) { FileModeState::deactivate_state(); } + + menu.update(hasFocus); +} + +void FileModeState::render() +{ + const bool hasFocus = BaseState::has_focus(); + + sm_renderTarget->clear(colors::TRANSPARENT); + + // This is here so it's rendered underneath the pop-up frame. + if (hasFocus) { FileModeState::render_control_guide(); } + + sdl::render_line(sm_renderTarget, 617, 0, 617, 538, colors::WHITE); + sdl::render_line(sm_renderTarget, 618, 0, 618, 538, colors::DIALOG_DARK); + + m_dirMenuA->render(sm_renderTarget, hasFocus && m_target == false); + m_dirMenuB->render(sm_renderTarget, hasFocus && m_target); + + sm_frame->render(sdl::Texture::Null, true); + sm_renderTarget->render(sdl::Texture::Null, 23, m_y + 12); +} + +void FileModeState::initialize_static_members() +{ + static constexpr std::string_view RENDER_TARGET_NAME = "FMRenderTarget"; + + static constexpr int CONTROL_GUIDE_START_X = 1220; + + if (sm_frame && sm_renderTarget) { return; } + + sm_frame = ui::Frame::create(15, 720, 1250, 555); + sm_renderTarget = sdl::TextureManager::load(RENDER_TARGET_NAME, 1234, 538, SDL_TEXTUREACCESS_TARGET); + sm_controlGuide = strings::get_by_name(strings::names::CONTROL_GUIDES, 4); + sm_controlGuideX = CONTROL_GUIDE_START_X - sdl::text::get_width(22, sm_controlGuide); +} + +void FileModeState::initialize_paths() +{ + const std::string pathA = m_mountA + ":/"; + const std::string pathB = m_mountB + ":/"; + + m_pathA = pathA; + m_pathB = pathB; +} + +void FileModeState::initialize_menus() +{ + m_dirMenuA = ui::Menu::create(8, 8, 594, 22, 538); + m_dirMenuB = ui::Menu::create(626, 8, 594, 22, 538); + + FileModeState::initialize_directory_menu(m_pathA, m_dirA, *m_dirMenuA.get()); + FileModeState::initialize_directory_menu(m_pathB, m_dirB, *m_dirMenuB.get()); +} + +void FileModeState::initialize_directory_menu(const fslib::Path &path, fslib::Directory &directory, ui::Menu &menu) +{ + static constexpr const char *DIR_PREFIX = "[D] "; + static constexpr const char *FILE_PREFIX = "[F] "; + + directory.open(path); + if (!directory.is_open()) { return; } + + menu.reset(); + menu.add_option("."); + menu.add_option(".."); + + for (const fslib::DirectoryEntry &entry : directory) + { + std::string option{}; + if (entry.is_directory()) { option = DIR_PREFIX; } + else { option = FILE_PREFIX; } + + option += entry.get_filename(); + menu.add_option(option); + } +} + +void FileModeState::update_y_coord() noexcept +{ + if (m_y == m_targetY) { return; } + + const double add = (m_targetY - m_y) / m_scaling; + const double distance = math::Util::absolute_distance(m_targetY, m_y); + m_y += std::round(add); + + // The second condition is a fix for when scaling is 1. + if (distance <= 4 || m_y == m_targetY) + { + m_y = m_targetY; + m_inPlace = true; + } + + sm_frame->set_y(m_y); +} + +void FileModeState::hide_dialog() noexcept +{ + if (!m_inPlace) { return; } + m_targetY = 720; +} + +bool FileModeState::is_hidden() noexcept { return m_inPlace && m_targetY == 720; } + +void FileModeState::enter_selected(fslib::Path &path, fslib::Directory &directory, ui::Menu &menu) +{ + const int selected = menu.get_selected(); + + if (selected == 1) { FileModeState::up_one_directory(path, directory, menu); } + else + { + const int dirIndex = selected - 2; + const fslib::DirectoryEntry &entry = directory[dirIndex]; + if (entry.is_directory()) { FileModeState::enter_directory(path, directory, menu, entry); } + } +} + +void FileModeState::open_option_menu(fslib::Directory &directory, ui::Menu &menu) +{ + const int selected = menu.get_selected(); + + if (selected == 0 || selected > 1) { FileOptionState::create_and_push(this); } +} + +void FileModeState::change_target() { m_target = m_target ? false : true; } + +void FileModeState::up_one_directory(fslib::Path &path, fslib::Directory &directory, ui::Menu &menu) +{ + if (FileModeState::path_is_root(path)) { return; } + + size_t lastSlash = path.find_last_of('/'); + if (lastSlash == path.NOT_FOUND) { return; } + else if (lastSlash <= 0) { lastSlash = 1; } + + fslib::Path newPath{path.sub_path(lastSlash)}; + path = std::move(newPath); + FileModeState::initialize_directory_menu(path, directory, menu); +} + +void FileModeState::enter_directory(fslib::Path &path, + fslib::Directory &directory, + ui::Menu &menu, + const fslib::DirectoryEntry &entry) +{ + if (!entry.is_directory()) { return; } + + path /= entry.get_filename(); + FileModeState::initialize_directory_menu(path, directory, menu); +} + +void FileModeState::render_control_guide() +{ + sdl::text::render(sdl::Texture::Null, sm_controlGuideX, 673, 22, sdl::text::NO_WRAP, colors::WHITE, sm_controlGuide); +} + +ui::Menu &FileModeState::get_source_menu() noexcept { return m_target ? *m_dirMenuB.get() : *m_dirMenuA.get(); } + +ui::Menu &FileModeState::get_destination_menu() noexcept { return m_target ? *m_dirMenuA.get() : *m_dirMenuB.get(); } + +fslib::Path &FileModeState::get_source_path() noexcept { return m_target ? m_pathB : m_pathA; } + +fslib::Path &FileModeState::get_destination_path() noexcept { return m_target ? m_pathA : m_pathB; } + +fslib::Directory &FileModeState::get_source_directory() noexcept { return m_target ? m_dirB : m_dirA; } + +fslib::Directory &FileModeState::get_destination_directory() noexcept { return m_target ? m_dirA : m_dirB; } + +void FileModeState::deactivate_state() noexcept +{ + sm_frame->set_y(720); + fslib::close_file_system(m_mountA); + fslib::close_file_system(m_mountB); + BaseState::deactivate(); +} \ No newline at end of file diff --git a/source/appstates/FileOptionState.cpp b/source/appstates/FileOptionState.cpp new file mode 100644 index 0000000..5f419b6 --- /dev/null +++ b/source/appstates/FileOptionState.cpp @@ -0,0 +1,430 @@ +#include "appstates/FileOptionState.hpp" + +#include "appstates/ConfirmState.hpp" +#include "appstates/MessageState.hpp" +#include "appstates/ProgressState.hpp" +#include "appstates/TaskState.hpp" +#include "config/config.hpp" +#include "error.hpp" +#include "fs/fs.hpp" +#include "fslib.hpp" +#include "input.hpp" +#include "keyboard.hpp" +#include "logging/logger.hpp" +#include "mathutil.hpp" +#include "strings/strings.hpp" +#include "stringutil.hpp" +#include "tasks/fileoptions.hpp" + +#include + +namespace +{ + enum + { + COPY, + DELETE, + RENAME, + CREATE_DIR, + PROPERTIES, + CLOSE + }; + + // These make things easier to read and type. + using TaskConfirm = ConfirmState; + using ProgressConfirm = ConfirmState; +} + +// Defined at bottom. +static std::string get_size_string(int64_t totalSize); + +FileOptionState::FileOptionState(FileModeState *spawningState) + : m_spawningState(spawningState) + , m_dataStruct(std::make_shared()) +{ + FileOptionState::initialize_static_members(); + FileOptionState::set_menu_side(); + FileOptionState::initialize_data_struct(); +} + +void FileOptionState::update() +{ + const bool hasFocus = BaseState::has_focus(); + + FileOptionState::update_x_coord(); + if (!m_inPlace) { return; } + + if (m_updateSource) + { + FileOptionState::update_filemode_source(); + m_updateSource = false; + } + else if (m_updateDest) + { + FileOptionState::update_filemode_dest(); + m_updateDest = false; + } + + sm_copyMenu->update(hasFocus); + const int selected = sm_copyMenu->get_selected(); + const bool aPressed = input::button_pressed(HidNpadButton_A); + const bool bPressed = input::button_pressed(HidNpadButton_B); + + if (aPressed) + { + switch (selected) + { + case COPY: FileOptionState::copy_target(); break; + case DELETE: FileOptionState::delete_target(); break; + case RENAME: FileOptionState::rename_target(); break; + case CREATE_DIR: FileOptionState::create_directory(); break; + case PROPERTIES: FileOptionState::get_show_target_properties(); break; + case CLOSE: FileOptionState::close(); break; + } + } + else if (bPressed) { FileOptionState::close(); } + else if (FileOptionState::is_closed()) { FileOptionState::deactivate_state(); } +} + +void FileOptionState::render() +{ + const bool hasFocus = BaseState::has_focus(); + + sm_dialog->render(sdl::Texture::Null, hasFocus); + sm_copyMenu->render(sdl::Texture::Null, hasFocus); + + // I just didn't like this disappearing. + m_spawningState->render_control_guide(); +} + +void FileOptionState::update_source() { m_updateSource = true; } + +void FileOptionState::update_destination() { m_updateDest = true; } + +void FileOptionState::initialize_static_members() +{ + if (sm_copyMenu && sm_dialog) { return; } + + sm_copyMenu = ui::Menu::create(0, 236, 234, 20, 720); // High target height is a workaround. + sm_dialog = ui::DialogBox::create(520, 218, 256, 256); + + // This never changes, so... + for (int i = 0; const char *menuOption = strings::get_by_name(strings::names::FILEOPTION_MENU, i); i++) + { + sm_copyMenu->add_option(menuOption); + } +} + +void FileOptionState::set_menu_side() +{ + const bool target = m_spawningState->m_target; + m_x = target ? 1280 : -240; + + m_targetX = target ? 840 : 200; + sm_dialog->set_x(m_x); + sm_copyMenu->set_x(m_x + 9); +} + +void FileOptionState::initialize_data_struct() { m_dataStruct->spawningState = this; } + +void FileOptionState::update_filemode_source() +{ + const fslib::Path &sourcePath = m_spawningState->get_source_path(); + fslib::Directory &sourceDir = m_spawningState->get_source_directory(); + ui::Menu &sourceMenu = m_spawningState->get_source_menu(); + + m_spawningState->initialize_directory_menu(sourcePath, sourceDir, sourceMenu); +} + +void FileOptionState::update_filemode_dest() +{ + const fslib::Path &destPath = m_spawningState->get_destination_path(); + fslib::Directory &destDir = m_spawningState->get_destination_directory(); + ui::Menu &destMenu = m_spawningState->get_destination_menu(); + + m_spawningState->initialize_directory_menu(destPath, destDir, destMenu); +} + +void FileOptionState::update_x_coord() +{ + if (m_x == m_targetX) { return; } + + // We're going to borrow the scaling from the FileMode + const int add = (m_targetX - m_x) / m_spawningState->m_scaling; + m_x += add; + + const int distance = math::Util::absolute_distance(m_x, m_targetX); + if (distance <= 4) + { + m_x = m_targetX; + m_inPlace = true; + } + sm_dialog->set_x(m_x); + sm_copyMenu->set_x(m_x + 9); +} + +void FileOptionState::copy_target() +{ + const int64_t journalSize = m_spawningState->m_journalSize; + + const fslib::Path &sourcePath = m_spawningState->get_source_path(); + const fslib::Directory &sourceDir = m_spawningState->get_source_directory(); + const ui::Menu &sourceMenu = m_spawningState->get_source_menu(); + + const fslib::Path &destPath = m_spawningState->get_destination_path(); + const fslib::Directory &destDir = m_spawningState->get_destination_directory(); + const ui::Menu &destMenu = m_spawningState->get_destination_menu(); + + const int sourceSelected = sourceMenu.get_selected(); + const int destSelected = destMenu.get_selected(); + + const int sourceIndex = sourceSelected - 2; + const int destIndex = destSelected - 2; + + fslib::Path fullSource{sourcePath}; + if (sourceSelected > 1) { fullSource /= sourceDir[sourceIndex]; } + + fslib::Path fullDest{destPath}; + if (destSelected == 0 && sourceSelected > 1) { fullDest /= sourceDir[sourceIndex]; } + if (destSelected > 1) + { + fullDest /= destDir[destIndex]; + if (sourceSelected > 1) { fullDest /= sourceDir[sourceIndex]; } + } + + // Reminder: JK, you move these. That's why the string is blank if they're declared past this point. + const std::string sourceString = fullSource.string(); + const std::string destString = fullDest.string(); + m_dataStruct->sourcePath = std::move(fullSource); + m_dataStruct->destPath = std::move(fullDest); + m_dataStruct->journalSize = journalSize; + + const char *copyFormat = strings::get_by_name(strings::names::FILEOPTION_CONFS, 0); + const std::string query = stringutil::get_formatted_string(copyFormat, sourceString.c_str(), destString.c_str()); + + ProgressConfirm::create_push_fade(query, false, tasks::fileoptions::copy_source_to_destination, m_dataStruct); +} + +void FileOptionState::delete_target() +{ + const fslib::Path &targetPath = m_spawningState->get_source_path(); + const fslib::Directory &targetDir = m_spawningState->get_source_directory(); + const ui::Menu &targetMenu = m_spawningState->get_source_menu(); + + fslib::Path fullTarget{targetPath}; + const int selected = targetMenu.get_selected(); + if (selected == 0) { return; } // I have no way to handle this right now. + else if (selected > 1) + { + const int dirIndex = selected - 2; + fullTarget /= targetDir[dirIndex]; + } + + const char *deleteFormat = strings::get_by_name(strings::names::FILEOPTION_CONFS, 1); + const std::string query = stringutil::get_formatted_string(deleteFormat, fullTarget.string().c_str()); + + m_dataStruct->sourcePath = std::move(fullTarget); + m_dataStruct->journalSize = m_spawningState->m_journalSize; + + TaskConfirm::create_push_fade(query, true, tasks::fileoptions::delete_target, m_dataStruct); +} + +void FileOptionState::rename_target() +{ + const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; + const fslib::Path &targetPath = m_spawningState->get_source_path(); + fslib::Directory &targetDir = m_spawningState->get_source_directory(); + ui::Menu &targetMenu = m_spawningState->get_source_menu(); + const int selected = targetMenu.get_selected(); + if (selected < 2) { return; } + + char nameBuffer[FS_MAX_PATH] = {0}; + const int dirIndex = selected - 2; + const char *filename = targetDir[dirIndex].get_filename(); + const char *keyboardFormat = strings::get_by_name(strings::names::KEYBOARD, 9); + const std::string keyboardHeader = stringutil::get_formatted_string(keyboardFormat, filename); + const bool validInput = keyboard::get_input(SwkbdType_QWERTY, filename, keyboardHeader, nameBuffer, FS_MAX_PATH); + if (!validInput) { return; } + + const fslib::Path oldPath{targetPath / filename}; + const fslib::Path newPath{targetPath / nameBuffer}; + + const std::string oldString = oldPath.string(); + const std::string newString = newPath.string(); + + // If this is false and there's a journaling size set, we need to commit on renaming for it to stick. + const bool isSource = !m_spawningState->m_target; + const int64_t journalSize = m_spawningState->m_journalSize; + const bool commitNeeded = isSource && journalSize > 0; + + const bool isDir = fslib::directory_exists(oldPath); + const bool dirError = isDir && error::fslib(fslib::rename_directory(oldPath, newPath)); + const bool fileError = !isDir && error::fslib(fslib::rename_file(oldPath, newPath)); + const bool commitError = commitNeeded && error::fslib(fslib::commit_data_to_file_system(oldPath.get_device_name())); + if (dirError && fileError && commitError) + { + const char *popFormat = strings::get_by_name(strings::names::FILEMODE_POPS, 5); + const std::string pop = stringutil::get_formatted_string(popFormat, filename); + ui::PopMessageManager::push_message(popTicks, pop); + } + else + { + const char *popFormat = strings::get_by_name(strings::names::FILEMODE_POPS, 4); + const std::string pop = stringutil::get_formatted_string(popFormat, filename, nameBuffer); + ui::PopMessageManager::push_message(popTicks, pop); + } + + m_spawningState->initialize_directory_menu(targetPath, targetDir, targetMenu); +} + +void FileOptionState::create_directory() +{ + const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; + const fslib::Path &targetPath = m_spawningState->get_source_path(); + fslib::Directory &targetDir = m_spawningState->get_source_directory(); + ui::Menu &targetMenu = m_spawningState->get_source_menu(); + const int64_t journalSize = m_spawningState->m_journalSize; + + char nameBuffer[FS_MAX_PATH] = {0}; + const char *keyboardHeader = strings::get_by_name(strings::names::KEYBOARD, 6); + const bool validInput = keyboard::get_input(SwkbdType_QWERTY, {}, keyboardHeader, nameBuffer, FS_MAX_PATH); + if (!validInput) { return; } + + const fslib::Path fullTarget{targetPath / nameBuffer}; + const bool commitRequired = journalSize > 0; + const bool createError = error::fslib(fslib::create_directory(fullTarget)); + const bool commitError = !createError && error::fslib(fslib::commit_data_to_file_system(fullTarget.get_device_name())); + if (createError || (commitRequired && commitError)) + { + const char *popFormat = strings::get_by_name(strings::names::FILEMODE_POPS, 7); + const std::string pop = stringutil::get_formatted_string(popFormat, nameBuffer); + ui::PopMessageManager::push_message(popTicks, pop); + } + else + { + const char *popFormat = strings::get_by_name(strings::names::FILEMODE_POPS, 6); + const std::string pop = stringutil::get_formatted_string(popFormat, nameBuffer); + ui::PopMessageManager::push_message(popTicks, pop); + } + + m_spawningState->initialize_directory_menu(targetPath, targetDir, targetMenu); +} + +void FileOptionState::get_show_target_properties() +{ + const fslib::Path &sourcePath = m_spawningState->get_source_path(); + const fslib::Directory &sourceDir = m_spawningState->get_source_directory(); + const ui::Menu &sourceMenu = m_spawningState->get_source_menu(); + + fslib::Path targetPath{sourcePath}; + const int selected = sourceMenu.get_selected(); + if (selected > 1) + { + const int dirIndex = selected - 2; + targetPath /= sourceDir[dirIndex]; + } + + const bool isDir = fslib::directory_exists(targetPath); + if (isDir) { FileOptionState::get_show_directory_properties(targetPath); } + else { FileOptionState::get_show_file_properties(targetPath); } +} + +void FileOptionState::get_show_directory_properties(const fslib::Path &path) +{ + int64_t subDirCount{}; + int64_t fileCount{}; + int64_t totalSize{}; + const bool getInfo = fs::get_directory_information(path, subDirCount, fileCount, totalSize); + if (!getInfo) { return; } + + const char *messageFormat = strings::get_by_name(strings::names::FILEOPTION_MESSAGES, 0); + const std::string pathString = path.string(); // This is needed as backup incase of root directories. + const std::string sizeString = get_size_string(totalSize); + const std::string message = + stringutil::get_formatted_string(messageFormat, pathString.c_str(), subDirCount, fileCount, sizeString.c_str()); + + MessageState::create_and_push(message); +} + +void FileOptionState::get_show_file_properties(const fslib::Path &path) +{ + + static constexpr size_t BUFFER_SIZE = 0x40; + + FsTimeStampRaw timestamp{}; + const int64_t fileSize = fslib::get_file_size(path); + error::fslib(fslib::get_file_timestamp(path, timestamp)); // Recorded, but not required. This doesn't work int saves. + if (fileSize == -1) { return; } + + // I don't like this, but it's the easiest way to pull this off. + const std::time_t created = static_cast(timestamp.created); + const std::time_t modified = static_cast(timestamp.modified); + const std::time_t accessed = static_cast(timestamp.accessed); + + const std::tm createdTm = *std::localtime(&created); + const std::tm modifiedTm = *std::localtime(&modified); + const std::tm accessedTm = *std::localtime(&accessed); + + char createdBuffer[BUFFER_SIZE] = {0}; + char lastModified[BUFFER_SIZE] = {0}; + char lastAccessed[BUFFER_SIZE] = {0}; + + std::strftime(createdBuffer, BUFFER_SIZE, "%c", &createdTm); + std::strftime(lastModified, BUFFER_SIZE, "%c", &modifiedTm); + std::strftime(lastAccessed, BUFFER_SIZE, "%c", &accessedTm); + + const char *messageFormat = strings::get_by_name(strings::names::FILEOPTION_MESSAGES, 1); + const std::string pathString = path.string(); + const std::string sizeString = get_size_string(fileSize); + const std::string message = stringutil::get_formatted_string(messageFormat, + pathString.c_str(), + sizeString.c_str(), + createdBuffer, + lastModified, + lastAccessed); + + MessageState::create_and_push(message); +} + +void FileOptionState::close() +{ + const bool target = m_spawningState->m_target; + + m_close = true; + m_targetX = target ? 1280 : -240; +} + +bool FileOptionState::is_closed() { return m_close && m_x == m_targetX; } + +void FileOptionState::deactivate_state() +{ + sm_copyMenu->set_selected(0); + BaseState::deactivate(); +} + +static std::string get_size_string(int64_t totalSize) +{ + static constexpr int64_t THRESHOLD_BYTES = 0x400; + static constexpr int64_t THRESHOLD_KB = 0x100000; + static constexpr int64_t THRESHOLD_MB = 0x40000000; + + std::string sizeString{}; + if (totalSize > THRESHOLD_MB) + { + const double gigabytes = static_cast(totalSize) / static_cast(THRESHOLD_MB); + sizeString = stringutil::get_formatted_string("%.02f GB", gigabytes); + } + else if (totalSize < THRESHOLD_BYTES) { sizeString = stringutil::get_formatted_string("%lli bytes", totalSize); } + else if (totalSize < THRESHOLD_KB) + { + const double kilobytes = static_cast(totalSize) / static_cast(THRESHOLD_BYTES); + sizeString = stringutil::get_formatted_string("%.02f KB", kilobytes); + } + else + { + const double megabytes = static_cast(totalSize) / static_cast(THRESHOLD_KB); + sizeString = stringutil::get_formatted_string("%.02f MB", megabytes); + } + + return sizeString; +} \ No newline at end of file diff --git a/source/appstates/SaveCreateState.cpp b/source/appstates/SaveCreateState.cpp index 15a6c0f..0e0ac26 100644 --- a/source/appstates/SaveCreateState.cpp +++ b/source/appstates/SaveCreateState.cpp @@ -3,9 +3,9 @@ #include "StateManager.hpp" #include "appstates/TaskState.hpp" #include "data/data.hpp" +#include "error.hpp" #include "fs/fs.hpp" #include "input.hpp" -#include "logging/error.hpp" #include "logging/logger.hpp" #include "strings/strings.hpp" #include "stringutil.hpp" diff --git a/source/appstates/SettingsState.cpp b/source/appstates/SettingsState.cpp index cfc6a00..dc1ebec 100644 --- a/source/appstates/SettingsState.cpp +++ b/source/appstates/SettingsState.cpp @@ -5,11 +5,11 @@ #include "appstates/MessageState.hpp" #include "config/config.hpp" #include "data/data.hpp" +#include "error.hpp" #include "fslib.hpp" #include "graphics/colors.hpp" #include "input.hpp" #include "keyboard.hpp" -#include "logging/error.hpp" #include "logging/logger.hpp" #include "strings/strings.hpp" #include "stringutil.hpp" @@ -157,10 +157,10 @@ void SettingsState::change_working_directory() const char *popSuccessFormat = strings::get_by_name(strings::names::SETTINGS_POPS, 1); const char *popFailed = strings::get_by_name(strings::names::SETTINGS_POPS, 2); - const fslib::Path oldPath{config::get_working_directory()}; + const std::string oldPath = config::get_working_directory().string(); std::array pathBuffer = {0}; - const bool input = keyboard::get_input(SwkbdType_Normal, oldPath.full_path(), inputHeader, pathBuffer.data(), FS_MAX_PATH); + const bool input = keyboard::get_input(SwkbdType_Normal, oldPath, inputHeader, pathBuffer.data(), FS_MAX_PATH); if (!input) { return; } const fslib::Path newPath{pathBuffer.data()}; @@ -179,7 +179,8 @@ void SettingsState::change_working_directory() return; } - const std::string popMessage = stringutil::get_formatted_string(popSuccessFormat, newPath.full_path()); + const std::string newPathString = newPath.string(); + const std::string popMessage = stringutil::get_formatted_string(popSuccessFormat, newPathString); ui::PopMessageManager::push_message(popTicks, popMessage); } diff --git a/source/appstates/TitleInfoState.cpp b/source/appstates/TitleInfoState.cpp index 82b1066..7d7bdb0 100644 --- a/source/appstates/TitleInfoState.cpp +++ b/source/appstates/TitleInfoState.cpp @@ -1,9 +1,9 @@ #include "appstates/TitleInfoState.hpp" #include "StateManager.hpp" +#include "error.hpp" #include "graphics/colors.hpp" #include "input.hpp" -#include "logging/error.hpp" #include "sdl.hpp" #include "strings/strings.hpp" #include "stringutil.hpp" diff --git a/source/appstates/TitleOptionState.cpp b/source/appstates/TitleOptionState.cpp index 5bf66a1..1234d3f 100644 --- a/source/appstates/TitleOptionState.cpp +++ b/source/appstates/TitleOptionState.cpp @@ -2,15 +2,16 @@ #include "StateManager.hpp" #include "appstates/ConfirmState.hpp" +#include "appstates/FileModeState.hpp" #include "appstates/MainMenuState.hpp" #include "appstates/TitleInfoState.hpp" #include "config/config.hpp" +#include "error.hpp" #include "fs/fs.hpp" #include "fslib.hpp" #include "graphics/colors.hpp" #include "input.hpp" #include "keyboard.hpp" -#include "logging/error.hpp" #include "logging/logger.hpp" #include "remote/remote.hpp" #include "strings/strings.hpp" @@ -57,25 +58,20 @@ void TitleOptionState::update() const bool hasFocus = BaseState::has_focus(); sm_slidePanel->update(hasFocus); - const bool isOpen = sm_slidePanel->is_open(); - if (!isOpen) { return; } + const bool isOpen = sm_slidePanel->is_open(); const bool aPressed = input::button_pressed(HidNpadButton_A); const bool bPressed = input::button_pressed(HidNpadButton_B); const int selected = sm_titleOptionMenu->get_selected(); - // This is kind of tricky to handle, because the blacklist function uses both. if (m_refreshRequired) { - // Refresh the views. MainMenuState::refresh_view_states(); m_refreshRequired = false; - // Return so nothing else happens. Not sure I like this, but w/e. return; } - if (m_exitRequired) { sm_slidePanel->close(); } - if (aPressed) + if (aPressed && isOpen) { switch (selected) { @@ -91,10 +87,16 @@ void TitleOptionState::update() case EXPORT_SVI: TitleOptionState::export_svi_file(); break; } } - else if (bPressed) { sm_slidePanel->close(); } + else if (bPressed || m_exitRequired) + { + sm_slidePanel->close(); + m_exitRequired = false; + } else if (sm_slidePanel->is_closed()) { TitleOptionState::deactivate_state(); } } +void TitleOptionState::sub_update() { sm_slidePanel->sub_update(); } + void TitleOptionState::render() { const bool hasFocus = BaseState::has_focus(); @@ -131,6 +133,7 @@ void TitleOptionState::initialize_data_struct() void TitleOptionState::create_push_info_state() { + sm_slidePanel->hide(); auto titleInfoState = TitleInfoState::create(m_user, m_titleInfo); StateManager::push_state(titleInfoState); } @@ -194,7 +197,18 @@ void TitleOptionState::change_output_directory() ui::PopMessageManager::push_message(popTicks, popSuccess); } -void TitleOptionState::create_push_file_mode() {} +void TitleOptionState::create_push_file_mode() +{ + const uint64_t applicationID = m_titleInfo->get_application_id(); + const FsSaveDataInfo *saveInfo = m_user->get_save_info_by_id(applicationID); + if (error::is_null(saveInfo)) { return; } + + const bool saveOpened = fslib::open_save_data_with_save_info(fs::DEFAULT_SAVE_MOUNT, *saveInfo); + if (!saveOpened) { return; } + + sm_slidePanel->hide(); + FileModeState::create_and_push(fs::DEFAULT_SAVE_MOUNT, "sdmc", true); +} void TitleOptionState::delete_all_local_backups() { diff --git a/source/appstates/UserOptionState.cpp b/source/appstates/UserOptionState.cpp index 7302230..ac76ef0 100644 --- a/source/appstates/UserOptionState.cpp +++ b/source/appstates/UserOptionState.cpp @@ -8,10 +8,10 @@ #include "appstates/TaskState.hpp" #include "config/config.hpp" #include "data/data.hpp" +#include "error.hpp" #include "fs/fs.hpp" #include "fslib.hpp" #include "input.hpp" -#include "logging/error.hpp" #include "logging/logger.hpp" #include "remote/remote.hpp" #include "strings/strings.hpp" @@ -78,6 +78,8 @@ void UserOptionState::update() else if (sm_menuPanel->is_closed()) { UserOptionState::deactivate_state(); } } +void UserOptionState::sub_update() { sm_menuPanel->sub_update(); } + void UserOptionState::render() { // Render target user's title selection screen. @@ -131,7 +133,11 @@ void UserOptionState::backup_all() else { ProgressConfirm::create_and_push(query, true, tasks::useroptions::backup_all_for_user_local, m_dataStruct); } } -void UserOptionState::create_save_create() { SaveCreateState::create_and_push(m_user, m_titleSelect); } +void UserOptionState::create_save_create() +{ + sm_menuPanel->hide(); + SaveCreateState::create_and_push(m_user, m_titleSelect); +} void UserOptionState::create_all_save_data() { diff --git a/source/config/ConfigContext.cpp b/source/config/ConfigContext.cpp index 9052970..2ba541b 100644 --- a/source/config/ConfigContext.cpp +++ b/source/config/ConfigContext.cpp @@ -3,7 +3,6 @@ #include "JSON.hpp" #include "config/keys.hpp" #include "error.hpp" -#include "logging/error.hpp" #include "logging/logger.hpp" #include "stringutil.hpp" @@ -68,14 +67,14 @@ bool config::ConfigContext::load() void config::ConfigContext::save() { ConfigContext::save_config_file(); } -uint8_t config::ConfigContext::get_by_key(std::string_view key) const +uint8_t config::ConfigContext::get_by_key(std::string_view key) const noexcept { const auto findKey = m_configMap.find(key); if (findKey == m_configMap.end()) { return 0; } return findKey->second; } -void config::ConfigContext::toggle_by_key(std::string_view key) +void config::ConfigContext::toggle_by_key(std::string_view key) noexcept { auto findKey = m_configMap.find(key); if (findKey == m_configMap.end()) { return; } @@ -84,7 +83,7 @@ void config::ConfigContext::toggle_by_key(std::string_view key) findKey->second = value ? 0 : 1; } -void config::ConfigContext::set_by_key(std::string_view key, uint8_t value) +void config::ConfigContext::set_by_key(std::string_view key, uint8_t value) noexcept { auto findKey = m_configMap.find(key); if (findKey == m_configMap.end()) { return; } @@ -92,9 +91,9 @@ void config::ConfigContext::set_by_key(std::string_view key, uint8_t value) findKey->second = value; } -fslib::Path config::ConfigContext::get_working_directory() const { return m_workingDirectory; } +fslib::Path config::ConfigContext::get_working_directory() const noexcept { return m_workingDirectory; } -bool config::ConfigContext::set_working_directory(const fslib::Path &workDir) +bool config::ConfigContext::set_working_directory(const fslib::Path &workDir) noexcept { if (!workDir.is_valid()) { return false; } @@ -102,9 +101,9 @@ bool config::ConfigContext::set_working_directory(const fslib::Path &workDir) return true; } -double config::ConfigContext::get_animation_scaling() const { return m_animationScaling; } +double config::ConfigContext::get_animation_scaling() const noexcept { return m_animationScaling; } -void config::ConfigContext::set_animation_scaling(double scaling) { m_animationScaling = scaling; } +void config::ConfigContext::set_animation_scaling(double scaling) noexcept { m_animationScaling = scaling; } void config::ConfigContext::add_favorite(uint64_t applicationID) { @@ -114,7 +113,7 @@ void config::ConfigContext::add_favorite(uint64_t applicationID) ConfigContext::save_config_file(); } -void config::ConfigContext::remove_favorite(uint64_t applicationID) +void config::ConfigContext::remove_favorite(uint64_t applicationID) noexcept { const auto findFav = ConfigContext::find_application_id(m_favorites, applicationID); if (findFav == m_favorites.end()) { return; } @@ -122,7 +121,7 @@ void config::ConfigContext::remove_favorite(uint64_t applicationID) ConfigContext::save_config_file(); } -bool config::ConfigContext::is_favorite(uint64_t applicationID) const +bool config::ConfigContext::is_favorite(uint64_t applicationID) const noexcept { return ConfigContext::find_application_id(m_favorites, applicationID) != m_favorites.end(); } @@ -134,7 +133,7 @@ void config::ConfigContext::add_to_blacklist(uint64_t applicationID) m_blacklist.push_back(applicationID); } -void config::ConfigContext::remove_from_blacklist(uint64_t applicationID) +void config::ConfigContext::remove_from_blacklist(uint64_t applicationID) noexcept { const auto findTitle = ConfigContext::find_application_id(m_blacklist, applicationID); if (findTitle == m_blacklist.end()) { return; } @@ -146,14 +145,14 @@ void config::ConfigContext::get_blacklist(std::vector &listOut) listOut.assign(m_blacklist.begin(), m_blacklist.end()); } -bool config::ConfigContext::is_blacklisted(uint64_t applicationID) const +bool config::ConfigContext::is_blacklisted(uint64_t applicationID) const noexcept { return ConfigContext::find_application_id(m_blacklist, applicationID) != m_blacklist.end(); } -bool config::ConfigContext::blacklist_empty() const { return m_blacklist.empty(); } +bool config::ConfigContext::blacklist_empty() const noexcept { return m_blacklist.empty(); } -bool config::ConfigContext::has_custom_path(uint64_t applicationID) const +bool config::ConfigContext::has_custom_path(uint64_t applicationID) const noexcept { return m_paths.find(applicationID) != m_paths.end(); } @@ -181,7 +180,7 @@ bool config::ConfigContext::load_config_file() const bool exists = fslib::file_exists(configPath); if (!exists) { return false; } - json::Object configJSON = json::new_object(json_object_from_file, configPath.full_path()); + json::Object configJSON = json::new_object(json_object_from_file, PATH_CONFIG_FILE.data()); if (!configJSON) { return false; } json_object_iterator configIter = json::iter_begin(configJSON); @@ -212,7 +211,8 @@ void config::ConfigContext::save_config_file() json::Object configJSON = json::new_object(json_object_new_object); if (!configJSON) { return; } - json_object *workDir = json_object_new_string(m_workingDirectory.full_path()); + const std::string workDirString = m_workingDirectory.string(); + json_object *workDir = json_object_new_string(workDirString.c_str()); json::add_object(configJSON, config::keys::WORKING_DIRECTORY, workDir); for (const auto &[key, value] : m_configMap) diff --git a/source/config/config.cpp b/source/config/config.cpp index 1711019..3118586 100644 --- a/source/config/config.cpp +++ b/source/config/config.cpp @@ -20,15 +20,15 @@ void config::reset_to_default() { s_context.reset(); } void config::save() { s_context.save(); } -uint8_t config::get_by_key(std::string_view key) { return s_context.get_by_key(key); } +uint8_t config::get_by_key(std::string_view key) noexcept { return s_context.get_by_key(key); } -void config::toggle_by_key(std::string_view key) { s_context.toggle_by_key(key); } +void config::toggle_by_key(std::string_view key) noexcept { s_context.toggle_by_key(key); } -void config::set_by_key(std::string_view key, uint8_t value) { s_context.set_by_key(key, value); } +void config::set_by_key(std::string_view key, uint8_t value) noexcept { s_context.set_by_key(key, value); } fslib::Path config::get_working_directory() { return s_context.get_working_directory(); } -bool config::set_working_directory(const fslib::Path &path) +bool config::set_working_directory(const fslib::Path &path) noexcept { const bool pathSet = s_context.set_working_directory(path); if (!pathSet) { return false; } @@ -37,9 +37,9 @@ bool config::set_working_directory(const fslib::Path &path) return true; } -double config::get_animation_scaling() { return s_context.get_animation_scaling(); } +double config::get_animation_scaling() noexcept { return s_context.get_animation_scaling(); } -void config::set_animation_scaling(double newScale) { s_context.set_animation_scaling(newScale); } +void config::set_animation_scaling(double newScale) noexcept { s_context.set_animation_scaling(newScale); } void config::add_remove_favorite(uint64_t applicationID) { @@ -49,7 +49,7 @@ void config::add_remove_favorite(uint64_t applicationID) s_context.save(); } -bool config::is_favorite(uint64_t applicationID) { return s_context.is_favorite(applicationID); } +bool config::is_favorite(uint64_t applicationID) noexcept { return s_context.is_favorite(applicationID); } void config::add_remove_blacklist(uint64_t applicationID) { @@ -61,16 +61,16 @@ void config::add_remove_blacklist(uint64_t applicationID) void config::get_blacklisted_titles(std::vector &listOut) { s_context.get_blacklist(listOut); } -bool config::is_blacklisted(uint64_t applicationID) { return s_context.is_blacklisted(applicationID); } +bool config::is_blacklisted(uint64_t applicationID) noexcept { return s_context.is_blacklisted(applicationID); } -bool config::blacklist_is_empty() { return s_context.blacklist_empty(); } +bool config::blacklist_is_empty() noexcept { return s_context.blacklist_empty(); } void config::add_custom_path(uint64_t applicationID, std::string_view customPath) { s_context.add_custom_path(applicationID, customPath); } -bool config::has_custom_path(uint64_t applicationID) { return s_context.has_custom_path(applicationID); } +bool config::has_custom_path(uint64_t applicationID) noexcept { return s_context.has_custom_path(applicationID); } void config::get_custom_path(uint64_t applicationID, char *pathOut, size_t pathOutSize) { diff --git a/source/curl/curl.cpp b/source/curl/curl.cpp index 25c1bb7..9424002 100644 --- a/source/curl/curl.cpp +++ b/source/curl/curl.cpp @@ -1,6 +1,6 @@ #include "curl/curl.hpp" -#include "logging/error.hpp" +#include "error.hpp" #include "logging/logger.hpp" #include "stringutil.hpp" diff --git a/source/data/DataContext.cpp b/source/data/DataContext.cpp index 33a454a..9662376 100644 --- a/source/data/DataContext.cpp +++ b/source/data/DataContext.cpp @@ -1,8 +1,8 @@ #include "data/DataContext.hpp" #include "config/config.hpp" +#include "error.hpp" #include "fs/fs.hpp" -#include "logging/error.hpp" #include "logging/logger.hpp" #include "strings/strings.hpp" #include "stringutil.hpp" @@ -128,11 +128,11 @@ bool data::DataContext::title_is_loaded(uint64_t applicationID) void data::DataContext::load_title(uint64_t applicationID) { std::scoped_lock titleGuard{m_titleMutex, m_iconQueueMutex}; - m_titleInfo.emplace(applicationID, applicationID); + m_titleInfo.try_emplace(applicationID, applicationID); m_iconQueue.push_back(&m_titleInfo.at(applicationID)); } -data::TitleInfo *data::DataContext::get_title_by_id(uint64_t applicationID) +data::TitleInfo *data::DataContext::get_title_by_id(uint64_t applicationID) noexcept { std::lock_guard titleGuard{m_titleMutex}; auto findTitle = m_titleInfo.find(applicationID); @@ -171,7 +171,8 @@ void data::DataContext::import_svi_files(sys::Task *task) task->set_status(statusLoadingSvi); - for (const fslib::DirectoryEntry &entry : sviDir.list()) + auto controlData = std::make_unique(); + for (const fslib::DirectoryEntry &entry : sviDir) { const fslib::Path target{sviPath / entry}; fslib::File sviFile{target, FsOpenMode_Read}; @@ -180,7 +181,6 @@ void data::DataContext::import_svi_files(sys::Task *task) uint32_t magic{}; uint64_t applicationID{}; - auto controlData = std::make_unique(); const bool magicRead = sviFile.read(&magic, SIZE_UINT32) == SIZE_UINT32; const bool idRead = sviFile.read(&applicationID, SIZE_UINT64) == SIZE_UINT64; const bool exists = DataContext::title_is_loaded(applicationID); @@ -190,8 +190,7 @@ void data::DataContext::import_svi_files(sys::Task *task) if (!dataRead) { continue; } std::scoped_lock multiGuard{m_iconQueueMutex, m_titleMutex}; - data::TitleInfo newTitle{applicationID, controlData}; - m_titleInfo.emplace(applicationID, std::move(newTitle)); + m_titleInfo.try_emplace(applicationID, applicationID, *controlData); m_iconQueue.push_back(&m_titleInfo.at(applicationID)); } } @@ -214,8 +213,8 @@ bool data::DataContext::read_cache(sys::Task *task) const char *statusLoadingCache = strings::get_by_name(strings::names::DATA_LOADING_STATUS, 4); task->set_status(statusLoadingCache); + auto controlData = std::make_unique(); do { - auto controlData = std::make_unique(); const bool dataRead = cacheZip.read(controlData.get(), SIZE_CTRL_DATA) == SIZE_CTRL_DATA; if (!dataRead) { continue; } @@ -228,8 +227,7 @@ bool data::DataContext::read_cache(sys::Task *task) std::scoped_lock multiGuard{m_iconQueueMutex, m_titleMutex}; - data::TitleInfo newTitle{applicationID, controlData}; - m_titleInfo.emplace(applicationID, std::move(newTitle)); + m_titleInfo.try_emplace(applicationID, applicationID, *controlData); m_iconQueue.push_back(&m_titleInfo.at(applicationID)); } while (cacheZip.next_file()); m_cacheIsValid = true; diff --git a/source/data/TitleInfo.cpp b/source/data/TitleInfo.cpp index fcbd7c8..27ec299 100644 --- a/source/data/TitleInfo.cpp +++ b/source/data/TitleInfo.cpp @@ -1,38 +1,34 @@ #include "data/TitleInfo.hpp" #include "config/config.hpp" +#include "error.hpp" #include "graphics/colors.hpp" #include "graphics/gfxutil.hpp" -#include "logging/error.hpp" #include "logging/logger.hpp" #include "stringutil.hpp" #include -data::TitleInfo::TitleInfo(uint64_t applicationID) +data::TitleInfo::TitleInfo(uint64_t applicationID) noexcept : m_applicationID(applicationID) - , m_data(std::make_unique()) { static constexpr size_t SIZE_CTRL_DATA = sizeof(NsApplicationControlData); uint64_t controlSize{}; - NacpLanguageEntry *entry{}; - NsApplicationControlData *data = m_data.get(); // This will filter from even trying to fetch control data for system titles. const bool isSystem = applicationID & 0x8000000000000000; const bool getError = !isSystem && error::libnx(nsGetApplicationControlData(NsApplicationControlSource_Storage, m_applicationID, - data, + &m_data, SIZE_CTRL_DATA, &controlSize)); - const bool entryError = !getError && error::libnx(nacpGetLanguageEntry(&data->nacp, &entry)); + const bool entryError = !getError && error::libnx(nacpGetLanguageEntry(&m_data.nacp, &m_entry)); if (isSystem || getError) { const std::string appIDHex = stringutil::get_formatted_string("%04X", m_applicationID & 0xFFFF); - char *name = data->nacp.lang[SetLanguage_ENUS].name; // I'm hoping this is enough? + char *name = m_data.nacp.lang[SetLanguage_ENUS].name; // I'm hoping this is enough? - std::memset(data, 0x00, SIZE_CTRL_DATA); std::snprintf(name, TitleInfo::SIZE_PATH_SAFE, "%016lX", m_applicationID); TitleInfo::get_create_path_safe_title(); } @@ -44,67 +40,35 @@ data::TitleInfo::TitleInfo(uint64_t applicationID) } // To do: Make this safer... -data::TitleInfo::TitleInfo(uint64_t applicationID, std::unique_ptr &controlData) +data::TitleInfo::TitleInfo(uint64_t applicationID, NsApplicationControlData &controlData) noexcept : m_applicationID(applicationID) - , m_data(std::move(controlData)) { m_hasData = true; + m_data = controlData; - NacpLanguageEntry *entry{}; - const bool entryError = error::libnx(nacpGetLanguageEntry(&m_data->nacp, &entry)); - if (entryError) { std::snprintf(entry->name, TitleInfo::SIZE_PATH_SAFE, "%016lX", m_applicationID); } + const bool entryError = error::libnx(nacpGetLanguageEntry(&m_data.nacp, &m_entry)); + if (entryError) { std::snprintf(m_entry->name, TitleInfo::SIZE_PATH_SAFE, "%016lX", m_applicationID); } TitleInfo::get_create_path_safe_title(); } -data::TitleInfo::TitleInfo(data::TitleInfo &&titleInfo) { *this = std::move(titleInfo); } +uint64_t data::TitleInfo::get_application_id() const noexcept { return m_applicationID; } -data::TitleInfo &data::TitleInfo::operator=(data::TitleInfo &&titleInfo) +const NsApplicationControlData *data::TitleInfo::get_control_data() const noexcept { return &m_data; } + +bool data::TitleInfo::has_control_data() const noexcept { return m_hasData; } + +const char *data::TitleInfo::get_title() const noexcept { return m_entry->name; } + +const char *data::TitleInfo::get_path_safe_title() const noexcept { return m_pathSafeTitle; } + +const char *data::TitleInfo::get_publisher() const noexcept { return m_entry->author; } + +uint64_t data::TitleInfo::get_save_data_owner_id() const noexcept { return m_data.nacp.save_data_owner_id; } + +int64_t data::TitleInfo::get_save_data_size(uint8_t saveType) const noexcept { - m_applicationID = titleInfo.m_applicationID; - m_data = std::move(titleInfo.m_data); - m_hasData = titleInfo.m_hasData; - std::memcpy(m_pathSafeTitle, titleInfo.m_pathSafeTitle, TitleInfo::SIZE_PATH_SAFE); - m_icon = titleInfo.m_icon; - - titleInfo.m_applicationID = 0; - titleInfo.m_data = nullptr; - titleInfo.m_hasData = false; - std::memset(titleInfo.m_pathSafeTitle, 0x00, TitleInfo::SIZE_PATH_SAFE); - titleInfo.m_icon = nullptr; - - return *this; -} - -uint64_t data::TitleInfo::get_application_id() const { return m_applicationID; } - -NsApplicationControlData *data::TitleInfo::get_control_data() { return m_data.get(); } - -bool data::TitleInfo::has_control_data() const { return m_hasData; } - -const char *data::TitleInfo::get_title() -{ - NacpLanguageEntry *entry{}; - const bool entryError = error::libnx(nacpGetLanguageEntry(&m_data->nacp, &entry)); - if (entryError) { return nullptr; } - return entry->name; -} - -const char *data::TitleInfo::get_path_safe_title() const { return m_pathSafeTitle; } - -const char *data::TitleInfo::get_publisher() -{ - NacpLanguageEntry *entry{}; - const bool entryError = error::libnx(nacpGetLanguageEntry(&m_data->nacp, &entry)); - if (entryError) { return nullptr; } - return entry->author; -} - -uint64_t data::TitleInfo::get_save_data_owner_id() const { return m_data->nacp.save_data_owner_id; } - -int64_t data::TitleInfo::get_save_data_size(uint8_t saveType) const -{ - const NacpStruct &nacp = m_data->nacp; + const NacpStruct &nacp = m_data.nacp; switch (saveType) { case FsSaveDataType_Account: return nacp.user_account_save_data_size; @@ -116,9 +80,9 @@ int64_t data::TitleInfo::get_save_data_size(uint8_t saveType) const return 0; } -int64_t data::TitleInfo::get_save_data_size_max(uint8_t saveType) const +int64_t data::TitleInfo::get_save_data_size_max(uint8_t saveType) const noexcept { - const NacpStruct &nacp = m_data->nacp; + const NacpStruct &nacp = m_data.nacp; switch (saveType) { case FsSaveDataType_Account: return std::max(nacp.user_account_save_data_size, nacp.user_account_save_data_size_max); @@ -130,9 +94,9 @@ int64_t data::TitleInfo::get_save_data_size_max(uint8_t saveType) const return 0; } -int64_t data::TitleInfo::get_journal_size(uint8_t saveType) const +int64_t data::TitleInfo::get_journal_size(uint8_t saveType) const noexcept { - const NacpStruct &nacp = m_data->nacp; + const NacpStruct &nacp = m_data.nacp; switch (saveType) { case FsSaveDataType_Account: return nacp.user_account_save_data_journal_size; @@ -144,9 +108,9 @@ int64_t data::TitleInfo::get_journal_size(uint8_t saveType) const return 0; } -int64_t data::TitleInfo::get_journal_size_max(uint8_t saveType) const +int64_t data::TitleInfo::get_journal_size_max(uint8_t saveType) const noexcept { - const NacpStruct &nacp = m_data->nacp; + const NacpStruct &nacp = m_data.nacp; switch (saveType) { case FsSaveDataType_Account: @@ -160,9 +124,9 @@ int64_t data::TitleInfo::get_journal_size_max(uint8_t saveType) const return 0; } -bool data::TitleInfo::has_save_data_type(uint8_t saveType) const +bool data::TitleInfo::has_save_data_type(uint8_t saveType) const noexcept { - const NacpStruct &nacp = m_data->nacp; + const NacpStruct &nacp = m_data.nacp; switch (saveType) { case FsSaveDataType_Account: return nacp.user_account_save_data_size > 0 || nacp.user_account_save_data_size_max > 0; @@ -173,9 +137,9 @@ bool data::TitleInfo::has_save_data_type(uint8_t saveType) const return false; } -sdl::SharedTexture data::TitleInfo::get_icon() const { return m_icon; } +sdl::SharedTexture data::TitleInfo::get_icon() const noexcept { return m_icon; } -void data::TitleInfo::set_path_safe_title(const char *newPathSafe) +void data::TitleInfo::set_path_safe_title(const char *newPathSafe) noexcept { const size_t length = std::char_traits::length(newPathSafe); if (length >= TitleInfo::SIZE_PATH_SAFE) { return; } @@ -184,10 +148,9 @@ void data::TitleInfo::set_path_safe_title(const char *newPathSafe) std::memcpy(m_pathSafeTitle, newPathSafe, length); } -void data::TitleInfo::get_create_path_safe_title() +void data::TitleInfo::get_create_path_safe_title() noexcept { const uint64_t applicationID = TitleInfo::get_application_id(); - NacpLanguageEntry *entry{}; const bool hasCustom = config::has_custom_path(applicationID); if (hasCustom) @@ -197,13 +160,8 @@ void data::TitleInfo::get_create_path_safe_title() } const bool useTitleId = config::get_by_key(config::keys::USE_TITLE_IDS); - const bool entryError = !useTitleId && error::libnx(nacpGetLanguageEntry(&m_data->nacp, &entry)); - const bool sanitized = - !useTitleId && !entryError && stringutil::sanitize_string_for_path(entry->name, m_pathSafeTitle, SIZE_PATH_SAFE); - if (useTitleId || entryError || !sanitized) - { - std::snprintf(m_pathSafeTitle, TitleInfo::SIZE_PATH_SAFE, "%016lX", m_applicationID); - } + const bool sanitized = !useTitleId && stringutil::sanitize_string_for_path(m_entry->name, m_pathSafeTitle, SIZE_PATH_SAFE); + if (useTitleId || !sanitized) { std::snprintf(m_pathSafeTitle, TitleInfo::SIZE_PATH_SAFE, "%016lX", m_applicationID); } } void data::TitleInfo::load_icon() @@ -214,7 +172,7 @@ void data::TitleInfo::load_icon() if (m_hasData) { const std::string textureName = stringutil::get_formatted_string("%016llX", m_applicationID); - m_icon = sdl::TextureManager::load(textureName, m_data->icon, SIZE_ICON); + m_icon = sdl::TextureManager::load(textureName, m_data.icon, SIZE_ICON); } else { diff --git a/source/data/User.cpp b/source/data/User.cpp index c6b1ccd..7b96745 100644 --- a/source/data/User.cpp +++ b/source/data/User.cpp @@ -2,10 +2,10 @@ #include "config/config.hpp" #include "data/data.hpp" +#include "error.hpp" #include "fs/fs.hpp" #include "graphics/colors.hpp" #include "graphics/gfxutil.hpp" -#include "logging/error.hpp" #include "logging/logger.hpp" #include "sdl.hpp" #include "stringutil.hpp" @@ -33,7 +33,7 @@ namespace // Function used to sort user data. Definition at the bottom. static bool sort_user_data(const data::UserDataEntry &entryA, const data::UserDataEntry &entryB); -data::User::User(AccountUid accountID, FsSaveDataType saveType) +data::User::User(AccountUid accountID, FsSaveDataType saveType) noexcept : m_accountID{accountID} , m_saveType{saveType} { @@ -47,7 +47,10 @@ data::User::User(AccountUid accountID, FsSaveDataType saveType) accountProfileClose(&profile); } -data::User::User(AccountUid accountID, std::string_view nickname, std::string_view pathSafeNickname, FsSaveDataType saveType) +data::User::User(AccountUid accountID, + std::string_view nickname, + std::string_view pathSafeNickname, + FsSaveDataType saveType) noexcept : m_accountID{accountID} , m_saveType{saveType} { @@ -55,9 +58,9 @@ data::User::User(AccountUid accountID, std::string_view nickname, std::string_vi std::memcpy(m_pathSafeNickname, pathSafeNickname.data(), pathSafeNickname.length()); } -data::User::User(data::User &&user) { *this = std::move(user); } +data::User::User(data::User &&user) noexcept { *this = std::move(user); } -data::User &data::User::operator=(data::User &&user) +data::User &data::User::operator=(data::User &&user) noexcept { static constexpr size_t SIZE_NICKNAME = 0x20; @@ -88,50 +91,50 @@ void data::User::add_data(const FsSaveDataInfo *saveInfo, const PdmPlayStatistic m_userData.push_back(std::move(vectorPair)); } -void data::User::clear_data_entries() { m_userData.clear(); } +void data::User::clear_data_entries() noexcept { m_userData.clear(); } void data::User::erase_data(int index) { m_userData.erase(m_userData.begin() + index); } -void data::User::sort_data() { std::sort(m_userData.begin(), m_userData.end(), sort_user_data); } +void data::User::sort_data() noexcept { std::sort(m_userData.begin(), m_userData.end(), sort_user_data); } -AccountUid data::User::get_account_id() const { return m_accountID; } +AccountUid data::User::get_account_id() const noexcept { return m_accountID; } -FsSaveDataType data::User::get_account_save_type() const { return m_saveType; } +FsSaveDataType data::User::get_account_save_type() const noexcept { return m_saveType; } -const char *data::User::get_nickname() const { return m_nickname; } +const char *data::User::get_nickname() const noexcept { return m_nickname; } -const char *data::User::get_path_safe_nickname() const { return m_pathSafeNickname; } +const char *data::User::get_path_safe_nickname() const noexcept { return m_pathSafeNickname; } -size_t data::User::get_total_data_entries() const { return m_userData.size(); } +size_t data::User::get_total_data_entries() const noexcept { return m_userData.size(); } -uint64_t data::User::get_application_id_at(int index) const +uint64_t data::User::get_application_id_at(int index) const noexcept { if (!User::index_check(index)) { return 0; } return m_userData.at(index).first; } -FsSaveDataInfo *data::User::get_save_info_at(int index) +FsSaveDataInfo *data::User::get_save_info_at(int index) noexcept { if (!User::index_check(index)) { return nullptr; } return &m_userData.at(index).second.first; } -PdmPlayStatistics *data::User::get_play_stats_at(int index) +PdmPlayStatistics *data::User::get_play_stats_at(int index) noexcept { if (!User::index_check(index)) { return nullptr; } return &m_userData.at(index).second.second; } -FsSaveDataInfo *data::User::get_save_info_by_id(uint64_t applicationID) +FsSaveDataInfo *data::User::get_save_info_by_id(uint64_t applicationID) noexcept { auto target = User::find_title_by_id(applicationID); if (target == m_userData.end()) { return nullptr; } return &target->second.first; } -data::UserSaveInfoList &data::User::get_user_save_info_list() { return m_userData; } +data::UserSaveInfoList &data::User::get_user_save_info_list() noexcept { return m_userData; } -PdmPlayStatistics *data::User::get_play_stats_by_id(uint64_t applicationID) +PdmPlayStatistics *data::User::get_play_stats_by_id(uint64_t applicationID) noexcept { auto target = User::find_title_by_id(applicationID); if (target == m_userData.end()) { return nullptr; } @@ -164,15 +167,12 @@ void data::User::load_user_data() while (infoReader.read()) { - const int64_t readCount = infoReader.get_read_count(); - - for (int64_t i = 0; i < readCount; i++) + for (const FsSaveDataInfo &saveInfo : infoReader) { - const FsSaveDataInfo &saveInfo = infoReader[i]; - const uint64_t saveInfoAppID = saveInfo.application_id; - const uint64_t saveInfoSysID = saveInfo.system_save_data_id; - const uint64_t applicationID = saveInfoAppID != 0 ? saveInfoAppID : saveInfoSysID; - const uint8_t saveDataType = saveInfo.save_data_type; + const uint64_t saveInfoAppID = saveInfo.application_id; + const uint64_t saveInfoSysID = saveInfo.system_save_data_id; + const uint64_t applicationID = saveInfoAppID != 0 ? saveInfoAppID : saveInfoSysID; + const uint8_t saveDataType = saveInfo.save_data_type; const bool isSystemSave = saveDataType == FsSaveDataType_System || saveDataType == FsSaveDataType_SystemBcat; const bool isBlacklisted = config::is_blacklisted(applicationID); diff --git a/source/data/data.cpp b/source/data/data.cpp index e3819ec..06966f2 100644 --- a/source/data/data.cpp +++ b/source/data/data.cpp @@ -2,7 +2,8 @@ #include "appstates/DataLoadingState.hpp" #include "data/DataContext.hpp" -#include "logging/error.hpp" +#include "error.hpp" +#include "logging/logger.hpp" #include "strings/strings.hpp" #include @@ -23,11 +24,14 @@ void data::launch_initialization(bool clearCache, std::function onDestru void data::get_users(data::UserList &userList) { s_context.get_users(userList); } -data::TitleInfo *data::get_title_info_by_id(uint64_t applicationID) { return s_context.get_title_by_id(applicationID); } +data::TitleInfo *data::get_title_info_by_id(uint64_t applicationID) noexcept +{ + return s_context.get_title_by_id(applicationID); +} void data::load_title_to_map(uint64_t applicationID) { s_context.load_title(applicationID); } -bool data::title_exists_in_map(uint64_t applicationID) { return s_context.title_is_loaded(applicationID); } +bool data::title_exists_in_map(uint64_t applicationID) noexcept { return s_context.title_is_loaded(applicationID); } void data::get_title_info_list(data::TitleInfoList &listOut) { s_context.get_title_info_list(listOut); } diff --git a/source/logging/error.cpp b/source/error.cpp similarity index 89% rename from source/logging/error.cpp rename to source/error.cpp index bc61c8d..290d860 100644 --- a/source/logging/error.cpp +++ b/source/error.cpp @@ -1,4 +1,4 @@ -#include "logging/error.hpp" +#include "error.hpp" #include "fslib.hpp" #include "logging/logger.hpp" @@ -7,9 +7,9 @@ #include /// @brief Prepares and makes sure the strings match the format I actually want! -static void prep_locations(std::string_view &file, std::string_view &function, const std::source_location &location); +static void prep_locations(std::string_view &file, std::string_view &function, const std::source_location &location) noexcept; -bool error::libnx(Result code, const std::source_location &location) +bool error::libnx(Result code, const std::source_location &location) noexcept { if (code == 0) { return false; } @@ -20,7 +20,7 @@ bool error::libnx(Result code, const std::source_location &location) return true; } -bool error::fslib(bool result, const std::source_location &location) +bool error::fslib(bool result, const std::source_location &location) noexcept { if (result) { return false; } @@ -37,7 +37,7 @@ bool error::fslib(bool result, const std::source_location &location) return true; } -bool error::is_null(const void *pointer, const std::source_location &location) +bool error::is_null(const void *pointer, const std::source_location &location) noexcept { if (pointer) { return false; } @@ -49,7 +49,7 @@ bool error::is_null(const void *pointer, const std::source_location &location) return true; } -static void prep_locations(std::string_view &file, std::string_view &function, const std::source_location &location) +static void prep_locations(std::string_view &file, std::string_view &function, const std::source_location &location) noexcept { file = location.file_name(); function = location.function_name(); diff --git a/source/fs/MiniUnzip.cpp b/source/fs/MiniUnzip.cpp index 0b2df73..e1e90fe 100644 --- a/source/fs/MiniUnzip.cpp +++ b/source/fs/MiniUnzip.cpp @@ -1,6 +1,6 @@ #include "fs/MiniUnzip.hpp" -#include "logging/error.hpp" +#include "error.hpp" #include "logging/logger.hpp" fs::MiniUnzip::MiniUnzip(const fslib::Path &path) { MiniUnzip::open(path); } @@ -12,7 +12,9 @@ bool fs::MiniUnzip::is_open() const { return m_isOpen; } bool fs::MiniUnzip::open(const fslib::Path &path) { MiniUnzip::close(); - m_unz = unzOpen64(path.full_path()); + + const std::string pathString = path.string(); + m_unz = unzOpen64(pathString.c_str()); if (error::is_null(m_unz) || !MiniUnzip::reset()) { return false; } m_isOpen = true; return true; diff --git a/source/fs/MiniZip.cpp b/source/fs/MiniZip.cpp index fa15251..10d4899 100644 --- a/source/fs/MiniZip.cpp +++ b/source/fs/MiniZip.cpp @@ -1,14 +1,19 @@ #include "fs/MiniZip.hpp" #include "config/config.hpp" -#include "logging/error.hpp" +#include "error.hpp" +#include "logging/logger.hpp" #include // Definition at bottom. static zip_fileinfo create_zip_file_info(); -fs::MiniZip::MiniZip(const fslib::Path &path) { MiniZip::open(path); } +fs::MiniZip::MiniZip(const fslib::Path &path) + : m_level(config::get_by_key(config::keys::ZIP_COMPRESSION_LEVEL)) +{ + MiniZip::open(path); +} fs::MiniZip::~MiniZip() { MiniZip::close(); } @@ -17,7 +22,9 @@ bool fs::MiniZip::is_open() const { return m_isOpen; } bool fs::MiniZip::open(const fslib::Path &path) { MiniZip::close(); - m_zip = zipOpen64(path.full_path(), APPEND_STATUS_CREATE); + + const std::string pathString = path.string(); + m_zip = zipOpen64(pathString.c_str(), APPEND_STATUS_CREATE); if (error::is_null(m_zip)) { return false; } m_isOpen = true; return true; @@ -32,19 +39,21 @@ void fs::MiniZip::close() bool fs::MiniZip::open_new_file(std::string_view filename, bool trimPath, size_t trimPlaces) { - const uint8_t zipLevel = config::get_by_key(config::keys::ZIP_COMPRESSION_LEVEL); - const size_t pathBegin = filename.find_first_of('/'); if (pathBegin != filename.npos) { filename = filename.substr(pathBegin + 1); } const zip_fileinfo fileInfo = create_zip_file_info(); - return zipOpenNewFileInZip64(m_zip, filename.data(), &fileInfo, nullptr, 0, nullptr, 0, nullptr, Z_DEFLATED, zipLevel, 0) == + return zipOpenNewFileInZip64(m_zip, filename.data(), &fileInfo, nullptr, 0, nullptr, 0, nullptr, Z_DEFLATED, m_level, 0) == ZIP_OK; } bool fs::MiniZip::close_current_file() { return zipCloseFileInZip(m_zip) == ZIP_OK; } -bool fs::MiniZip::write(const void *buffer, size_t dataSize) { return zipWriteInFileInZip(m_zip, buffer, dataSize) == ZIP_OK; } +bool fs::MiniZip::write(const void *buffer, size_t dataSize) +{ + if (!m_isOpen) { return false; } + return zipWriteInFileInZip(m_zip, buffer, dataSize) == ZIP_OK; +} static zip_fileinfo create_zip_file_info() { diff --git a/source/fs/PathFilter.cpp b/source/fs/PathFilter.cpp index 844b246..5d3042a 100644 --- a/source/fs/PathFilter.cpp +++ b/source/fs/PathFilter.cpp @@ -4,7 +4,8 @@ fs::PathFilter::PathFilter(const fslib::Path &filePath) { - json::Object filterJSON = json::new_object(json_object_from_file, filePath.full_path()); + const std::string pathString = filePath.string(); + json::Object filterJSON = json::new_object(json_object_from_file, pathString.c_str()); if (!filterJSON) { return; } json_object *filter = json::get_object(filterJSON, "filters"); @@ -21,9 +22,9 @@ fs::PathFilter::PathFilter(const fslib::Path &filePath) } } -bool fs::PathFilter::has_paths() const { return !m_paths.empty(); } +bool fs::PathFilter::has_paths() const noexcept { return !m_paths.empty(); } -bool fs::PathFilter::is_filtered(const fslib::Path &path) +bool fs::PathFilter::is_filtered(const fslib::Path &path) const noexcept { - return std::find(m_paths.begin(), m_paths.end(), path.full_path()) != m_paths.end(); + return std::find(m_paths.begin(), m_paths.end(), path) != m_paths.end(); } diff --git a/source/fs/SaveMetaData.cpp b/source/fs/SaveMetaData.cpp index 2f13482..fdd99aa 100644 --- a/source/fs/SaveMetaData.cpp +++ b/source/fs/SaveMetaData.cpp @@ -1,31 +1,20 @@ #include "fs/SaveMetaData.hpp" +#include "error.hpp" #include "fs/directory_functions.hpp" #include "fs/save_data_functions.hpp" #include "fs/save_mount.hpp" #include "fslib.hpp" -#include "logging/error.hpp" namespace { constexpr size_t SIZE_EXTRA_DATA = sizeof(FsSaveDataExtraData); } -bool fs::read_save_data_extra_info(const FsSaveDataInfo *saveInfo, FsSaveDataExtraData &dataOut) -{ - const FsSaveDataSpaceId spaceID = static_cast(saveInfo->save_data_space_id); - const uint64_t saveDataID = saveInfo->save_data_id; - - const bool readError = - error::libnx(fsReadSaveDataFileSystemExtraDataBySaveDataSpaceId(&dataOut, SIZE_EXTRA_DATA, spaceID, saveDataID)); - if (readError) { return false; } - return true; -} - -bool fs::fill_save_meta_data(const FsSaveDataInfo *saveInfo, fs::SaveMetaData &meta) +bool fs::fill_save_meta_data(const FsSaveDataInfo *saveInfo, fs::SaveMetaData &meta) noexcept { FsSaveDataExtraData extraData{}; - const bool extraRead = fs::read_save_data_extra_info(saveInfo, extraData); + const bool extraRead = fs::read_save_extra_data(saveInfo, extraData); if (!extraRead) { return false; } meta = {.magic = fs::SAVE_META_MAGIC, @@ -46,10 +35,10 @@ bool fs::fill_save_meta_data(const FsSaveDataInfo *saveInfo, fs::SaveMetaData &m return true; } -bool fs::process_save_meta_data(const FsSaveDataInfo *saveInfo, const SaveMetaData &meta) +bool fs::process_save_meta_data(const FsSaveDataInfo *saveInfo, const SaveMetaData &meta) noexcept { FsSaveDataExtraData extraData{}; - const bool extraRead = fs::read_save_data_extra_info(saveInfo, extraData); + const bool extraRead = fs::read_save_extra_data(saveInfo, extraData); if (!extraRead) { return false; } const bool needsExtend = extraData.data_size < meta.saveDataSize; diff --git a/source/fs/ScopedSaveMount.cpp b/source/fs/ScopedSaveMount.cpp index 702fe32..cc11b46 100644 --- a/source/fs/ScopedSaveMount.cpp +++ b/source/fs/ScopedSaveMount.cpp @@ -1,7 +1,7 @@ #include "fs/ScopedSaveMount.hpp" +#include "error.hpp" #include "fslib.hpp" -#include "logging/error.hpp" fs::ScopedSaveMount::ScopedSaveMount(std::string_view mount, const FsSaveDataInfo *saveInfo, bool log) : m_mountPoint(mount) @@ -11,9 +11,9 @@ fs::ScopedSaveMount::ScopedSaveMount(std::string_view mount, const FsSaveDataInf else { m_isOpen = fslib::open_save_data_with_save_info(m_mountPoint, *saveInfo); } } -fs::ScopedSaveMount::ScopedSaveMount(ScopedSaveMount &&scopedSaveMount) { *this = std::move(scopedSaveMount); } +fs::ScopedSaveMount::ScopedSaveMount(ScopedSaveMount &&scopedSaveMount) noexcept { *this = std::move(scopedSaveMount); } -fs::ScopedSaveMount &fs::ScopedSaveMount::operator=(ScopedSaveMount &&scopedSaveMount) +fs::ScopedSaveMount &fs::ScopedSaveMount::operator=(ScopedSaveMount &&scopedSaveMount) noexcept { m_mountPoint = std::move(scopedSaveMount.m_mountPoint); m_isOpen = scopedSaveMount.m_isOpen; @@ -27,4 +27,4 @@ fs::ScopedSaveMount::~ScopedSaveMount() else { fslib::close_file_system(m_mountPoint); } } -bool fs::ScopedSaveMount::is_open() const { return m_isOpen; } +bool fs::ScopedSaveMount::is_open() const noexcept { return m_isOpen; } diff --git a/source/fs/directory_functions.cpp b/source/fs/directory_functions.cpp index 0caa294..3d85092 100644 --- a/source/fs/directory_functions.cpp +++ b/source/fs/directory_functions.cpp @@ -1,24 +1,34 @@ #include "fs/directory_functions.hpp" +#include "error.hpp" #include "fs/SaveMetaData.hpp" +#include "logging/logger.hpp" -uint64_t fs::get_directory_total_size(const fslib::Path &targetPath) +bool fs::get_directory_information(const fslib::Path &directoryPath, + int64_t &subDirCount, + int64_t &fileCount, + int64_t &totalSize) { - fslib::Directory targetDir{targetPath}; - if (!targetDir.is_open()) { return 0; } + fslib::Directory dir{directoryPath}; + if (error::fslib(dir.is_open())) { return false; } - uint64_t directorySize = 0; - for (const fslib::DirectoryEntry &entry : targetDir.list()) + for (const fslib::DirectoryEntry &entry : dir) { if (entry.is_directory()) { - const fslib::Path newTarget{targetPath / entry}; - directorySize += fs::get_directory_total_size(newTarget); + const fslib::Path newPath{directoryPath / entry}; + const bool getInfo = fs::get_directory_information(newPath, subDirCount, fileCount, totalSize); + if (!getInfo) { return false; } + ++subDirCount; + } + else + { + totalSize += entry.get_size(); + ++fileCount; } - else { directorySize += entry.get_size(); } } - return directorySize; + return true; } bool fs::directory_has_contents(const fslib::Path &directoryPath) @@ -26,7 +36,7 @@ bool fs::directory_has_contents(const fslib::Path &directoryPath) fslib::Directory testDir{directoryPath}; if (!testDir.is_open()) { return false; } - for (const fslib::DirectoryEntry &entry : testDir.list()) + for (const fslib::DirectoryEntry &entry : testDir) { if (entry.get_filename() != fs::NAME_SAVE_META) { return true; } } diff --git a/source/fs/io.cpp b/source/fs/io.cpp index 6c0fcc9..40a77c5 100644 --- a/source/fs/io.cpp +++ b/source/fs/io.cpp @@ -1,8 +1,8 @@ #include "fs/io.hpp" +#include "error.hpp" #include "fs/SaveMetaData.hpp" #include "fslib.hpp" -#include "logging/error.hpp" #include "strings/strings.hpp" #include "stringutil.hpp" #include "sys/sys.hpp" @@ -70,7 +70,8 @@ void fs::copy_file(const fslib::Path &source, const fslib::Path &destination, sy const int64_t sourceSize = sourceFile.get_size(); if (task) { - const std::string status = stringutil::get_formatted_string(statusTemplate, source.full_path()); + const std::string sourceString = source.string(); + const std::string status = stringutil::get_formatted_string(statusTemplate, sourceString.c_str()); task->set_status(status); task->reset(static_cast(sourceSize)); } @@ -111,7 +112,6 @@ void fs::copy_file(const fslib::Path &source, const fslib::Path &destination, sy void fs::copy_file_commit(const fslib::Path &source, const fslib::Path &destination, - std::string_view device, int64_t journalSize, sys::ProgressTask *task) { @@ -126,7 +126,8 @@ void fs::copy_file_commit(const fslib::Path &source, const int64_t sourceSize = sourceFile.get_size(); if (task) { - const std::string status = stringutil::get_formatted_string(copyingStatus, source.full_path()); + const std::string sourceString = source.string(); + const std::string status = stringutil::get_formatted_string(copyingStatus, sourceString.c_str()); task->set_status(status); task->reset(static_cast(sourceSize)); } @@ -163,7 +164,7 @@ void fs::copy_file_commit(const fslib::Path &source, if (needsCommit) { destFile.close(); - const bool commitError = error::fslib(fslib::commit_data_to_file_system(device)); + const bool commitError = error::fslib(fslib::commit_data_to_file_system(destination.get_device_name())); // To do: Handle this better. Threads current have no way of communicating errors. if (commitError) { ui::PopMessageManager::push_message(popTicks, popCommitFailed); } @@ -180,7 +181,7 @@ void fs::copy_file_commit(const fslib::Path &source, readThread.join(); destFile.close(); - const bool commitError = error::fslib(fslib::commit_data_to_file_system(device)); + const bool commitError = error::fslib(fslib::commit_data_to_file_system(destination.get_device_name())); if (commitError) { ui::PopMessageManager::push_message(popTicks, popCommitFailed); } } @@ -189,7 +190,7 @@ void fs::copy_directory(const fslib::Path &source, const fslib::Path &destinatio fslib::Directory sourceDir{source}; if (error::fslib(sourceDir.is_open())) { return; } - for (const fslib::DirectoryEntry &entry : sourceDir.list()) + for (const fslib::DirectoryEntry &entry : sourceDir) { const char *filename = entry.get_filename(); if (filename == fs::NAME_SAVE_META) { continue; } @@ -210,14 +211,13 @@ void fs::copy_directory(const fslib::Path &source, const fslib::Path &destinatio void fs::copy_directory_commit(const fslib::Path &source, const fslib::Path &destination, - std::string_view device, int64_t journalSize, sys::ProgressTask *task) { fslib::Directory sourceDir{source}; if (error::fslib(sourceDir.is_open())) { return; } - for (const fslib::DirectoryEntry &entry : sourceDir.list()) + for (const fslib::DirectoryEntry &entry : sourceDir) { const char *filename = entry.get_filename(); if (filename == fs::NAME_SAVE_META) { continue; } @@ -230,8 +230,8 @@ void fs::copy_directory_commit(const fslib::Path &source, const bool createError = !destExists && error::fslib(fslib::create_directory(fullDest)); if (!destExists && createError) { continue; } - fs::copy_directory_commit(fullSource, fullDest, device, journalSize, task); + fs::copy_directory_commit(fullSource, fullDest, journalSize, task); } - else { fs::copy_file_commit(fullSource, fullDest, device, journalSize, task); } + else { fs::copy_file_commit(fullSource, fullDest, journalSize, task); } } } diff --git a/source/fs/save_data_functions.cpp b/source/fs/save_data_functions.cpp index 801eab1..3953e55 100644 --- a/source/fs/save_data_functions.cpp +++ b/source/fs/save_data_functions.cpp @@ -1,9 +1,9 @@ #include "fs/save_data_functions.hpp" -#include "logging/error.hpp" +#include "error.hpp" #include "logging/logger.hpp" -bool fs::create_save_data_for(data::User *targetUser, data::TitleInfo *titleInfo) +bool fs::create_save_data_for(data::User *targetUser, data::TitleInfo *titleInfo) noexcept { static constexpr FsSaveDataMetaInfo saveMeta = {.size = 0x40060, .type = FsSaveDataMetaType_Thumbnail}; @@ -29,11 +29,10 @@ bool fs::create_save_data_for(data::User *targetUser, data::TitleInfo *titleInfo .save_data_space_id = FsSaveDataSpaceId_User}; // I want this recorded. - const bool createError = error::libnx(fsCreateSaveDataFileSystem(&saveAttributes, &saveCreation, &saveMeta)); - return createError == false; + return error::libnx(fsCreateSaveDataFileSystem(&saveAttributes, &saveCreation, &saveMeta)) == false; } -bool fs::delete_save_data(const FsSaveDataInfo *saveInfo) +bool fs::delete_save_data(const FsSaveDataInfo *saveInfo) noexcept { const FsSaveDataSpaceId spaceID = static_cast(saveInfo->save_data_space_id); const bool isSystem = fs::is_system_save_data(saveInfo); @@ -47,8 +46,7 @@ bool fs::delete_save_data(const FsSaveDataInfo *saveInfo) .save_data_rank = saveInfo->save_data_rank, .save_data_index = saveInfo->save_data_index}; - const bool deleteError = error::libnx(fsDeleteSaveDataFileSystemBySaveDataAttribute(spaceID, &saveAttributes)); - return deleteError == false; + return error::libnx(fsDeleteSaveDataFileSystemBySaveDataAttribute(spaceID, &saveAttributes)) == false; } bool fs::extend_save_data(const FsSaveDataInfo *saveInfo, int64_t size, int64_t journalSize) @@ -56,11 +54,22 @@ bool fs::extend_save_data(const FsSaveDataInfo *saveInfo, int64_t size, int64_t const FsSaveDataSpaceId spaceID = static_cast(saveInfo->save_data_space_id); const uint64_t saveID = saveInfo->save_data_id; - const bool extendError = error::libnx(fsExtendSaveDataFileSystem(spaceID, saveID, size, journalSize)); - return extendError == false; + return error::libnx(fsExtendSaveDataFileSystem(spaceID, saveID, size, journalSize)) == false; } -bool fs::is_system_save_data(const FsSaveDataInfo *saveInfo) +bool fs::is_system_save_data(const FsSaveDataInfo *saveInfo) noexcept { return saveInfo->save_data_type == FsSaveDataType_System || saveInfo->save_data_type == FsSaveDataType_SystemBcat; } + +bool fs::read_save_extra_data(const FsSaveDataInfo *saveInfo, FsSaveDataExtraData &extraOut) noexcept +{ + static constexpr size_t EXTRA_SIZE = sizeof(FsSaveDataExtraData); + + const FsSaveDataSpaceId spaceID = static_cast(saveInfo->save_data_space_id); + + const bool readError = error::libnx( + fsReadSaveDataFileSystemExtraDataBySaveDataSpaceId(&extraOut, EXTRA_SIZE, spaceID, saveInfo->save_data_id)); + + return !readError; +} \ No newline at end of file diff --git a/source/fs/zip.cpp b/source/fs/zip.cpp index 5090572..980778a 100644 --- a/source/fs/zip.cpp +++ b/source/fs/zip.cpp @@ -1,8 +1,8 @@ #include "fs/zip.hpp" #include "config/config.hpp" +#include "error.hpp" #include "fs/SaveMetaData.hpp" -#include "logging/error.hpp" #include "logging/logger.hpp" #include "strings/strings.hpp" #include "stringutil.hpp" @@ -19,7 +19,7 @@ namespace { /// @brief Buffer size used for writing files to ZIP. - constexpr size_t SIZE_ZIP_BUFFER = 0x100000; + constexpr size_t SIZE_ZIP_BUFFER = 0x10000; /// @brief Buffer size used for decompressing files from ZIP. constexpr size_t SIZE_UNZIP_BUFFER = 0x600000; @@ -100,14 +100,15 @@ void fs::copy_directory_to_zip(const fslib::Path &source, fs::MiniZip &dest, sys fslib::Directory sourceDir{source}; if (error::fslib(sourceDir.is_open())) { return; } - for (const fslib::DirectoryEntry &entry : sourceDir.list()) + for (const fslib::DirectoryEntry &entry : sourceDir) { const fslib::Path fullSource{source / entry}; if (entry.is_directory()) { fs::copy_directory_to_zip(fullSource, dest, task); } else { fslib::File sourceFile{fullSource, FsOpenMode_Read}; - const bool newZipFile = dest.open_new_file(fullSource.full_path()); + const std::string sourceString = fullSource.string(); + const bool newZipFile = dest.open_new_file(sourceString); if (error::fslib(sourceFile.is_open()) || !newZipFile) { continue; } const int64_t fileSize = sourceFile.get_size(); @@ -117,7 +118,7 @@ void fs::copy_directory_to_zip(const fslib::Path &source, fs::MiniZip &dest, sys if (task) { - const std::string status = stringutil::get_formatted_string(ioStatus, fullSource.full_path()); + const std::string status = stringutil::get_formatted_string(ioStatus, sourceString.c_str()); task->set_status(status); task->reset(static_cast(fileSize)); } @@ -158,17 +159,13 @@ void fs::copy_directory_to_zip(const fslib::Path &source, fs::MiniZip &dest, sys } } -void fs::copy_zip_to_directory(fs::MiniUnzip &unzip, - const fslib::Path &dest, - int64_t journalSize, - std::string_view commitDevice, - sys::ProgressTask *task) +void fs::copy_zip_to_directory(fs::MiniUnzip &unzip, const fslib::Path &dest, int64_t journalSize, sys::ProgressTask *task) { if (!unzip.reset()) { return; } const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; const char *popCommitFailed = strings::get_by_name(strings::names::IO_POPS, 0); const char *statusTemplate = strings::get_by_name(strings::names::IO_STATUSES, 2); - const bool needCommits = journalSize > 0 && !commitDevice.empty(); + const bool needCommits = journalSize > 0; do { if (unzip.get_filename() == fs::NAME_SAVE_META) { continue; } @@ -178,9 +175,10 @@ void fs::copy_zip_to_directory(fs::MiniUnzip &unzip, if (lastDir == fullDest.NOT_FOUND) { continue; } const fslib::Path dirPath{fullDest.sub_path(lastDir)}; - const bool exists = dirPath.is_valid() && fslib::directory_exists(dirPath); - const bool createError = dirPath.is_valid() && !exists && error::fslib(fslib::create_directories_recursively(dirPath)); - if (dirPath.is_valid() && !exists && createError) { continue; } + const bool isValid = dirPath.is_valid(); + const bool exists = isValid && fslib::directory_exists(dirPath); + const bool createError = isValid && !exists && error::fslib(fslib::create_directories_recursively(dirPath)); + if (isValid && !exists && createError) { continue; } const int64_t fileSize = unzip.get_uncompressed_size(); fslib::File destFile{fullDest, FsOpenMode_Create | FsOpenMode_Write, fileSize}; @@ -203,8 +201,8 @@ void fs::copy_zip_to_directory(fs::MiniUnzip &unzip, bool &bufferReady = sharedData->bufferReady; std::unique_ptr &sharedBuffer = sharedData->sharedBuffer; - std::thread readThread(unzipReadThreadFunction, std::ref(unzip), sharedData); int64_t journalCount{}; + std::thread readThread(unzipReadThreadFunction, std::ref(unzip), sharedData); for (int64_t i = 0; i < fileSize;) { ssize_t localRead{}; @@ -223,7 +221,7 @@ void fs::copy_zip_to_directory(fs::MiniUnzip &unzip, if (commitNeeded) { destFile.close(); - const bool commitError = error::fslib(fslib::commit_data_to_file_system(commitDevice)); + const bool commitError = error::fslib(fslib::commit_data_to_file_system(dest.get_device_name())); if (commitError) { ui::PopMessageManager::push_message(popTicks, popCommitFailed); } // To do: How to recover? destFile.open(fullDest, FsOpenMode_Write); @@ -240,7 +238,7 @@ void fs::copy_zip_to_directory(fs::MiniUnzip &unzip, readThread.join(); destFile.close(); - const bool commitError = needCommits && error::fslib(fslib::commit_data_to_file_system(commitDevice)); + const bool commitError = needCommits && error::fslib(fslib::commit_data_to_file_system(dest.get_device_name())); if (commitError) { ui::PopMessageManager::push_message(popTicks, popCommitFailed); } } while (unzip.next_file()); } diff --git a/source/input.cpp b/source/input.cpp index 1f005f7..8b6e6df 100644 --- a/source/input.cpp +++ b/source/input.cpp @@ -11,16 +11,19 @@ void input::initialize() padInitializeDefault(&s_gamepad); } -void input::update() { padUpdate(&s_gamepad); } +void input::update() noexcept { padUpdate(&s_gamepad); } -bool input::button_pressed(HidNpadButton button) +bool input::button_pressed(HidNpadButton button) noexcept { return (s_gamepad.buttons_cur & button) && !(s_gamepad.buttons_old & button); } -bool input::button_held(HidNpadButton button) { return (s_gamepad.buttons_cur & button) && (s_gamepad.buttons_old & button); } +bool input::button_held(HidNpadButton button) noexcept +{ + return (s_gamepad.buttons_cur & button) && (s_gamepad.buttons_old & button); +} -bool input::button_released(HidNpadButton button) +bool input::button_released(HidNpadButton button) noexcept { return (s_gamepad.buttons_old & button) && !(s_gamepad.buttons_cur & button); } diff --git a/source/keyboard.cpp b/source/keyboard.cpp index 16ab221..4442fb5 100644 --- a/source/keyboard.cpp +++ b/source/keyboard.cpp @@ -1,6 +1,6 @@ #include "keyboard.hpp" -#include "logging/error.hpp" +#include "error.hpp" #include diff --git a/source/logging/logger.cpp b/source/logging/logger.cpp index 0b4c1af..b1adda1 100644 --- a/source/logging/logger.cpp +++ b/source/logging/logger.cpp @@ -27,7 +27,7 @@ void logger::initialize() if (!exists) { fslib::create_file(logPath); } } -void logger::log(const char *format, ...) +void logger::log(const char *format, ...) noexcept { static std::mutex logLock{}; diff --git a/source/remote/Form.cpp b/source/remote/Form.cpp index f4aa8ea..e05875f 100644 --- a/source/remote/Form.cpp +++ b/source/remote/Form.cpp @@ -2,7 +2,7 @@ remote::Form::Form(const remote::Form &form) { m_form = form.m_form; } -remote::Form::Form(remote::Form &&form) { m_form = std::move(form.m_form); } +remote::Form::Form(remote::Form &&form) noexcept { m_form = std::move(form.m_form); } remote::Form &remote::Form::operator=(const remote::Form &form) { @@ -10,7 +10,7 @@ remote::Form &remote::Form::operator=(const remote::Form &form) return *this; } -remote::Form &remote::Form::operator=(remote::Form &&form) +remote::Form &remote::Form::operator=(remote::Form &&form) noexcept { m_form = std::move(form.m_form); return *this; @@ -23,6 +23,6 @@ remote::Form &remote::Form::append_parameter(std::string_view param, std::string return *this; } -const char *remote::Form::get() const { return m_form.c_str(); } +const char *remote::Form::get() const noexcept { return m_form.c_str(); } -size_t remote::Form::length() const { return m_form.length(); } +size_t remote::Form::length() const noexcept { return m_form.length(); } diff --git a/source/remote/GoogleDrive.cpp b/source/remote/GoogleDrive.cpp index b46a80d..55bf06f 100644 --- a/source/remote/GoogleDrive.cpp +++ b/source/remote/GoogleDrive.cpp @@ -550,7 +550,7 @@ bool remote::GoogleDrive::get_root_id() return true; } -bool remote::GoogleDrive::token_is_valid() const +bool remote::GoogleDrive::token_is_valid() const noexcept { // I'm giving this a grace period just to be safe. return std::time(NULL) < m_tokenExpires - 10; @@ -681,7 +681,7 @@ bool remote::GoogleDrive::process_listing(json::Object &json) return true; } -bool remote::GoogleDrive::error_occurred(json::Object &json, bool log) +bool remote::GoogleDrive::error_occurred(json::Object &json, bool log) noexcept { json_object *error = json::get_object(json, "error"); if (!error) { return false; } diff --git a/source/remote/Item.cpp b/source/remote/Item.cpp index 045c412..b657299 100644 --- a/source/remote/Item.cpp +++ b/source/remote/Item.cpp @@ -9,15 +9,15 @@ remote::Item::Item(std::string_view name, std::string_view id, std::string_view , m_size{size} , m_isDirectory{directory} {}; -std::string_view remote::Item::get_name() const { return m_name; } +std::string_view remote::Item::get_name() const noexcept { return m_name; } -std::string_view remote::Item::get_id() const { return m_id; } +std::string_view remote::Item::get_id() const noexcept { return m_id; } -std::string_view remote::Item::get_parent_id() const { return m_parent; } +std::string_view remote::Item::get_parent_id() const noexcept { return m_parent; } -size_t remote::Item::get_size() const { return m_size; } +size_t remote::Item::get_size() const noexcept { return m_size; } -bool remote::Item::is_directory() const { return m_isDirectory; } +bool remote::Item::is_directory() const noexcept { return m_isDirectory; } void remote::Item::set_name(std::string_view name) { m_name = name; } @@ -25,6 +25,6 @@ void remote::Item::set_id(std::string_view id) { m_id = id; } void remote::Item::set_parent_id(std::string_view parent) { m_parent = parent; } -void remote::Item::set_size(size_t size) { m_size = size; } +void remote::Item::set_size(size_t size) noexcept { m_size = size; } -void remote::Item::set_is_directory(bool directory) { m_isDirectory = directory; } +void remote::Item::set_is_directory(bool directory) noexcept { m_isDirectory = directory; } diff --git a/source/remote/Storage.cpp b/source/remote/Storage.cpp index 89516d8..d9819e6 100644 --- a/source/remote/Storage.cpp +++ b/source/remote/Storage.cpp @@ -11,9 +11,12 @@ remote::Storage::Storage(std::string_view prefix, bool supportsUtf8) , m_utf8Paths(supportsUtf8) , m_prefix(prefix) {}; -bool remote::Storage::is_initialized() const { return m_isInitialized; } +bool remote::Storage::is_initialized() const noexcept { return m_isInitialized; } -bool remote::Storage::directory_exists(std::string_view name) { return Storage::find_directory_by_name(name) != m_list.end(); } +bool remote::Storage::directory_exists(std::string_view name) const noexcept +{ + return Storage::find_directory_by_name(name) != m_list.end(); +} void remote::Storage::return_to_root() { m_parent = m_root; } @@ -21,7 +24,7 @@ void remote::Storage::set_root_directory(const remote::Item *root) { m_root = ro void remote::Storage::change_directory(const remote::Item *item) { m_parent = item->get_id(); } -remote::Item *remote::Storage::get_directory_by_name(std::string_view name) +remote::Item *remote::Storage::get_directory_by_name(std::string_view name) noexcept { auto findDirectory = Storage::find_directory_by_name(name); if (findDirectory == m_list.end()) { return nullptr; } @@ -53,22 +56,25 @@ void remote::Storage::get_directory_listing_with_parent(const remote::Item *item } } -bool remote::Storage::file_exists(std::string_view name) { return Storage::find_file_by_name(name) != m_list.end(); } +bool remote::Storage::file_exists(std::string_view name) const noexcept +{ + return Storage::find_file_by_name(name) != m_list.end(); +} -remote::Item *remote::Storage::get_file_by_name(std::string_view name) +remote::Item *remote::Storage::get_file_by_name(std::string_view name) noexcept { auto findFile = Storage::find_file_by_name(name); if (findFile == m_list.end()) { return nullptr; } return &(*findFile); } -bool remote::Storage::supports_utf8() const { return m_utf8Paths; } +bool remote::Storage::supports_utf8() const noexcept { return m_utf8Paths; } -std::string_view remote::Storage::get_prefix() const { return m_prefix; } +std::string_view remote::Storage::get_prefix() const noexcept { return m_prefix; } -remote::Storage::List::iterator remote::Storage::find_directory_by_name(std::string_view name) +remote::Storage::List::iterator remote::Storage::find_directory_by_name(std::string_view name) noexcept { - auto is_match = [&](const Item &item) + auto is_match = [&](const Item &item) noexcept { const bool isDir = item.is_directory(); const bool parentMatch = isDir && item.get_parent_id() == m_parent; @@ -80,9 +86,23 @@ remote::Storage::List::iterator remote::Storage::find_directory_by_name(std::str return std::find_if(m_list.begin(), m_list.end(), is_match); } -remote::Storage::List::iterator remote::Storage::find_directory_by_id(std::string_view id) +remote::Storage::List::const_iterator remote::Storage::find_directory_by_name(std::string_view name) const noexcept { - auto is_match = [&](const Item &item) + auto is_match = [&](const Item &item) noexcept + { + const bool isDir = item.is_directory(); + const bool parentMatch = isDir && item.get_parent_id() == m_parent; + const bool nameMatch = parentMatch && item.get_name() == name; + + return isDir && parentMatch && nameMatch; + }; + + return std::find_if(m_list.begin(), m_list.end(), is_match); +} + +remote::Storage::List::iterator remote::Storage::find_directory_by_id(std::string_view id) noexcept +{ + auto is_match = [&](const Item &item) noexcept { const bool isDir = item.is_directory(); const bool idMatch = item.get_id() == id; @@ -92,23 +112,50 @@ remote::Storage::List::iterator remote::Storage::find_directory_by_id(std::strin return std::find_if(m_list.begin(), m_list.end(), is_match); } -remote::Storage::List::iterator remote::Storage::find_file_by_name(std::string_view name) +remote::Storage::List::const_iterator remote::Storage::find_directory_by_id(std::string_view id) const noexcept { - auto is_match = [&](const Item &item) + auto is_match = [&](const Item &item) noexcept { - const bool notDir = !item.is_directory(); - const bool parentMatch = notDir && item.get_parent_id() == m_parent; - const bool nameMatch = parentMatch && item.get_name() == name; + const bool isDir = item.is_directory(); + const bool idMatch = item.get_id() == id; - return notDir && parentMatch && nameMatch; + return isDir && idMatch; }; return std::find_if(m_list.begin(), m_list.end(), is_match); } -remote::Storage::List::iterator remote::Storage::find_file_by_id(std::string_view id) +remote::Storage::List::iterator remote::Storage::find_file_by_name(std::string_view name) noexcept { - auto is_match = [&](const Item &item) + auto is_match = [&](const Item &item) noexcept + { + const bool isFile = !item.is_directory(); + const bool parentMatch = isFile && item.get_parent_id() == m_parent; + const bool nameMatch = parentMatch && item.get_name() == name; + + return isFile && parentMatch && nameMatch; + }; + + return std::find_if(m_list.begin(), m_list.end(), is_match); +} + +remote::Storage::List::const_iterator remote::Storage::find_file_by_name(std::string_view name) const noexcept +{ + auto is_match = [&](const Item &item) noexcept + { + const bool isFile = !item.is_directory(); + const bool parentMatch = !isFile && item.get_parent_id() == m_parent; + const bool nameMatch = parentMatch && item.get_name() == name; + + return isFile && parentMatch && nameMatch; + }; + + return std::find_if(m_list.begin(), m_list.end(), is_match); +} + +remote::Storage::List::iterator remote::Storage::find_file_by_id(std::string_view id) noexcept +{ + auto is_match = [&](const Item &item) noexcept { const bool isFile = !item.is_directory(); const bool isMatch = item.get_id() == id; @@ -119,22 +166,45 @@ remote::Storage::List::iterator remote::Storage::find_file_by_id(std::string_vie return std::find_if(m_list.begin(), m_list.end(), is_match); } -remote::Storage::List::iterator remote::Storage::find_item_by_id(std::string_view id) +remote::Storage::List::const_iterator remote::Storage::find_file_by_id(std::string_view id) const noexcept { - auto is_match = [&](const Item &item) + auto is_match = [&](const remote::Item &item) noexcept { + const bool isFile = !item.is_directory(); const bool isMatch = item.get_id() == id; - return isMatch; + return isFile && isMatch; }; return std::find_if(m_list.begin(), m_list.end(), is_match); } +remote::Storage::List::iterator remote::Storage::find_item_by_id(std::string_view id) noexcept +{ + auto is_match = [&](const Item &item) { return item.get_id() == id; }; + + return std::find_if(m_list.begin(), m_list.end(), is_match); +} + +remote::Storage::List::const_iterator remote::Storage::find_item_by_id(std::string_view id) const noexcept +{ + auto is_match = [&](const remote::Item &item) { return item.get_id() == id; }; + + return std::find_if(m_list.begin(), m_list.end(), is_match); +} + remote::Storage::List::iterator remote::Storage::find_by_parent_id(remote::Storage::List::iterator start, - std::string_view parentID) + std::string_view parentID) noexcept { auto is_match = [&](const Item &item) { return item.get_parent_id() == parentID; }; return std::find_if(start, m_list.end(), is_match); } + +remote::Storage::List::const_iterator remote::Storage::find_by_parent_id(Storage::List::const_iterator start, + std::string_view parentID) const noexcept +{ + auto is_match = [&](const remote::Item &item) { return item.get_parent_id() == parentID; }; + + return std::find_if(start, m_list.end(), is_match); +} diff --git a/source/remote/URL.cpp b/source/remote/URL.cpp index e2322bd..1b7d9cd 100644 --- a/source/remote/URL.cpp +++ b/source/remote/URL.cpp @@ -13,7 +13,7 @@ remote::URL &remote::URL::operator=(const remote::URL &url) return *this; } -remote::URL &remote::URL::operator=(remote::URL &&url) +remote::URL &remote::URL::operator=(remote::URL &&url) noexcept { m_url = std::move(url.m_url); return *this; @@ -47,7 +47,7 @@ remote::URL &remote::URL::append_slash() return *this; } -const char *remote::URL::get() const { return m_url.c_str(); } +const char *remote::URL::get() const noexcept { return m_url.c_str(); } void remote::URL::append_separator() { diff --git a/source/remote/WebDav.cpp b/source/remote/WebDav.cpp index e157f41..0922d0e 100644 --- a/source/remote/WebDav.cpp +++ b/source/remote/WebDav.cpp @@ -2,7 +2,7 @@ #include "JSON.hpp" #include "curl/curl.hpp" -#include "logging/error.hpp" +#include "error.hpp" #include "logging/logger.hpp" #include "remote/remote.hpp" #include "strings/strings.hpp" diff --git a/source/remote/remote.cpp b/source/remote/remote.cpp index 51daac2..58d7a0e 100644 --- a/source/remote/remote.cpp +++ b/source/remote/remote.cpp @@ -2,7 +2,7 @@ #include "StateManager.hpp" #include "appstates/TaskState.hpp" -#include "logging/error.hpp" +#include "error.hpp" #include "logging/logger.hpp" #include "remote/GoogleDrive.hpp" #include "remote/WebDav.hpp" @@ -31,7 +31,7 @@ static void drive_sign_in(sys::Task *task, remote::GoogleDrive *drive); /// @param drive Pointer to the drive instance.. static void drive_set_jksv_root(remote::GoogleDrive *drive); -bool remote::has_internet_connection() +bool remote::has_internet_connection() noexcept { NifmInternetConnectionType type{}; uint32_t strength{}; @@ -86,7 +86,7 @@ void remote::initialize_webdav() } } -remote::Storage *remote::get_remote_storage() +remote::Storage *remote::get_remote_storage() noexcept { if (!s_storage || !s_storage->is_initialized()) { return nullptr; } return s_storage.get(); diff --git a/source/strings/strings.cpp b/source/strings/strings.cpp index 069c690..80aa112 100644 --- a/source/strings/strings.cpp +++ b/source/strings/strings.cpp @@ -2,8 +2,8 @@ #include "JSON.hpp" #include "config/config.hpp" +#include "error.hpp" #include "fslib.hpp" -#include "logging/error.hpp" #include "logging/logger.hpp" #include "stringutil.hpp" @@ -15,6 +15,7 @@ namespace { // This is the actual map where the strings are. std::map, std::string> s_stringMap; + // This map is for matching files to the language value std::unordered_map s_fileMap = {{SetLanguage_JA, "JA.json"}, {SetLanguage_ENUS, "ENUS.json"}, @@ -42,8 +43,8 @@ static void replace_buttons_in_string(std::string &target); bool strings::initialize() { - const fslib::Path filePath = get_file_path(); - json::Object stringJSON = json::new_object(json_object_from_file, filePath.full_path()); + const std::string stringPath = get_file_path().string(); + json::Object stringJSON = json::new_object(json_object_from_file, stringPath.c_str()); if (!stringJSON) { return false; } json_object_iterator stringIterator = json::iter_begin(stringJSON); @@ -77,7 +78,7 @@ bool strings::initialize() return true; } -const char *strings::get_by_name(std::string_view name, int index) +const char *strings::get_by_name(std::string_view name, int index) noexcept { const auto mapPair = std::make_pair(name.data(), index); const auto findPair = s_stringMap.find(mapPair); diff --git a/source/stringutil.cpp b/source/stringutil.cpp index 77d9b9f..907faa0 100644 --- a/source/stringutil.cpp +++ b/source/stringutil.cpp @@ -59,12 +59,12 @@ bool stringutil::sanitize_string_for_path(const char *stringIn, char *stringOut, const bool countCheck = count <= 0 || i + count >= stringOutSize; const bool codeCheck = codepoint < 0x20 || codepoint > 0x7E; if (countCheck) { break; } + else if (codepoint == L'é') { stringOut[offset++] = 'e'; } else if (codeCheck) { return false; } const bool forbidden = std::find(FORBIDDEN_PATH_CHARACTERS.begin(), FORBIDDEN_PATH_CHARACTERS.end(), codepoint) != FORBIDDEN_PATH_CHARACTERS.end(); if (forbidden) { stringOut[offset++] = 0x20; } - else if (codepoint == L'é') { stringOut[offset++] = 'e'; } else { std::memcpy(&stringOut[offset], &stringIn[i], static_cast(count)); @@ -83,9 +83,9 @@ std::string stringutil::get_date_string(stringutil::DateFormat format) { char stringBuffer[0x80] = {0}; - std::time_t timer; + std::time_t timer{}; std::time(&timer); - std::tm *localTime = std::localtime(&timer); + const std::tm *localTime = std::localtime(&timer); switch (format) { diff --git a/source/sys/ProgressTask.cpp b/source/sys/ProgressTask.cpp index 13d50aa..f03c25e 100644 --- a/source/sys/ProgressTask.cpp +++ b/source/sys/ProgressTask.cpp @@ -1,18 +1,18 @@ #include "sys/ProgressTask.hpp" -void sys::ProgressTask::reset(double goal) +void sys::ProgressTask::reset(double goal) noexcept { m_current = 0; m_goal = goal; } -void sys::ProgressTask::update_current(double current) { m_current = current; } +void sys::ProgressTask::update_current(double current) noexcept { m_current = current; } -void sys::ProgressTask::increase_current(double amount) { m_current += amount; } +void sys::ProgressTask::increase_current(double amount) noexcept { m_current += amount; } -double sys::ProgressTask::get_goal() const { return m_goal; } +double sys::ProgressTask::get_goal() const noexcept { return m_goal; } -double sys::ProgressTask::get_progress() const +double sys::ProgressTask::get_progress() const noexcept { // Reminder: Never divide by zero. It ends badly every time! return m_goal > 0 ? m_current / m_goal : 0; diff --git a/source/sys/Task.cpp b/source/sys/Task.cpp index 572e567..46180e5 100644 --- a/source/sys/Task.cpp +++ b/source/sys/Task.cpp @@ -4,9 +4,9 @@ sys::Task::~Task() { m_thread.join(); } -bool sys::Task::is_running() const { return m_isRunning; } +bool sys::Task::is_running() const noexcept { return m_isRunning; } -void sys::Task::complete() { m_isRunning = false; } +void sys::Task::complete() noexcept { m_isRunning = false; } void sys::Task::set_status(std::string_view status) { @@ -14,7 +14,7 @@ void sys::Task::set_status(std::string_view status) m_status = status; } -std::string sys::Task::get_status() +std::string sys::Task::get_status() noexcept { std::lock_guard statusGuard{m_statusLock}; return m_status; diff --git a/source/sys/Timer.cpp b/source/sys/Timer.cpp index 65b3148..a7078c6 100644 --- a/source/sys/Timer.cpp +++ b/source/sys/Timer.cpp @@ -4,15 +4,15 @@ #include -sys::Timer::Timer(uint64_t triggerTicks) { Timer::start(triggerTicks); } +sys::Timer::Timer(uint64_t triggerTicks) noexcept { Timer::start(triggerTicks); } -void sys::Timer::start(uint64_t triggerTicks) +void sys::Timer::start(uint64_t triggerTicks) noexcept { m_triggerTicks = triggerTicks; m_startingTicks = SDL_GetTicks64(); } -bool sys::Timer::is_triggered() +bool sys::Timer::is_triggered() noexcept { const uint64_t currentTicks = SDL_GetTicks64(); const bool started = m_startingTicks != 0 && m_triggerTicks != 0; @@ -23,4 +23,4 @@ bool sys::Timer::is_triggered() return true; } -void sys::Timer::restart() { m_startingTicks = SDL_GetTicks64(); } +void sys::Timer::restart() noexcept { m_startingTicks = SDL_GetTicks64(); } diff --git a/source/tasks/backup.cpp b/source/tasks/backup.cpp index f2187f6..47fd8bf 100644 --- a/source/tasks/backup.cpp +++ b/source/tasks/backup.cpp @@ -1,8 +1,8 @@ #include "tasks/backup.hpp" #include "config/config.hpp" +#include "error.hpp" #include "fs/fs.hpp" -#include "logging/error.hpp" #include "logging/logger.hpp" #include "remote/remote.hpp" #include "strings/strings.hpp" @@ -36,7 +36,8 @@ void tasks::backup::create_new_backup_local(sys::ProgressTask *task, if (error::is_null(task)) { return; } if (error::is_null(user) || error::is_null(titleInfo)) { TASK_FINISH_RETURN(task); } - const bool hasZipExt = std::strstr(target.full_path(), STRING_ZIP_EXT); + const std::string targetString = target.string(); + const bool hasZipExt = std::strstr(targetString.c_str(), STRING_ZIP_EXT); const uint64_t applicationID = titleInfo->get_application_id(); const FsSaveDataInfo *saveInfo = user->get_save_info_by_id(applicationID); if (error::is_null(saveInfo)) { TASK_FINISH_RETURN(task); } @@ -198,12 +199,16 @@ void tasks::backup::restore_backup_local(sys::ProgressTask *task, BackupMenuStat const uint64_t applicationID = titleInfo->get_application_id(); const FsSaveDataInfo *saveInfo = user->get_save_info_by_id(applicationID); const uint8_t saveType = user->get_account_save_type(); - const uint64_t journalSize = titleInfo->get_journal_size(saveType); if (error::is_null(saveInfo)) { TASK_FINISH_RETURN(task); } - const bool autoBackup = config::get_by_key(config::keys::AUTO_BACKUP_ON_RESTORE); - const bool isDir = fslib::directory_exists(target); - const bool hasZipExt = std::strstr(target.full_path(), STRING_ZIP_EXT); + FsSaveDataExtraData extraData{}; + const bool readExtra = fs::read_save_extra_data(saveInfo, extraData); + const int64_t journalSize = readExtra ? extraData.journal_size : titleInfo->get_journal_size(saveType); + + const std::string targetString = target.string(); + const bool autoBackup = config::get_by_key(config::keys::AUTO_BACKUP_ON_RESTORE); + const bool isDir = fslib::directory_exists(target); + const bool hasZipExt = std::strstr(targetString.c_str(), STRING_ZIP_EXT); const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; if (autoBackup) { auto_backup(task, taskData); } @@ -226,18 +231,18 @@ void tasks::backup::restore_backup_local(sys::ProgressTask *task, BackupMenuStat read_and_process_meta(unzip, taskData, task); auto scopedMount = create_scoped_mount(saveInfo); - fs::copy_zip_to_directory(unzip, fs::DEFAULT_SAVE_ROOT, journalSize, fs::DEFAULT_SAVE_MOUNT, task); + fs::copy_zip_to_directory(unzip, fs::DEFAULT_SAVE_ROOT, journalSize, task); } else if (isDir) { read_and_process_meta(target, taskData, task); auto scopedMount = create_scoped_mount(saveInfo); - fs::copy_directory_commit(target, fs::DEFAULT_SAVE_ROOT, fs::DEFAULT_SAVE_MOUNT, journalSize, task); + fs::copy_directory_commit(target, fs::DEFAULT_SAVE_ROOT, journalSize, task); } else { auto scopedMount = create_scoped_mount(saveInfo); - fs::copy_file_commit(target, fs::DEFAULT_SAVE_ROOT, fs::DEFAULT_SAVE_MOUNT, journalSize, task); + fs::copy_file_commit(target, fs::DEFAULT_SAVE_ROOT, journalSize, task); } spawningState->refresh(); @@ -306,10 +311,12 @@ void tasks::backup::restore_backup_remote(sys::ProgressTask *task, BackupMenuSta read_and_process_meta(backup, taskData, task); { - const uint8_t saveType = user->get_account_save_type(); - const uint64_t journalSize = titleInfo->get_journal_size(saveType); + FsSaveDataExtraData extraData{}; + const bool readExtra = fs::read_save_extra_data(saveInfo, extraData); + const uint8_t saveType = user->get_account_save_type(); + const int64_t journalSize = readExtra ? extraData.journal_size : titleInfo->get_journal_size(saveType); fs::ScopedSaveMount saveMount{fs::DEFAULT_SAVE_MOUNT, saveInfo}; - fs::copy_zip_to_directory(backup, fs::DEFAULT_SAVE_ROOT, journalSize, fs::DEFAULT_SAVE_MOUNT, task); + fs::copy_zip_to_directory(backup, fs::DEFAULT_SAVE_ROOT, journalSize, task); } backup.close(); @@ -333,8 +340,9 @@ void tasks::backup::delete_backup_local(sys::Task *task, BackupMenuState::TaskDa const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; { - const char *statusFormat = strings::get_by_name(strings::names::IO_STATUSES, 3); - const std::string status = stringutil::get_formatted_string(statusFormat, path.full_path()); + const std::string pathString = path.string(); + const char *statusFormat = strings::get_by_name(strings::names::IO_STATUSES, 3); + const std::string status = stringutil::get_formatted_string(statusFormat, pathString.c_str()); task->set_status(status); } diff --git a/source/tasks/fileoptions.cpp b/source/tasks/fileoptions.cpp new file mode 100644 index 0000000..259d8c2 --- /dev/null +++ b/source/tasks/fileoptions.cpp @@ -0,0 +1,72 @@ +#include "tasks/fileoptions.hpp" + +#include "appstates/MessageState.hpp" +#include "error.hpp" +#include "fs/fs.hpp" +#include "fslib.hpp" +#include "strings/strings.hpp" +#include "stringutil.hpp" + +void tasks::fileoptions::copy_source_to_destination(sys::ProgressTask *task, FileOptionState::TaskData taskData) +{ + if (error::is_null(task)) { return; } + + const fslib::Path &source = taskData->sourcePath; + const fslib::Path &dest = taskData->destPath; + const int64_t journalSpace = taskData->journalSize; + FileOptionState *spawningState = taskData->spawningState; + + const bool sourceIsDir = fslib::directory_exists(source); + bool destError = false; + if (sourceIsDir) { destError = error::fslib(fslib::create_directories_recursively(dest)); } + else + { + const size_t subDest = dest.find_last_of('/'); + if (subDest != dest.NOT_FOUND && subDest > 1) + { + fslib::Path subDestPath{dest.sub_path(subDest)}; + destError = error::fslib(fslib::create_directories_recursively(subDestPath)); + } + } + + if (destError) { TASK_FINISH_RETURN(task); } + + const bool needsCommit = journalSpace > 0; + + if (sourceIsDir && needsCommit) { fs::copy_directory_commit(source, dest, journalSpace, task); } + else if (!sourceIsDir && needsCommit) { fs::copy_file_commit(source, dest, journalSpace, task); } + else if (sourceIsDir && !needsCommit) { fs::copy_directory(source, dest, task); } + else if (!sourceIsDir && !needsCommit) { fs::copy_file(source, dest, task); } + + spawningState->update_destination(); + task->complete(); +} + +void tasks::fileoptions::delete_target(sys::Task *task, FileOptionState::TaskData taskData) +{ + if (error::is_null(task)) { return; } + + // Gonna borrow this. No point in duplicating it. + const char *deletingFormat = strings::get_by_name(strings::names::IO_STATUSES, 3); + + const fslib::Path &target = taskData->sourcePath; + const int64_t journalSpace = taskData->journalSize; + FileOptionState *spawningState = taskData->spawningState; + + { + const char *filename = target.get_filename(); + const std::string status = stringutil::get_formatted_string(deletingFormat, filename); + task->set_status(status); + } + + const bool isDir = fslib::directory_exists(target); + bool needsCommit = journalSpace > 0; + + if (isDir) { fslib::delete_directory_recursively(target); } + else { fslib::delete_file(target); } + + if (needsCommit) { fslib::commit_data_to_file_system(target.get_device_name()); } + + spawningState->update_source(); + task->complete(); +} diff --git a/source/tasks/mainmenu.cpp b/source/tasks/mainmenu.cpp index 7985772..ec298b4 100644 --- a/source/tasks/mainmenu.cpp +++ b/source/tasks/mainmenu.cpp @@ -2,8 +2,8 @@ #include "config/config.hpp" #include "data/data.hpp" +#include "error.hpp" #include "fs/fs.hpp" -#include "logging/error.hpp" #include "remote/remote.hpp" #include "stringutil.hpp" #include "tasks/backup.hpp" diff --git a/source/tasks/savecreate.cpp b/source/tasks/savecreate.cpp index 1039ab7..876549e 100644 --- a/source/tasks/savecreate.cpp +++ b/source/tasks/savecreate.cpp @@ -1,7 +1,7 @@ #include "tasks/savecreate.hpp" +#include "error.hpp" #include "fs/fs.hpp" -#include "logging/error.hpp" #include "strings/strings.hpp" #include "stringutil.hpp" #include "ui/PopMessageManager.hpp" diff --git a/source/tasks/titleoptions.cpp b/source/tasks/titleoptions.cpp index 5a4341c..d51ca9d 100644 --- a/source/tasks/titleoptions.cpp +++ b/source/tasks/titleoptions.cpp @@ -2,9 +2,9 @@ #include "config/config.hpp" #include "data/data.hpp" +#include "error.hpp" #include "fs/fs.hpp" #include "keyboard.hpp" -#include "logging/error.hpp" #include "logging/logger.hpp" #include "remote/remote.hpp" #include "strings/strings.hpp" @@ -208,7 +208,7 @@ void tasks::titleoptions::extend_save_data(sys::Task *task, TitleOptionState::Ta std::array sizeBuffer = {0}; FsSaveDataExtraData extraData{}; - const bool readExtra = fs::read_save_data_extra_info(saveInfo, extraData); + const bool readExtra = fs::read_save_extra_data(saveInfo, extraData); const int sizeMB = extraData.data_size / SIZE_MB; const char *keyboardHeader = strings::get_by_name(strings::names::KEYBOARD, 8); diff --git a/source/tasks/useroptions.cpp b/source/tasks/useroptions.cpp index 6f9cd90..f0bb1de 100644 --- a/source/tasks/useroptions.cpp +++ b/source/tasks/useroptions.cpp @@ -1,8 +1,8 @@ #include "tasks/useroptions.hpp" #include "config/config.hpp" +#include "error.hpp" #include "fs/fs.hpp" -#include "logging/error.hpp" #include "remote/remote.hpp" #include "strings/strings.hpp" #include "stringutil.hpp" diff --git a/source/ui/BoundingBox.cpp b/source/ui/BoundingBox.cpp index 71c4ebd..2fb6273 100644 --- a/source/ui/BoundingBox.cpp +++ b/source/ui/BoundingBox.cpp @@ -46,17 +46,13 @@ void ui::BoundingBox::render(sdl::SharedTexture &target, bool hasFocus) sm_corners->render_part(target, rightX, bottomY, CORNER_WIDTH, CORNER_HEIGHT, CORNER_WIDTH, CORNER_HEIGHT); } -void ui::BoundingBox::set_xy(int x, int y) -{ - if (x != BoundingBox::NO_SET) { m_x = x; } - if (y != BoundingBox::NO_SET) { m_y = y; } -} +void ui::BoundingBox::set_x(int x) noexcept { m_x = x; } -void ui::BoundingBox::set_width_height(int width, int height) -{ - if (width != BoundingBox::NO_SET) { m_width = width; } - if (height != BoundingBox::NO_SET) { m_height = height; } -} +void ui::BoundingBox::set_y(int y) noexcept { m_y = y; } + +void ui::BoundingBox::set_width(int width) noexcept { m_width = width; } + +void ui::BoundingBox::set_height(int height) noexcept { m_height = height; } void ui::BoundingBox::initialize_static_members() { diff --git a/source/ui/ColorMod.cpp b/source/ui/ColorMod.cpp index 5b71993..5c4e5d5 100644 --- a/source/ui/ColorMod.cpp +++ b/source/ui/ColorMod.cpp @@ -1,6 +1,6 @@ #include "ui/ColorMod.hpp" -void ui::ColorMod::update() +void ui::ColorMod::update() noexcept { const bool changeDown = m_direction && ((m_colorMod += 6) >= 0x72); const bool changeUp = !m_direction && ((m_colorMod -= 3) <= 0x00); @@ -8,7 +8,7 @@ void ui::ColorMod::update() else if (changeUp) { m_direction = true; } } -ui::ColorMod::operator sdl::Color() const +ui::ColorMod::operator sdl::Color() const noexcept { uint32_t color{}; color |= static_cast((0x88 + m_colorMod) << 16); diff --git a/source/ui/DialogBox.cpp b/source/ui/DialogBox.cpp index fb454e0..9614ab6 100644 --- a/source/ui/DialogBox.cpp +++ b/source/ui/DialogBox.cpp @@ -49,17 +49,13 @@ void ui::DialogBox::render(sdl::SharedTexture &target, bool hasFocus) CORNER_HEIGHT); } -void ui::DialogBox::set_xy(int x, int y) -{ - if (x != DialogBox::NO_SET) { m_x = x; } - if (y != DialogBox::NO_SET) { m_y = y; } -} +void ui::DialogBox::set_x(int x) noexcept { m_x = x; } -void ui::DialogBox::set_width_height(int width, int height) -{ - if (width != DialogBox::NO_SET) { m_width = width; } - if (height != DialogBox::NO_SET) { m_height = height; } -} +void ui::DialogBox::set_y(int y) noexcept { m_y = y; } + +void ui::DialogBox::set_width(int width) noexcept { m_width = width; } + +void ui::DialogBox::set_height(int height) noexcept { m_height = height; } void ui::DialogBox::initialize_static_members() { diff --git a/source/ui/Frame.cpp b/source/ui/Frame.cpp new file mode 100644 index 0000000..becef22 --- /dev/null +++ b/source/ui/Frame.cpp @@ -0,0 +1,56 @@ +#include "ui/Frame.hpp" + +#include "graphics/colors.hpp" + +ui::Frame::Frame(int x, int y, int width, int height) + : m_x(x) + , m_y(y) + , m_width(width) + , m_height(height) +{ + Frame::initialize_static_members(); +} + +void ui::Frame::render(sdl::SharedTexture &target, bool hasFocus) +{ + // This is the size of one of the "tiles" of the frame. + static constexpr int TILE = 16; + + const int midWidth = m_width - (TILE * 2); + const int midHeight = m_height - (TILE * 2); + const int rightEdge = (m_x + m_width) - TILE; + const int bottomEdge = (m_y + m_height) - TILE; + const int textureCorner = TILE * 2; + + // Top. + sm_frameCorners->render_part(target, m_x, m_y, 0, 0, TILE, TILE); + sm_frameCorners->render_part_stretched(target, TILE, 0, TILE, TILE, m_x + TILE, m_y, midWidth, TILE); + sm_frameCorners->render_part(target, rightEdge, m_y, 32, 0, TILE, TILE); + + // Middle + sm_frameCorners->render_part_stretched(target, 0, TILE, TILE, TILE, m_x, m_y + TILE, TILE, midHeight); + sdl::render_rect_fill(target, m_x + TILE, m_y + TILE, midWidth, midHeight, colors::SLIDE_PANEL_CLEAR); + sm_frameCorners->render_part_stretched(target, textureCorner, TILE, TILE, TILE, rightEdge, m_y + TILE, TILE, midHeight); + + // Bottom + sm_frameCorners->render_part(target, m_x, bottomEdge, 0, textureCorner, TILE, TILE); + sm_frameCorners->render_part_stretched(target, TILE, textureCorner, TILE, TILE, m_x + TILE, bottomEdge, midWidth, TILE); + sm_frameCorners->render_part(target, rightEdge, bottomEdge, textureCorner, textureCorner, TILE, TILE); +} + +void ui::Frame::set_x(int x) { m_x = x; } + +void ui::Frame::set_y(int y) { m_y = y; } + +void ui::Frame::set_width(int width) { m_width = width; } + +void ui::Frame::set_height(int height) { m_height = height; } + +void ui::Frame::initialize_static_members() +{ + static constexpr std::string_view FRAME_NAME = "FrameCorners"; + static constexpr const char *FRAME_PATH = "romfs:/Textures/Frame.png"; + + if (sm_frameCorners) { return; } + sm_frameCorners = sdl::TextureManager::load(FRAME_NAME, FRAME_PATH); +} diff --git a/source/ui/IconMenu.cpp b/source/ui/IconMenu.cpp index 0f155b6..ed72f70 100644 --- a/source/ui/IconMenu.cpp +++ b/source/ui/IconMenu.cpp @@ -15,7 +15,8 @@ ui::IconMenu::IconMenu(int x, int y, int renderTargetHeight) : Menu(x, y, 152, 84, renderTargetHeight) { // This needs to be overriden from the base state. - m_boundingBox->set_width_height(152, 146); + m_boundingBox->set_width(152); + m_boundingBox->set_height(146); } void ui::IconMenu::update(bool hasFocus) { Menu::update(hasFocus); } @@ -31,7 +32,8 @@ void ui::IconMenu::render(sdl::SharedTexture &target, bool hasFocus) { if (hasFocus) { - m_boundingBox->set_xy(m_x - 8, tempY - 8); + m_boundingBox->set_x(m_x - 8); + m_boundingBox->set_y(tempY - 8); m_boundingBox->render(target, hasFocus); } // This is always rendered. diff --git a/source/ui/Menu.cpp b/source/ui/Menu.cpp index 430dc76..213ce9b 100644 --- a/source/ui/Menu.cpp +++ b/source/ui/Menu.cpp @@ -63,7 +63,8 @@ void ui::Menu::render(sdl::SharedTexture &target, bool hasFocus) { if (hasFocus) { - m_boundingBox->set_xy(m_x - 4, tempY - 4); + m_boundingBox->set_x(m_x - 4); + m_boundingBox->set_y(tempY - 4); m_boundingBox->render(target, hasFocus); } sdl::render_rect_fill(m_optionTarget, 8, 8, 4, m_optionHeight - 14, colors::BLUE_GREEN); @@ -89,15 +90,18 @@ void ui::Menu::edit_option(int index, std::string_view newOption) m_options[index] = newOption.data(); } -int ui::Menu::get_selected() const { return m_selected; } +int ui::Menu::get_selected() const noexcept { return m_selected; } void ui::Menu::set_selected(int selected) { m_selected = selected; Menu::update_scroll_text(); } +void ui::Menu::set_x(int x) noexcept { m_x = x; } -void ui::Menu::set_width(int width) { m_width = width; } +void ui::Menu::set_y(int y) noexcept { m_y = y; } + +void ui::Menu::set_width(int width) noexcept { m_width = width; } void ui::Menu::reset() { @@ -106,6 +110,8 @@ void ui::Menu::reset() m_options.clear(); } +bool ui::Menu::is_empty() const noexcept { return m_options.empty(); } + void ui::Menu::update_scroll_text() { const std::string_view text = m_optionScroll->get_text(); diff --git a/source/ui/PopMessage.cpp b/source/ui/PopMessage.cpp index c0b550c..816a59b 100644 --- a/source/ui/PopMessage.cpp +++ b/source/ui/PopMessage.cpp @@ -32,11 +32,11 @@ void ui::PopMessage::render() sdl::text::render(sdl::Texture::Null, m_textX, m_y + 5, 22, sdl::text::NO_WRAP, colors::BLACK, message); } -std::string_view ui::PopMessage::get_message() const { return m_message; } +bool ui::PopMessage::finished() const noexcept { return m_finished; } -bool ui::PopMessage::finished() const { return m_finished; } +std::string_view ui::PopMessage::get_message() const noexcept { return m_message; } -void ui::PopMessage::update_y(double targetY) +void ui::PopMessage::update_y(double targetY) noexcept { if (m_y == targetY) { return; } @@ -51,10 +51,10 @@ void ui::PopMessage::update_y(double targetY) m_yMet = true; m_typeTimer.start(5); } - m_dialog->set_xy(m_dialog->NO_SET, m_y - 6); + m_dialog->set_y(m_y - 6); } -void ui::PopMessage::update_text_offset() +void ui::PopMessage::update_text_offset() noexcept { static constexpr int HALF_WIDTH = 640; @@ -76,7 +76,7 @@ void ui::PopMessage::update_text_offset() const int dialogX = m_textX - 16; const int dialogWidth = stringWidth + 32; - m_dialog->set_xy(dialogX, m_dialog->NO_SET); - m_dialog->set_width_height(dialogWidth, m_dialog->NO_SET); + m_dialog->set_x(dialogX); + m_dialog->set_width(dialogWidth); if (m_substrOffset >= messageLength) { m_displayTimer.start(m_ticks); } } diff --git a/source/ui/SlideOutPanel.cpp b/source/ui/SlideOutPanel.cpp index 442b5b4..b6bf9aa 100644 --- a/source/ui/SlideOutPanel.cpp +++ b/source/ui/SlideOutPanel.cpp @@ -25,11 +25,9 @@ ui::SlideOutPanel::SlideOutPanel(int width, Side side) void ui::SlideOutPanel::update(bool hasFocus) { - const bool openingFromLeft = !m_isOpen && m_side == Side::Left && m_x < m_targetX; - const bool openingFromRight = !m_isOpen && m_side == Side::Right && m_x > m_targetX; + if (hasFocus && SlideOutPanel::is_hidden()) { SlideOutPanel::unhide(); } - if (openingFromLeft) { SlideOutPanel::slide_out_left(); } - else if (openingFromRight) { SlideOutPanel::slide_out_right(); } + slide_out(); if (m_isOpen) { @@ -37,6 +35,8 @@ void ui::SlideOutPanel::update(bool hasFocus) } } +void ui::SlideOutPanel::sub_update() { SlideOutPanel::close_hide_panel(); } + void ui::SlideOutPanel::render(sdl::SharedTexture &target, bool hasFocus) { for (auto ¤tElement : m_elements) { currentElement->render(m_renderTarget, hasFocus); } @@ -46,37 +46,49 @@ void ui::SlideOutPanel::render(sdl::SharedTexture &target, bool hasFocus) void ui::SlideOutPanel::clear_target() { m_renderTarget->clear(colors::SLIDE_PANEL_CLEAR); } -void ui::SlideOutPanel::reset() +void ui::SlideOutPanel::reset() noexcept { m_x = m_side == Side::Left ? -(m_width) : SCREEN_WIDTH; m_isOpen = false; m_closePanel = false; } -void ui::SlideOutPanel::close() { m_closePanel = true; } +void ui::SlideOutPanel::close() noexcept { m_closePanel = true; } -bool ui::SlideOutPanel::is_open() const { return m_isOpen; } +void ui::SlideOutPanel::hide() noexcept { m_hidePanel = true; } -bool ui::SlideOutPanel::is_closed() +void ui::SlideOutPanel::unhide() noexcept { m_hidePanel = false; } + +bool ui::SlideOutPanel::is_open() const noexcept { return m_isOpen; } + +bool ui::SlideOutPanel::is_closed() noexcept { - // I'm assuming this is going to be called, waiting for the panel to close so. - const double scaling = config::get_animation_scaling(); - const bool closeToLeft = m_closePanel && m_side == Side::Left && m_x > -m_width; - const bool closeToRight = m_closePanel && m_side == Side::Right && m_x < SCREEN_WIDTH; - if (closeToLeft) { m_x += -(m_width - m_x) / scaling; } - else if (closeToRight) { m_x += m_x / scaling; } - + close_hide_panel(); const bool closed = m_side == Side::Left ? m_x <= -m_width : m_x >= SCREEN_WIDTH; return m_closePanel && closed; } +bool ui::SlideOutPanel::is_hidden() const noexcept { return m_hidePanel; } + void ui::SlideOutPanel::push_new_element(std::shared_ptr newElement) { m_elements.push_back(newElement); } void ui::SlideOutPanel::clear_elements() { m_elements.clear(); } -sdl::SharedTexture &ui::SlideOutPanel::get_target() { return m_renderTarget; } +sdl::SharedTexture &ui::SlideOutPanel::get_target() noexcept { return m_renderTarget; } -void ui::SlideOutPanel::slide_out_left() +void ui::SlideOutPanel::slide_out() noexcept +{ + const bool needsSlideOut = !m_isOpen && !m_closePanel && !m_hidePanel; + if (!needsSlideOut) { return; } + + const bool slideRight = m_side == SlideOutPanel::Side::Left && m_x < 0; + const bool slideLeft = m_side == SlideOutPanel::Side::Right && m_x > SCREEN_WIDTH - m_width; + + if (slideRight) { SlideOutPanel::slide_out_left(); } + else if (slideLeft) { SlideOutPanel::slide_out_right(); } +} + +void ui::SlideOutPanel::slide_out_left() noexcept { const double scaling = config::get_animation_scaling(); @@ -91,7 +103,7 @@ void ui::SlideOutPanel::slide_out_left() } } -void ui::SlideOutPanel::slide_out_right() +void ui::SlideOutPanel::slide_out_right() noexcept { const double scaling = config::get_animation_scaling(); const double screenWidth = static_cast(SCREEN_WIDTH); @@ -106,3 +118,16 @@ void ui::SlideOutPanel::slide_out_right() m_isOpen = true; } } + +void ui::SlideOutPanel::close_hide_panel() noexcept +{ + const double scaling = config::get_animation_scaling(); + const bool closeHide = m_closePanel || m_hidePanel; + const bool closeToLeft = closeHide && m_side == Side::Left && m_x > -m_width; + const bool closeToRight = closeHide && m_side == Side::Right && m_x < SCREEN_WIDTH; + if (closeToLeft) { m_x += -((m_width - m_x) / scaling); } + else if (closeToRight) { m_x += m_x / scaling; } + + const bool closedOrHidden = (m_x <= -m_width) || (m_x >= SCREEN_WIDTH); + if (closedOrHidden) { m_isOpen = false; } +} diff --git a/source/ui/TextScroll.cpp b/source/ui/TextScroll.cpp index f0271db..6b42b79 100644 --- a/source/ui/TextScroll.cpp +++ b/source/ui/TextScroll.cpp @@ -54,7 +54,7 @@ void ui::TextScroll::initialize(std::string_view text, TextScroll::set_text(text, center); } -std::string_view ui::TextScroll::get_text() const { return m_text; } +std::string_view ui::TextScroll::get_text() const noexcept { return m_text; } void ui::TextScroll::set_text(std::string_view text, bool center) { @@ -103,12 +103,6 @@ void ui::TextScroll::update(bool hasFocus) } } -void ui::TextScroll::set_xy(int x, int y) -{ - m_renderX = x; - m_renderY = y; -} - void ui::TextScroll::render(sdl::SharedTexture &target, bool hasFocus) { m_renderTarget->clear(m_clearColor); diff --git a/source/ui/TitleTile.cpp b/source/ui/TitleTile.cpp index d1c082b..a0822ba 100644 --- a/source/ui/TitleTile.cpp +++ b/source/ui/TitleTile.cpp @@ -40,12 +40,12 @@ void ui::TitleTile::render(sdl::SharedTexture &target, int x, int y) if (m_isFavorite) { sdl::text::render(target, renderX + 2, renderY + 2, 28, sdl::text::NO_WRAP, colors::PINK, HEART_CHAR); } } -void ui::TitleTile::reset() +void ui::TitleTile::reset() noexcept { m_renderWidth = 128; m_renderHeight = 128; } -int ui::TitleTile::get_width() const { return m_renderWidth; } +int ui::TitleTile::get_width() const noexcept { return m_renderWidth; } -int ui::TitleTile::get_height() const { return m_renderHeight; } +int ui::TitleTile::get_height() const noexcept { return m_renderHeight; } diff --git a/source/ui/TitleView.cpp b/source/ui/TitleView.cpp index ebf6912..7cec71e 100644 --- a/source/ui/TitleView.cpp +++ b/source/ui/TitleView.cpp @@ -1,9 +1,9 @@ #include "ui/TitleView.hpp" #include "config/config.hpp" +#include "error.hpp" #include "graphics/colors.hpp" #include "input.hpp" -#include "logging/error.hpp" #include "logging/logger.hpp" #include @@ -57,7 +57,8 @@ void ui::TitleView::render(sdl::SharedTexture &target, bool hasFocus) if (hasFocus) { - m_bounding->set_xy(m_selectedX - 30, m_selectedY - 30); + m_bounding->set_x(m_selectedX - 30); + m_bounding->set_y(m_selectedY - 30); sdl::render_rect_fill(target, m_selectedX - 28, m_selectedY - 28, 184, 184, colors::CLEAR_COLOR); m_bounding->render(target, hasFocus); } @@ -66,9 +67,9 @@ void ui::TitleView::render(sdl::SharedTexture &target, bool hasFocus) selectedTile.render(target, m_selectedX, m_selectedY); } -int ui::TitleView::get_selected() const { return m_selected; } +int ui::TitleView::get_selected() const noexcept { return m_selected; } -void ui::TitleView::set_selected(int selected) +void ui::TitleView::set_selected(int selected) noexcept { const int tilesCount = m_titleTiles.size(); if (selected < 0 || selected >= tilesCount) { return; }