[ci skip] DumpOptionsFrame: add GetOutputFilePath method

Other changes include:

* DumpOptionsFrame: update contructors to also take a base output path string.

* GameCardImageDumpOptionsFrame: simplify constructor by letting it take care of retrieving the title on its own.

* nxdt_utils: remove utilsCreateOutputDirectories() function -- we'll be using utilsCreateDirectoryTree() anyway, so it's okay.
This commit is contained in:
Pablo Curiel 2024-04-20 23:52:56 +02:00
parent 17ec42d812
commit 1181a95d17
9 changed files with 83 additions and 86 deletions

View File

@ -152,10 +152,6 @@ void utilsGenerateFormattedSizeString(double size, char *dst, size_t dst_size);
/// Returns false if there's an error.
bool utilsGetFileSystemStatsByPath(const char *path, u64 *out_total, u64 *out_free);
/// Creates output directories in the specified device.
/// If 'device' is NULL, output directories will be created on the SD card.
void utilsCreateOutputDirectories(const char *device);
/// Returns true if a file exists.
bool utilsCheckIfFileExists(const char *path);

View File

@ -81,12 +81,12 @@
#define HBMENU_BASE_PATH "/switch/"
#define APP_BASE_PATH HBMENU_BASE_PATH APP_TITLE "/"
#define GAMECARD_PATH APP_BASE_PATH "Gamecard/"
#define HFS_PATH APP_BASE_PATH "HFS/"
#define NSP_PATH APP_BASE_PATH "NSP/"
#define TICKET_PATH APP_BASE_PATH "Ticket/"
#define NCA_PATH APP_BASE_PATH "NCA/"
#define NCA_FS_PATH APP_BASE_PATH "NCA FS/"
#define GAMECARD_SUBDIR "Gamecard"
#define HFS_SUBDIR "HFS"
#define NSP_SUBDIR "NSP"
#define TICKET_SUBDIR "Ticket"
#define NCA_SUBDIR "NCA"
#define NCA_FS_SUBDIR "NCA FS"
#define CONFIG_FILE_NAME APP_TITLE "_config.json"
#define DEFAULT_CONFIG_PATH "romfs:/default_config.json"

View File

@ -80,7 +80,7 @@ namespace nxdt::tasks
/* Runs in the background thread. */
bool doInBackground(const std::string& path, const std::string& url, const bool& force_https) override final
{
/* If the process fails or if it's cancelled, httpDownloadFile() will take care of closing the incomplete output file and delete it. */
/* If the process fails or if it's cancelled, httpDownloadFile() will take care of closing the incomplete output file and deleting it. */
return httpDownloadFile(path.c_str(), url.c_str(), force_https, DownloadFileTask::HttpProgressCallback, this);
}

View File

@ -34,7 +34,7 @@ namespace nxdt::views
{
private:
RootView *root_view = nullptr;
std::string raw_filename{}, extension{};
std::string storage_prefix{}, base_output_path{}, raw_filename{}, extension{};
brls::List *list = nullptr;
brls::InputListItem *filename = nullptr;
@ -45,24 +45,23 @@ namespace nxdt::views
bool finalized = false;
void Initialize(std::string& title, brls::Image *icon);
void Initialize(const std::string& title, brls::Image *icon);
std::string SanitizeUserFileName(void);
void UpdateOutputStorages(const nxdt::tasks::UmsDeviceVector& ums_devices);
void UpdateStoragePrefix(u32 selected);
protected:
DumpOptionsFrame(RootView *root_view, std::string& title, std::string& raw_filename, std::string extension);
DumpOptionsFrame(RootView *root_view, std::string& title, brls::Image *icon, std::string& raw_filename, std::string extension);
DumpOptionsFrame(RootView *root_view, const std::string& title, const std::string& base_output_path, const std::string& raw_filename, const std::string& extension);
DumpOptionsFrame(RootView *root_view, const std::string& title, brls::Image *icon, const std::string& base_output_path, const std::string& raw_filename, const std::string& extension);
~DumpOptionsFrame();
bool onCancel(void) override final;
void addView(brls::View *view, bool fill = false);
std::string GetFileName(void);
std::string GetOutputStoragePrefix(void);
const std::string GetOutputFilePath(void);
ALWAYS_INLINE brls::GenericEvent::Subscription RegisterButtonListener(brls::GenericEvent::Callback cb)
{

View File

@ -38,7 +38,7 @@ namespace nxdt::views
brls::SelectListItem *checksum_lookup_method = nullptr;
public:
GameCardImageDumpOptionsFrame(RootView *root_view, std::string title, std::string raw_filename);
GameCardImageDumpOptionsFrame(RootView *root_view, std::string raw_filename);
};
}

