Merge pull request #287 from J-D-K/dev

Implement File Mode, add noexcept where appropriate, update fslib for full RAII FS.
This commit is contained in:
JK 2025-09-06 13:08:43 -04:00 committed by GitHub
commit f052d0b2a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
130 changed files with 2166 additions and 772 deletions

1
.gitignore vendored
View File

@ -16,3 +16,4 @@ JKSV.pfs0
#sometimes I give jksv to people and forget about this.
JKSV.zip
JKSV.nro.zip

@ -1 +1 @@
Subproject commit f948cecb43c4f1e089442a8c0fd58df7deefb955
Subproject commit 30f56742733a350a1f4788d6fa2bcf26712ae669

@ -1 +1 @@
Subproject commit fa7d0f456c78d7f94b8519260978419b564610b8
Subproject commit 779fc5bd8aa4782e376fbce3baa146837f7d4825

View File

@ -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

View File

@ -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();

View File

@ -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{};

View File

@ -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();
};

View File

@ -0,0 +1,160 @@
#pragma once
#include "StateManager.hpp"
#include "appstates/BaseState.hpp"
#include "fslib.hpp"
#include "sdl.hpp"
#include "ui/ui.hpp"
#include <string_view>
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<FileModeState> create(std::string_view mountA,
std::string_view mountB,
int64_t journalSize = 0)
{
return std::make_shared<FileModeState>(mountA, mountB, journalSize);
}
static inline std::shared_ptr<FileModeState> create_and_push(std::string_view mountA,
std::string_view mountB,
int64_t journalSize = 0)
{
auto newState = std::make_shared<FileModeState>(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<ui::Menu> m_dirMenuA{};
std::shared_ptr<ui::Menu> 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<ui::Frame> 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<char>::length(path.get_path()) <= 1; }
/// @brief Closes the filesystems passed and deactivates the state.
void deactivate_state() noexcept;
};

View File

@ -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 <atomic>
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<FileOptionState> create(FileModeState *spawningState)
{
return std::make_shared<FileOptionState>(spawningState);
}
/// @brief Same as above. Pushes state before returning it.
static inline std::shared_ptr<FileOptionState> 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<FileOptionState::DataStruct>;
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<bool> m_updateSource{};
std::atomic<bool> m_updateDest{};
/// @brief This is the data struct passed to tasks.
std::shared_ptr<FileOptionState::DataStruct> m_dataStruct{};
/// @brief This is shared by all instances.
static inline std::shared_ptr<ui::Menu> sm_copyMenu{};
/// @brief This is shared by all instances.
static inline std::shared_ptr<ui::DialogBox> 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();
};

View File

@ -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;

View File

@ -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;

View File

@ -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<uint64_t> &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);

View File

@ -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.

View File

@ -1,34 +1,31 @@
#pragma once
#include <string_view>
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";
}

View File

@ -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<sys::byte> 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{};
};

View File

@ -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{};
};

View File

@ -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);

View File

@ -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<NsApplicationControlData> &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<NsApplicationControlData> 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

View File

@ -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.

View File

@ -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);

View File

@ -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.

View File

@ -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;
}

View File

@ -6,7 +6,7 @@
namespace fs
{
class MiniUnzip
class MiniUnzip final
{
public:
MiniUnzip() = default;

View File

@ -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{};
};

View File

@ -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<std::string> m_paths{};
std::vector<fslib::Path> m_paths{};
};
}

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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);

View File

@ -1,5 +1,6 @@
#pragma once
#include "data/data.hpp"
#include <switch.h>
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

View File

@ -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

View File

@ -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.

View File

@ -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};

View File

@ -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

View File

@ -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

View File

@ -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; }
};
}

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -1,44 +1,46 @@
#pragma once
#include <string_view>
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";
}

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -4,40 +4,37 @@
#include <string>
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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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<ui::BoundingBox> 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.

View File

@ -1,5 +1,6 @@
#pragma once
#include "sdl.hpp"
#include <cstdint>
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.

View File

@ -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<ui::DialogBox> 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.

View File

@ -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.

58
include/ui/Frame.hpp Normal file
View File

@ -0,0 +1,58 @@
#pragma once
#include "sdl.hpp"
#include "ui/Element.hpp"
#include <memory>
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<ui::Frame> create(int x, int y, int width, int height)
{
return std::make_shared<ui::Frame>(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();
};
}

View File

@ -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<ui::IconMenu> create(int x, int y, int renderTargetHeight)
{

View File

@ -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();

View File

@ -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<ui::DialogBox> 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;
};
}

View File

@ -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<std::shared_ptr<ui::Element>> 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

View File

