diff --git a/include/core/title.h b/include/core/title.h index 8967f88..4814b4e 100644 --- a/include/core/title.h +++ b/include/core/title.h @@ -67,11 +67,12 @@ typedef struct { } TitleUserApplicationData; typedef enum { - TitleFileNameConvention_Full = 0, ///< Individual titles: "[{Name}] [{TitleId}][v{TitleVersion}][{TitleType}]". - ///< Gamecards: "[{Name1}] [{TitleId1}][v{TitleVersion1}] + ... + [{NameN}] [{TitleIdN}][v{TitleVersionN}]". - TitleFileNameConvention_IdAndVersionOnly = 1 ///< Individual titles: "{TitleId}_v{TitleVersion}_{TitleType}". - ///< Gamecards: "{TitleId1}_v{TitleVersion1}_{TitleType1} + ... + {TitleIdN}_v{TitleVersionN}_{TitleTypeN}". -} TitleFileNameConvention; + TitleNamingConvention_Full = 0, ///< Individual titles: "{Name} [{Id}][v{Version}][{Type}]". + ///< Gamecards: "[{Name1}] [{Id1}][v{Version1}] + ... + [{NameN}] [{IdN}][v{VersionN}]". + TitleNamingConvention_IdAndVersionOnly = 1, ///< Individual titles: "{Id}_v{Version}_{Type}". + ///< Gamecards: "{TitleId1}_v{TitleVersion1}_{TitleType1} + ... + {TitleIdN}_v{TitleVersionN}_{TitleTypeN}". + TitleNamingConvention_Count = 2 +} TitleNamingConvention; typedef enum { TitleFileNameIllegalCharReplaceType_None = 0, @@ -130,11 +131,11 @@ void titleFreeOrphanTitles(TitleInfo ***orphan_info); bool titleIsGameCardInfoUpdated(void); /// Returns a pointer to a dynamically allocated buffer that holds a filename string suitable for output title dumps. Returns NULL if an error occurs. -char *titleGenerateFileName(TitleInfo *title_info, u8 name_convention, u8 illegal_char_replace_type); +char *titleGenerateFileName(TitleInfo *title_info, u8 naming_convention, u8 illegal_char_replace_type); /// Returns a pointer to a dynamically allocated buffer that holds a filename string suitable for output gamecard dumps. Returns NULL if an error occurs. /// A valid gamecard must be inserted, and title info must have been loaded from it accordingly. -char *titleGenerateGameCardFileName(u8 name_convention, u8 illegal_char_replace_type); +char *titleGenerateGameCardFileName(u8 naming_convention, u8 illegal_char_replace_type); /// Returns a pointer to a string holding the name of the provided NcmContentType value. Returns NULL if the provided value is invalid. const char *titleGetNcmContentTypeName(u8 content_type); diff --git a/include/options_tab.hpp b/include/options_tab.hpp new file mode 100644 index 0000000..6b9e95c --- /dev/null +++ b/include/options_tab.hpp @@ -0,0 +1,38 @@ +/* + * options_tab.hpp + * + * Copyright (c) 2020-2021, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nxdumptool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#ifndef __OPTIONS_TAB_HPP__ +#define __OPTIONS_TAB_HPP__ + +#include + +namespace nxdt::views +{ + class OptionsTab: public brls::List + { + public: + OptionsTab(void); + }; +} + +#endif /* __OPTIONS_TAB_HPP__ */ diff --git a/libs/borealis b/libs/borealis index 6d95c14..bfc32db 160000 --- a/libs/borealis +++ b/libs/borealis @@ -1 +1 @@ -Subproject commit 6d95c14f2f91dc6c2bcb1d1d0e4ebdd1f00f7c3b +Subproject commit bfc32dba9394409691a940896d2a10dfc65c10df diff --git a/romfs/default_config.json b/romfs/default_config.json index a55b1dc..a8d8c88 100644 --- a/romfs/default_config.json +++ b/romfs/default_config.json @@ -1,6 +1,6 @@ { "overclock": true, - "name_convention": 0, + "naming_convention": 0, "dump_destination": 0, "gamecard": { "append_key_area": false, diff --git a/romfs/i18n/en-US/options_tab.json b/romfs/i18n/en-US/options_tab.json new file mode 100644 index 0000000..483ae38 --- /dev/null +++ b/romfs/i18n/en-US/options_tab.json @@ -0,0 +1,20 @@ +{ + "overclock": { + "label": "Overclock", + "description": "Overclocks both CPU and MEM to 1785 MHz and 1600 MHz, respectively, in order to speed up dump operations. This is considered a relatively safe action.\n\nIf the application is running under title override mode, and sys-clk is active, and a clock profile has been created for the overriden title, this setting has no effect at all.", + "value_enabled": "Yes", + "value_disabled": "No" + }, + + "naming_convention": { + "label": "Naming convention", + "description": "Sets the naming convention used for all output dumps.\n\n\uE016 Full: \"{Name} [{Id}][v{Version}][{Type}]\".\n\uE016 ID and version only: \"{Id}_v{Version}_{Type}\".\n\nIf \"Full\" is selected, the display version string will also be appended to dumped updates whenever possible.", + "value_00": "Full", + "value_01": "ID and version only" + }, + + "update_app": { + "label": "Update application", + "description": "Checks if an update is available in nxdumptool's GitHub repository. Requires Internet connectivity." + } +} diff --git a/source/core/config.c b/source/core/config.c index 2058ee1..30baec1 100644 --- a/source/core/config.c +++ b/source/core/config.c @@ -151,6 +151,8 @@ static bool configParseConfigJson(void) end: if (use_default_config) { + LOG_MSG("Loading default configuration."); + /* Free config JSON. */ configFreeConfigJson(); @@ -171,7 +173,7 @@ end: static void configWriteConfigJson(void) { if (!g_configJson) return; - if (json_object_to_file_ext(CONFIG_PATH, g_configJson, JSON_C_TO_STRING_PRETTY) != 0) configLogJsonError(); + if (json_object_to_file_ext(CONFIG_PATH, g_configJson, JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY) != 0) configLogJsonError(); } static void configFreeConfigJson(void) @@ -231,7 +233,7 @@ end: static bool configValidateJsonRootObject(const struct json_object *obj) { - bool ret = false, overclock_found = false, name_convention_found = false, dump_destination_found = false, gamecard_found = false; + bool ret = false, overclock_found = false, naming_convention_found = false, dump_destination_found = false, gamecard_found = false; bool nsp_found = false, ticket_found = false, nca_fs_found = false; if (!configValidateJsonObject(obj)) goto end; @@ -239,7 +241,7 @@ static bool configValidateJsonRootObject(const struct json_object *obj) json_object_object_foreach(obj, key, val) { JSON_VALIDATE_FIELD(Boolean, overclock); - JSON_VALIDATE_FIELD(Integer, name_convention, TitleFileNameConvention_Full, TitleFileNameConvention_IdAndVersionOnly); + JSON_VALIDATE_FIELD(Integer, naming_convention, TitleNamingConvention_Full, TitleNamingConvention_IdAndVersionOnly); JSON_VALIDATE_FIELD(Integer, dump_destination, ConfigDumpDestination_SdCard, ConfigDumpDestination_UsbHost); JSON_VALIDATE_OBJECT(GameCard, gamecard); JSON_VALIDATE_OBJECT(Nsp, nsp); @@ -248,7 +250,7 @@ static bool configValidateJsonRootObject(const struct json_object *obj) goto end; } - ret = (overclock_found && name_convention_found && dump_destination_found && gamecard_found && nsp_found && ticket_found && nca_fs_found); + ret = (overclock_found && naming_convention_found && dump_destination_found && gamecard_found && nsp_found && ticket_found && nca_fs_found); end: return ret; diff --git a/source/core/nxdt_utils.c b/source/core/nxdt_utils.c index 9f98f87..c260151 100644 --- a/source/core/nxdt_utils.c +++ b/source/core/nxdt_utils.c @@ -153,7 +153,11 @@ bool utilsInitializeResources(const int program_argc, const char **program_argv) if (!umsInitialize()) break; /* Load keyset. */ - if (!keysLoadKeyset()) break; + if (!keysLoadKeyset()) + { + LOG_MSG("Failed to load keyset!\nUpdate your keys file with Lockpick_RCM:\n" LOCKPICK_RCM_URL); + break; + } /* Allocate NCA crypto buffer. */ if (!ncaAllocateCryptoBuffer()) diff --git a/source/core/title.c b/source/core/title.c index 1d76ba8..35c192a 100644 --- a/source/core/title.c +++ b/source/core/title.c @@ -919,10 +919,10 @@ bool titleIsGameCardInfoUpdated(void) return ret; } -char *titleGenerateFileName(TitleInfo *title_info, u8 name_convention, u8 illegal_char_replace_type) +char *titleGenerateFileName(TitleInfo *title_info, u8 naming_convention, u8 illegal_char_replace_type) { - if (!title_info || title_info->meta_key.type < NcmContentMetaType_Application || title_info->meta_key.type > NcmContentMetaType_Delta || name_convention > TitleFileNameConvention_IdAndVersionOnly || \ - (name_convention == TitleFileNameConvention_Full && illegal_char_replace_type > TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly)) + if (!title_info || title_info->meta_key.type < NcmContentMetaType_Application || title_info->meta_key.type > NcmContentMetaType_Delta || naming_convention > TitleNamingConvention_IdAndVersionOnly || \ + (naming_convention == TitleNamingConvention_Full && illegal_char_replace_type > TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly)) { LOG_MSG("Invalid parameters!"); return NULL; @@ -932,7 +932,7 @@ char *titleGenerateFileName(TitleInfo *title_info, u8 name_convention, u8 illega char title_name[0x400] = {0}, *version_str = NULL, *filename = NULL; /* Generate filename for this title. */ - if (name_convention == TitleFileNameConvention_Full) + if (naming_convention == TitleNamingConvention_Full) { if (title_info->app_metadata && *(title_info->app_metadata->lang_entry.name)) { @@ -951,7 +951,7 @@ char *titleGenerateFileName(TitleInfo *title_info, u8 name_convention, u8 illega sprintf(title_name + strlen(title_name), "[%016lX][v%u][%s]", title_info->meta_key.id, title_info->meta_key.version, g_filenameTypeStrings[type]); } else - if (name_convention == TitleFileNameConvention_IdAndVersionOnly) + if (naming_convention == TitleNamingConvention_IdAndVersionOnly) { sprintf(title_name, "%016lX_v%u_%s", title_info->meta_key.id, title_info->meta_key.version, g_filenameTypeStrings[type]); } @@ -963,7 +963,7 @@ char *titleGenerateFileName(TitleInfo *title_info, u8 name_convention, u8 illega return filename; } -char *titleGenerateGameCardFileName(u8 name_convention, u8 illegal_char_replace_type) +char *titleGenerateGameCardFileName(u8 naming_convention, u8 illegal_char_replace_type) { char *filename = NULL; @@ -978,8 +978,8 @@ char *titleGenerateGameCardFileName(u8 name_convention, u8 illegal_char_replace_ char app_name[0x400] = {0}; bool error = false; - if (!g_titleInterfaceInit || !g_titleGameCardAvailable || name_convention > TitleFileNameConvention_IdAndVersionOnly || \ - (name_convention == TitleFileNameConvention_Full && illegal_char_replace_type > TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly)) + if (!g_titleInterfaceInit || !g_titleGameCardAvailable || naming_convention > TitleNamingConvention_IdAndVersionOnly || \ + (naming_convention == TitleNamingConvention_Full && illegal_char_replace_type > TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly)) { LOG_MSG("Invalid parameters!"); break; @@ -1013,7 +1013,7 @@ char *titleGenerateGameCardFileName(u8 name_convention, u8 illegal_char_replace_ /* Generate current user application name. */ *app_name = '\0'; - if (name_convention == TitleFileNameConvention_Full) + if (naming_convention == TitleNamingConvention_Full) { if (cur_filename_len) strcat(app_name, " + "); @@ -1035,7 +1035,7 @@ char *titleGenerateGameCardFileName(u8 name_convention, u8 illegal_char_replace_ sprintf(app_name + strlen(app_name), "[%016lX][v%u]", app_info->meta_key.id, app_version); } else - if (name_convention == TitleFileNameConvention_IdAndVersionOnly) + if (naming_convention == TitleNamingConvention_IdAndVersionOnly) { if (cur_filename_len) strcat(app_name, "+"); sprintf(app_name + strlen(app_name), "%016lX_v%u", app_info->meta_key.id, app_version); diff --git a/source/options_tab.cpp b/source/options_tab.cpp new file mode 100644 index 0000000..d5a0a65 --- /dev/null +++ b/source/options_tab.cpp @@ -0,0 +1,67 @@ +/* + * options_tab.cpp + * + * Copyright (c) 2020-2021, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nxdumptool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +using namespace brls::i18n::literals; /* For _i18n. */ + +namespace nxdt::views +{ + OptionsTab::OptionsTab(void) : brls::List() + { + /* Set custom spacing. */ + this->setSpacing(this->getSpacing() / 2); + this->setMarginBottom(20); + + /* Overclock. */ + brls::ToggleListItem *overclock = new brls::ToggleListItem("options_tab/overclock/label"_i18n, configGetBoolean("overclock"), \ + "options_tab/overclock/description"_i18n, "options_tab/overclock/value_enabled"_i18n, \ + "options_tab/overclock/value_disabled"_i18n); + overclock->getClickEvent()->subscribe([](brls::View* view) { + brls::ToggleListItem *item = static_cast(view); + bool value = item->getToggleState(); + utilsOverclockSystem(value); + configSetBoolean("overclock", value); + }); + this->addView(overclock); + + /* Naming convention. */ + brls::SelectListItem *naming_convention = new brls::SelectListItem("options_tab/naming_convention/label"_i18n, { + "options_tab/naming_convention/value_00"_i18n, + "options_tab/naming_convention/value_01"_i18n + }, static_cast(configGetInteger("naming_convention")), + "options_tab/naming_convention/description"_i18n); + naming_convention->getValueSelectedEvent()->subscribe([](int selected){ + if (selected < 0 || selected > static_cast(TitleNamingConvention_Count)) return; + configSetInteger("naming_convention", selected); + }); + this->addView(naming_convention); + + /* Update application. */ + if (!envIsNso()) + { + brls::ListItem *update_app = new brls::ListItem("options_tab/update_app/label"_i18n, "options_tab/update_app/description"_i18n); + this->addView(update_app); + } + } +} diff --git a/source/root_view.cpp b/source/root_view.cpp index f01b03f..6bb97a3 100644 --- a/source/root_view.cpp +++ b/source/root_view.cpp @@ -23,7 +23,7 @@ #include #include #include -//#include +#include #include namespace i18n = brls::i18n; /* For getStr(). */ @@ -111,7 +111,7 @@ namespace nxdt::views this->addSeparator(); - this->addTab("root_view/tabs/options"_i18n, new brls::Rectangle(nvgRGB(255, 255, 0))); + this->addTab("root_view/tabs/options"_i18n, new OptionsTab()); this->addSeparator(); diff --git a/todo.txt b/todo.txt index d8f9c39..f231c9a 100644 --- a/todo.txt +++ b/todo.txt @@ -23,7 +23,7 @@ todo: usb: improve abi (make it rest-like?) usb: improve cancel mechanism - others: config load/save using json + others: use hardcoded directories, move data to hardcoded directory if the launch path isn't the right one others: dump verification via nswdb / no-intro others: update application feature others: fatfs browser for emmc partitions