View File

@ -87,19 +87,6 @@ static const u32 g_sizeSuffixesCount = MAX_ELEMENTS(g_sizeSuffixes);
static const char g_illegalFileSystemChars[] = "\\/:*?\"<>|";
static const size_t g_illegalFileSystemCharsLength = (MAX_ELEMENTS(g_illegalFileSystemChars) - 1);
static const char *g_outputDirs[] = {
HBMENU_BASE_PATH,
APP_BASE_PATH,
GAMECARD_PATH,
HFS_PATH,
NSP_PATH,
TICKET_PATH,
NCA_PATH,
NCA_FS_PATH
};
static const size_t g_outputDirsCount = MAX_ELEMENTS(g_outputDirs);
static bool g_appUpdated = false;
static const SplConfigItem SplConfigItem_ExosphereApiVersion = (SplConfigItem)65000;
@ -205,10 +192,6 @@ bool utilsInitializeResources(void)
LOG_MSG_INFO("Running under %s %s unit in %s mode.", g_isDevUnit ? "development" : "retail", utilsIsMarikoUnit() ? "Mariko" : "Erista", utilsIsAppletMode() ? "applet" : "title override");
/* Create output directories (SD card only). */
/* TODO: remove the APP_TITLE check whenever we're ready for a release. */
if (!strcasecmp(APP_TITLE, "nxdumptool")) utilsCreateOutputDirectories(NULL);
if (g_appLaunchPath)
{
LOG_MSG_INFO("Launch path: \"%s\".", g_appLaunchPath);
@ -217,6 +200,7 @@ bool utilsInitializeResources(void)
/* TODO: uncomment this block whenever we are ready for a release. */
/*if (strcmp(g_appLaunchPath, NRO_PATH) != 0)
{
utilsCreateDirectoryTree(NRO_PATH, false);
remove(NRO_PATH);
rename(g_appLaunchPath, NRO_PATH);
@ -786,24 +770,6 @@ bool utilsGetFileSystemStatsByPath(const char *path, u64 *out_total, u64 *out_fr
return true;
}
void utilsCreateOutputDirectories(const char *device)
{
size_t device_len = 0;
char path[FS_MAX_PATH] = {0};
if (device && (!(device_len = strlen(device)) || device[device_len - 1] != ':'))
{
LOG_MSG_ERROR("Invalid parameters!");
return;
}
for(size_t i = 0; i < g_outputDirsCount; i++)
{
sprintf(path, "%s%s", (device ? device : DEVOPTAB_SDMC_DEVICE), g_outputDirs[i]);
mkdir(path, 0744);
}
}
bool utilsCheckIfFileExists(const char *path)
{
if (!path || !*path) return false;

View File

@ -26,7 +26,8 @@ using namespace i18n::literals; /* For _i18n. */
namespace nxdt::views
{
DumpOptionsFrame::DumpOptionsFrame(RootView *root_view, std::string& title, std::string& raw_filename, std::string extension) : brls::ThumbnailFrame(), root_view(root_view), raw_filename(raw_filename), extension(extension)
DumpOptionsFrame::DumpOptionsFrame(RootView *root_view, const std::string& title, const std::string& base_output_path, const std::string& raw_filename, const std::string& extension) :
brls::ThumbnailFrame(), root_view(root_view), base_output_path(base_output_path), raw_filename(raw_filename), extension(extension)
{
/* Generate icon using the default image. */
brls::Image *icon = new brls::Image();
@ -37,7 +38,8 @@ namespace nxdt::views
this->Initialize(title, icon);
}
DumpOptionsFrame::DumpOptionsFrame(RootView *root_view, std::string& title, brls::Image *icon, std::string& raw_filename, std::string extension) : brls::ThumbnailFrame(), root_view(root_view), raw_filename(raw_filename), extension(extension)
DumpOptionsFrame::DumpOptionsFrame(RootView *root_view, const std::string& title, brls::Image *icon, const std::string& base_output_path, const std::string& raw_filename, const std::string& extension) :
brls::ThumbnailFrame(), root_view(root_view), base_output_path(base_output_path), raw_filename(raw_filename), extension(extension)
{
/* Initialize the rest of the elements. */
this->Initialize(title, icon);
@ -52,7 +54,7 @@ namespace nxdt::views
this->root_view->UnregisterUmsTaskListener(this->ums_task_sub);
}
void DumpOptionsFrame::Initialize(std::string& title, brls::Image *icon)
void DumpOptionsFrame::Initialize(const std::string& title, brls::Image *icon)
{
/* Set UI properties. */
this->setTitle(title);
@ -86,11 +88,17 @@ namespace nxdt::views
/* Sanitize output filename for the selected storage. */
this->filename->setValue(this->SanitizeUserFileName());
/* Update the storage prefix. */
this->UpdateStoragePrefix(static_cast<u32>(selected));
});
/* Manually update output storages vector. */
/* Manually update the output storages vector. */
this->UpdateOutputStorages(this->root_view->GetUmsDevices());
/* Manually update the storage prefix. */
this->UpdateStoragePrefix(this->output_storage->getSelectedValue());
this->list->addView(this->output_storage);
/* Subscribe to the UMS device event. */
@ -180,6 +188,25 @@ namespace nxdt::views
}
}
void DumpOptionsFrame::UpdateStoragePrefix(u32 selected)
{
switch(selected)
{
case ConfigOutputStorage_SdCard:
this->storage_prefix = DEVOPTAB_SDMC_DEVICE "/";
break;
case ConfigOutputStorage_UsbHost:
this->storage_prefix = "/";
break;
default:
{
const nxdt::tasks::UmsDeviceVector& ums_devices = this->root_view->GetUmsDevices();
this->storage_prefix = std::string(ums_devices.at(selected - ConfigOutputStorage_Count).first->name);
break;
}
}
}
bool DumpOptionsFrame::onCancel(void)
{
/* Pop view. */
@ -192,33 +219,35 @@ namespace nxdt::views
this->list->addView(view, fill);
}
std::string DumpOptionsFrame::GetFileName(void)
const std::string DumpOptionsFrame::GetOutputFilePath(void)
{
return this->filename->getValue();
}
std::string output = this->storage_prefix;
u32 selected = this->output_storage->getSelectedValue();
char *sanitized_path = nullptr;
std::string DumpOptionsFrame::GetOutputStoragePrefix(void)
{
std::string prefix{};
u8 selected = static_cast<u8>(this->output_storage ? this->output_storage->getSelectedValue() : configGetInteger("output_storage"));
switch(selected)
if (selected == ConfigOutputStorage_SdCard || selected >= ConfigOutputStorage_Count)
{
case ConfigOutputStorage_SdCard:
prefix = DEVOPTAB_SDMC_DEVICE "/";
break;
case ConfigOutputStorage_UsbHost:
prefix = "/";
break;
default:
{
const nxdt::tasks::UmsDeviceVector& ums_devices = this->root_view->GetUmsDevices();
prefix = std::string(ums_devices.at(selected - ConfigOutputStorage_Count).first->name);
break;
}
/* Remove the trailing path separator (if available) and append the application's base path if we're dealing with an SD card or a UMS device. */
if (output.back() == '/') output.pop_back();
output += APP_BASE_PATH;
}
return prefix;
/* Append a path separator, if needed. */
if (output.back() != '/' && this->base_output_path.front() != '/') output.push_back('/');
/* Append the base output path string. */
output += this->base_output_path;
/* Generate the sanitized file path. */
sanitized_path = utilsGeneratePath(output.c_str(), this->filename->getValue().c_str(), this->extension.c_str());
if (!sanitized_path) throw fmt::format("Failed to generate sanitized file path.");
/* Update output. */
output = std::string(sanitized_path);
/* Free sanitized path. */
free(sanitized_path);
return output;
}
}