@ -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<ui::TextScroll> 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{};

View File

@ -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{};

View File

@ -18,9 +18,6 @@ namespace ui
/// @param user User to use.
TitleView(data::User *user);
/// @brief Required destructor.
~TitleView() {};
static inline std::shared_ptr<ui::TitleView> create(data::User *user)
{
return std::make_shared<ui::TitleView>(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();

View File

@ -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"

View File

@ -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]"
]
}
}

BIN
romfs/Textures/Frame.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

View File

@ -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 <typename... Args>
@ -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;
}

View File

@ -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<BaseState> &back = stateVector.back();
if (!back->has_focus()) { back->give_focus(); }
back->update();

View File

@ -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++});

View File

@ -1,6 +1,6 @@
#include "appstates/BaseState.hpp"
#include "logging/error.hpp"
#include "error.hpp"
#include <switch.h>

View File

@ -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()

View File

@ -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;

View File

@ -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 <cmath>
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<double>::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();
}

View File

@ -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 <ctime>
namespace
{
enum
{
COPY,
DELETE,
RENAME,
CREATE_DIR,
PROPERTIES,
CLOSE
};
// These make things easier to read and type.
using TaskConfirm = ConfirmState<sys::Task, TaskState, FileOptionState::DataStruct>;
using ProgressConfirm = ConfirmState<sys::ProgressTask, ProgressState, FileOptionState::DataStruct>;
}
// 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::DataStruct>())
{
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<int>::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<std::time_t>(timestamp.created);
const std::time_t modified = static_cast<std::time_t>(timestamp.modified);
const std::time_t accessed = static_cast<std::time_t>(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<double>(totalSize) / static_cast<double>(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<double>(totalSize) / static_cast<double>(THRESHOLD_BYTES);
sizeString = stringutil::get_formatted_string("%.02f KB", kilobytes);
}
else
{
const double megabytes = static_cast<double>(totalSize) / static_cast<double>(THRESHOLD_KB);
sizeString = stringutil::get_formatted_string("%.02f MB", megabytes);
}
return sizeString;
}

View File

@ -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"

View File

@ -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<char, FS_MAX_PATH> 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);
}

View File

@ -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"

View File

@ -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()
{

View File

@ -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()
{

View File

@ -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<uint64_t> &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)

View File

@ -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<uint64_t> &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)
{

View File

@ -1,6 +1,6 @@
#include "curl/curl.hpp"
#include "logging/error.hpp"
#include "error.hpp"
#include "logging/logger.hpp"
#include "stringutil.hpp"

View File

@ -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<NsApplicationControlData>();
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<NsApplicationControlData>();
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<NsApplicationControlData>();
do {
auto controlData = std::make_unique<NsApplicationControlData>();
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;

View File

@ -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 <cstring>
data::TitleInfo::TitleInfo(uint64_t applicationID)
data::TitleInfo::TitleInfo(uint64_t applicationID) noexcept
: m_applicationID(applicationID)
, m_data(std::make_unique<NsApplicationControlData>())
{
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<NsApplicationControlData> &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<char>::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
{

View File

@ -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);

View File

@ -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 <switch.h>
@ -23,11 +24,14 @@ void data::launch_initialization(bool clearCache, std::function<void()> 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); }

View File

@ -1,4 +1,4 @@
#include "logging/error.hpp"
#include "error.hpp"
#include "fslib.hpp"
#include "logging/logger.hpp"
@ -7,9 +7,9 @@
#include <string_view>
/// @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();

View File

@ -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;

View File

@ -1,14 +1,19 @@
#include "fs/MiniZip.hpp"
#include "config/config.hpp"
#include "logging/error.hpp"
#include "error.hpp"
#include "logging/logger.hpp"
#include <ctime>
// 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()
{

View File

@ -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();
}

View File

@ -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<FsSaveDataSpaceId>(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;

View File

@ -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; }

View File

@ -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; }
}

View File

@ -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<double>(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<double>(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); }
}
}

View File

@ -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<FsSaveDataSpaceId>(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<FsSaveDataSpaceId>(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<FsSaveDataSpaceId>(saveInfo->save_data_space_id);
const bool readError = error::libnx(
fsReadSaveDataFileSystemExtraDataBySaveDataSpaceId(&extraOut, EXTRA_SIZE, spaceID, saveInfo->save_data_id));
return !readError;
}

View File

@ -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<double>(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<sys::byte[]> &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());
}

View File

@ -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);
}

View File

@ -1,6 +1,6 @@
#include "keyboard.hpp"
#include "logging/error.hpp"
#include "error.hpp"
#include <string>

Some files were not shown because too many files have changed in this diff Show More