View File

@ -26,7 +26,8 @@ using namespace i18n::literals; /* For _i18n. */
namespace nxdt::views
{
GameCardImageDumpOptionsFrame::GameCardImageDumpOptionsFrame(RootView *root_view, std::string title, std::string raw_filename) : DumpOptionsFrame(root_view, title, raw_filename, ".xci")
GameCardImageDumpOptionsFrame::GameCardImageDumpOptionsFrame(RootView *root_view, std::string raw_filename) :
DumpOptionsFrame(root_view, "gamecard_tab/list/dump_card_image/label"_i18n, std::string(GAMECARD_SUBDIR), raw_filename, std::string(".xci"))
{
/* Prepend KeyArea data. */
this->prepend_key_area = new brls::ToggleListItem("dump_options/prepend_key_area/label"_i18n, configGetBoolean("gamecard/prepend_key_area"), "dump_options/prepend_key_area/description"_i18n,
@ -116,10 +117,11 @@ namespace nxdt::views
/* Register dump button callback. */
this->RegisterButtonListener([this](brls::View *view) {
/* Retrieve configuration values set by the user. */
//bool prepend_key_area = this->prepend_key_area_item->getToggleState();
//bool keep_certificate = this->keep_certificate_item->getToggleState();
//bool prepend_key_area_val = this->prepend_key_area->getToggleState();
//bool keep_certificate_val = this->keep_certificate->getToggleState();
bool trim_dump_val = this->trim_dump->getToggleState();
//bool calculate_checksum = this->calculate_checksum_item->getToggleState();
//bool calculate_checksum_val = this->calculate_checksum->getToggleState();
//int checksum_lookup_method_val = static_cast<int>(this->checksum_lookup_method->getSelectedValue());
/* Get gamecard size. */
u64 gc_size = 0;
@ -132,6 +134,11 @@ namespace nxdt::views
/* Display update frame. */
//brls::Application::pushView(new OptionsTabUpdateApplicationFrame(), brls::ViewAnimation::SLIDE_LEFT, false);
brls::Application::notify(fmt::format("0x{:X}", gc_size));
LOG_MSG_DEBUG("Output file path: %s", this->GetOutputFilePath().c_str());
});
}
}

View File

@ -257,7 +257,7 @@ namespace nxdt::views
dump_card_image->getClickEvent()->subscribe([this](brls::View *view) {
std::string& raw_filename = (configGetInteger("naming_convention") == TitleNamingConvention_Full ? raw_filename_full : raw_filename_id_only);
brls::Application::pushView(new GameCardImageDumpOptionsFrame(this->root_view, "gamecard_tab/list/dump_card_image/label"_i18n, raw_filename), brls::ViewAnimation::SLIDE_LEFT);
brls::Application::pushView(new GameCardImageDumpOptionsFrame(this->root_view, raw_filename), brls::ViewAnimation::SLIDE_LEFT);
});
this->list->addView(dump_card_image);