From 91636d674122295a951c031c8122f138f455cc3f Mon Sep 17 00:00:00 2001 From: Steven Smith Date: Thu, 28 Apr 2016 18:01:51 -0700 Subject: [PATCH] Further cleanup. --- romfs/textcolor.cfg | 1 + source/core/linkedlist.c | 29 +- source/core/linkedlist.h | 2 +- source/core/screen.c | 2 + source/core/screen.h | 5 +- source/core/util.c | 328 +----------------- source/core/util.h | 25 +- source/ui/error.c | 17 + source/ui/error.h | 9 + source/ui/section/action/action.h | 31 +- .../ui/section/action/browsebossextsavedata.c | 4 +- .../ui/section/action/browsesystemsavedata.c | 4 +- .../ui/section/action/browsetitlesavedata.c | 4 +- .../ui/section/action/browseuserextsavedata.c | 4 +- source/ui/section/action/clipboard.c | 41 +-- source/ui/section/action/clipboard.h | 6 +- source/ui/section/action/copycontents.c | 29 -- source/ui/section/action/deletecontents.c | 152 ++++---- .../ui/section/action/deletependingtitles.c | 100 ++++-- source/ui/section/action/exportsecurevalue.c | 8 +- source/ui/section/action/extractsmdh.c | 55 +-- source/ui/section/action/importsecurevalue.c | 3 +- source/ui/section/action/installcdn.c | 56 ++- source/ui/section/action/installcias.c | 185 +++++----- source/ui/section/action/installtickets.c | 183 +++++----- source/ui/section/action/pastefiles.c | 209 ++++++----- source/ui/section/dumpnand.c | 61 ++-- source/ui/section/extsavedata.c | 34 +- source/ui/section/files.c | 241 +++++++------ source/ui/section/networkinstall.c | 22 +- source/ui/section/pendingtitles.c | 34 +- source/ui/section/qrinstall.c | 84 ++--- source/ui/section/section.h | 2 +- source/ui/section/systemsavedata.c | 34 +- source/ui/section/task/capturecam.c | 78 ++--- source/ui/section/task/dataop.c | 124 +++---- source/ui/section/task/listextsavedata.c | 92 ++--- source/ui/section/task/listfiles.c | 241 +++++++------ source/ui/section/task/listpendingtitles.c | 63 ++-- source/ui/section/task/listsystemsavedata.c | 62 ++-- source/ui/section/task/listtickets.c | 62 ++-- source/ui/section/task/listtitles.c | 198 ++++++----- source/ui/section/task/task.h | 111 ++++-- source/ui/section/tickets.c | 34 +- source/ui/section/titles.c | 34 +- 45 files changed, 1513 insertions(+), 1590 deletions(-) delete mode 100644 source/ui/section/action/copycontents.c diff --git a/romfs/textcolor.cfg b/romfs/textcolor.cfg index 2a22c04..78cbb17 100644 --- a/romfs/textcolor.cfg +++ b/romfs/textcolor.cfg @@ -3,4 +3,5 @@ nand=FF0000FF sd=FF00FF00 gamecard=FFFF0000 dstitle=FF82004B +file=FF000000 directory=FF0000FF \ No newline at end of file diff --git a/source/core/linkedlist.c b/source/core/linkedlist.c index 9fdb3e5..99d0f1a 100644 --- a/source/core/linkedlist.c +++ b/source/core/linkedlist.c @@ -186,23 +186,27 @@ bool linked_list_remove_at(linked_list* list, unsigned int index) { return true; } -void linked_list_sort(linked_list* list, int (*compare)(const void* p1, const void* p2)) { +void linked_list_sort(linked_list* list, int (*compare)(const void** p1, const void** p2)) { unsigned int count = list->size; - void* elements[count]; - unsigned int i = 0; - linked_list_node* node = list->first; - while(node != NULL && i < count) { - elements[i++] = node->value; - node = node->next; - } + void** elements = (void**) calloc(count, sizeof(void*)); + if(elements != NULL) { + unsigned int num = 0; + linked_list_node* node = list->first; + while(node != NULL && num < count) { + elements[num++] = node->value; + node = node->next; + } - linked_list_clear(list); + linked_list_clear(list); - qsort(elements, count, sizeof(void*), compare); + qsort(elements, num, sizeof(void*), (int (*)(const void* p1, const void* p2)) compare); - for(unsigned int index = 0; index < count; index++) { - linked_list_add(list, elements[index]); + for(unsigned int i = 0; i < num; i++) { + linked_list_add(list, elements[i]); + } + + free(elements); } } @@ -240,4 +244,5 @@ void linked_list_iter_remove(linked_list_iter* iter) { } linked_list_remove_node(iter->list, iter->curr); + iter->curr = NULL; } \ No newline at end of file diff --git a/source/core/linkedlist.h b/source/core/linkedlist.h index fc1ce22..930b925 100644 --- a/source/core/linkedlist.h +++ b/source/core/linkedlist.h @@ -31,7 +31,7 @@ bool linked_list_add(linked_list* list, void* value); bool linked_list_add_at(linked_list* list, unsigned int index, void* value); bool linked_list_remove(linked_list* list, void* value); bool linked_list_remove_at(linked_list* list, unsigned int index); -void linked_list_sort(linked_list* list, int (*compare)(const void* p1, const void* p2)); +void linked_list_sort(linked_list* list, int (*compare)(const void** p1, const void** p2)); void linked_list_iterate(linked_list* list, linked_list_iter* iter); diff --git a/source/core/screen.c b/source/core/screen.c index 75f8c00..2db01ce 100644 --- a/source/core/screen.c +++ b/source/core/screen.c @@ -199,6 +199,8 @@ void screen_init() { colorConfig[COLOR_GAME_CARD] = color; } else if(strcasecmp(key, "dstitle") == 0) { colorConfig[COLOR_DS_TITLE] = color; + } else if(strcasecmp(key, "file") == 0) { + colorConfig[COLOR_FILE] = color; } else if(strcasecmp(key, "directory") == 0) { colorConfig[COLOR_DIRECTORY] = color; } diff --git a/source/core/screen.h b/source/core/screen.h index 4147c22..1cdda1c 100644 --- a/source/core/screen.h +++ b/source/core/screen.h @@ -41,14 +41,15 @@ #define TEXTURE_WIFI_3 30 #define TEXTURE_AUTO_START 31 -#define NUM_COLORS 6 +#define NUM_COLORS 7 #define COLOR_TEXT 0 #define COLOR_NAND 1 #define COLOR_SD 2 #define COLOR_GAME_CARD 3 #define COLOR_DS_TITLE 4 -#define COLOR_DIRECTORY 5 +#define COLOR_FILE 5 +#define COLOR_DIRECTORY 6 void screen_init(); void screen_exit(); diff --git a/source/core/util.c b/source/core/util.c index 3b3dc84..b2d7d27 100644 --- a/source/core/util.c +++ b/source/core/util.c @@ -6,6 +6,7 @@ #include <3ds.h> #include "util.h" +#include "../ui/error.h" #include "../ui/section/task/task.h" extern void cleanup(); @@ -152,33 +153,18 @@ void util_free_path_utf8(FS_Path* path) { free(path); } -bool util_exists(FS_Archive* archive, const char* path) { - bool exists = false; - - FS_Path* fsPath = util_make_path_utf8(path); - if(path != NULL) { - Handle handle = 0; - if(R_SUCCEEDED(FSUSER_OpenFile(&handle, *archive, *fsPath, FS_OPEN_READ, 0))) { - FSFILE_Close(handle); - exists = true; - } else if(R_SUCCEEDED(FSUSER_OpenDirectory(&handle, *archive, *fsPath))) { - FSDIR_Close(handle); - exists = true; - } - - util_free_path_utf8(fsPath); - } - - return exists; +FS_Path util_make_binary_path(const void* data, u32 size) { + FS_Path path = {PATH_BINARY, size, data}; + return path; } -bool util_is_dir(FS_Archive* archive, const char* path) { +bool util_is_dir(FS_Archive archive, const char* path) { Result res = 0; FS_Path* fsPath = util_make_path_utf8(path); if(fsPath != NULL) { Handle dirHandle = 0; - if(R_SUCCEEDED(res = FSUSER_OpenDirectory(&dirHandle, *archive, *fsPath))) { + if(R_SUCCEEDED(res = FSUSER_OpenDirectory(&dirHandle, archive, *fsPath))) { FSDIR_Close(dirHandle); } @@ -190,19 +176,22 @@ bool util_is_dir(FS_Archive* archive, const char* path) { return R_SUCCEEDED(res); } -Result util_ensure_dir(FS_Archive* archive, const char* path) { +Result util_ensure_dir(FS_Archive archive, const char* path) { Result res = 0; - if(!util_is_dir(archive, path)) { - FS_Path* fsPath = util_make_path_utf8(path); - if(fsPath != NULL) { - FSUSER_DeleteFile(*archive, *fsPath); - res = FSUSER_CreateDirectory(*archive, *fsPath, 0); - - util_free_path_utf8(fsPath); + FS_Path* fsPath = util_make_path_utf8(path); + if(fsPath != NULL) { + Handle dirHandle = 0; + if(R_SUCCEEDED(FSUSER_OpenDirectory(&dirHandle, archive, *fsPath))) { + FSDIR_Close(dirHandle); } else { - res = R_FBI_OUT_OF_MEMORY; + FSUSER_DeleteFile(archive, *fsPath); + res = FSUSER_CreateDirectory(archive, *fsPath, 0); } + + util_free_path_utf8(fsPath); + } else { + res = R_FBI_OUT_OF_MEMORY; } return res; @@ -245,285 +234,4 @@ void util_get_parent_path(char* out, const char* path, u32 size) { u32 terminatorPos = end - path + 1 < size - 1 ? end - path + 1 : size - 1; strncpy(out, path, terminatorPos); out[terminatorPos] = '\0'; -} - -bool util_filter_dirs(void* data, FS_Archive* archive, const char* path, u32 attributes) { - return (bool) (attributes & FS_ATTRIBUTE_DIRECTORY); -} - -bool util_filter_files(void* data, FS_Archive* archive, const char* path, u32 attributes) { - return !(attributes & FS_ATTRIBUTE_DIRECTORY); -} - -bool util_filter_hidden(void* data, FS_Archive* archive, const char* path, u32 attributes) { - return !(attributes & FS_ATTRIBUTE_HIDDEN); -} - -bool util_filter_file_extension(void* data, FS_Archive* archive, const char* path, u32 attributes) { - if(data == NULL) { - return true; - } - - char* extension = (char*) data; - size_t extensionLen = strlen(extension); - - size_t len = strlen(path); - return util_filter_files(data, archive, path, attributes) && len >= extensionLen && strcmp(path + len - extensionLen, extension) == 0; -} - -bool util_filter_not_path(void* data, FS_Archive* archive, const char* path, u32 attributes) { - if(data == NULL) { - return true; - } - - return strcmp(path, (char*) data) != 0; -} - -static Result util_traverse_dir_internal(FS_Archive* archive, const char* path, bool recursive, bool dirsFirst, void* data, bool (*filter)(void* data, FS_Archive* archive, const char* path, u32 attributes), - void (*process)(void* data, FS_Archive* archive, const char* path, u32 attributes)) { - Result res = 0; - - FS_Path* fsPath = util_make_path_utf8(path); - if(fsPath != NULL) { - Handle handle = 0; - if(R_SUCCEEDED(res = FSUSER_OpenDirectory(&handle, *archive, *fsPath))) { - size_t pathLen = strlen(path); - char* pathBuf = (char*) calloc(1, FILE_PATH_MAX); - if(pathBuf != NULL) { - strncpy(pathBuf, path, FILE_PATH_MAX); - - u32 entryCount = 0; - FS_DirectoryEntry entry; - u32 done = 0; - while(R_SUCCEEDED(FSDIR_Read(handle, &entryCount, 1, &entry)) && entryCount > 0) { - ssize_t units = utf16_to_utf8((uint8_t*) pathBuf + pathLen, entry.name, FILE_PATH_MAX - pathLen - 1); - if(units > 0) { - pathBuf[pathLen + units] = '\0'; - if(entry.attributes & FS_ATTRIBUTE_DIRECTORY) { - if(pathLen + units < FILE_PATH_MAX - 2) { - pathBuf[pathLen + units] = '/'; - pathBuf[pathLen + units + 1] = '\0'; - } - } - - if(dirsFirst) { - if(process != NULL && (filter == NULL || filter(data, archive, pathBuf, entry.attributes))) { - process(data, archive, pathBuf, entry.attributes); - } - } - - if((entry.attributes & FS_ATTRIBUTE_DIRECTORY) && recursive) { - if(R_FAILED(res = util_traverse_dir_internal(archive, pathBuf, recursive, dirsFirst, data, filter, process))) { - break; - } - } - - if(!dirsFirst) { - if(process != NULL && (filter == NULL || filter(data, archive, pathBuf, entry.attributes))) { - process(data, archive, pathBuf, entry.attributes); - } - } - } - - done++; - } - - free(pathBuf); - } else { - res = R_FBI_OUT_OF_MEMORY; - } - - FSDIR_Close(handle); - } - - util_free_path_utf8(fsPath); - } else { - res = R_FBI_OUT_OF_MEMORY; - } - - return res; -} - -static Result util_traverse_dir(FS_Archive* archive, const char* path, bool recursive, bool dirsFirst, void* data, bool (*filter)(void* data, FS_Archive* archive, const char* path, u32 attributes), - void (*process)(void* data, FS_Archive* archive, const char* path, u32 attributes)) { - if(dirsFirst && strcmp(path, "/") != 0) { - if(process != NULL && (filter == NULL || filter(data, archive, path, FS_ATTRIBUTE_DIRECTORY))) { - process(data, archive, path, FS_ATTRIBUTE_DIRECTORY); - } - } - - Result res = util_traverse_dir_internal(archive, path, recursive, dirsFirst, data, filter, process); - - if(!dirsFirst && strcmp(path, "/") != 0) { - if(process != NULL && (filter == NULL || filter(data, archive, path, FS_ATTRIBUTE_DIRECTORY))) { - process(data, archive, path, FS_ATTRIBUTE_DIRECTORY); - } - } - - return res; -} - -static Result util_traverse_file(FS_Archive* archive, const char* path, bool recursive, bool dirsFirst, void* data, bool (*filter)(void* data, FS_Archive* archive, const char* path, u32 attributes), - void (*process)(void* data, FS_Archive* archive, const char* path, u32 attributes)) { - Result res = 0; - - FS_Path* fsPath = util_make_path_utf8(path); - if(fsPath != NULL) { - Handle handle = 0; - if(R_SUCCEEDED(res = FSUSER_OpenFile(&handle, *archive, *fsPath, FS_OPEN_READ, 0))) { - if(process != NULL && (filter == NULL || filter(data, archive, path, 0))) { - process(data, archive, path, 0); - } - - FSFILE_Close(handle); - } - - util_free_path_utf8(fsPath); - } else { - res = R_FBI_OUT_OF_MEMORY; - } - - return res; -} - -Result util_traverse_contents(FS_Archive* archive, const char* path, bool recursive, bool dirsFirst, void* data, bool (*filter)(void* data, FS_Archive* archive, const char* path, u32 attributes), - void (*process)(void* data, FS_Archive* archive, const char* path, u32 attributes)) { - Result res = 0; - - if(util_is_dir(archive, path)) { - res = util_traverse_dir(archive, path, recursive, dirsFirst, data, filter, process); - } else { - res = util_traverse_file(archive, path, recursive, dirsFirst, data, filter, process); - } - - return res; -} - -typedef struct { - u32* count; - void* data; - bool (*filter)(void* data, FS_Archive* archive, const char* path, u32 attributes); -} count_data; - -static bool util_count_contents_filter(void* data, FS_Archive* archive, const char* path, u32 attributes) { - count_data* countData = (count_data*) data; - if(countData->filter != NULL) { - return countData->filter(countData->data, archive, path, attributes); - } - - return true; -} - -static void util_count_contents_process(void* data, FS_Archive* archive, const char* path, u32 attributes) { - (*((count_data*) data)->count)++; -} - -Result util_count_contents(u32* out, FS_Archive* archive, const char* path, bool recursive, bool dirsFirst, void* data, bool (*filter)(void* data, FS_Archive* archive, const char* path, u32 attributes)) { - if(out == NULL) { - return 0; - } - - count_data countData; - countData.count = out; - countData.data = data; - countData.filter = filter; - return util_traverse_contents(archive, path, recursive, dirsFirst, &countData, util_count_contents_filter, util_count_contents_process); -} - -typedef struct { - char*** contents; - u32 index; - void* data; - bool (*filter)(void* data, FS_Archive* archive, const char* path, u32 attributes); -} populate_data; - -static bool util_populate_contents_filter(void* data, FS_Archive* archive, const char* path, u32 attributes) { - populate_data* populateData = (populate_data*) data; - if(populateData->filter != NULL) { - return populateData->filter(populateData->data, archive, path, attributes); - } - - return true; -} - -static void util_populate_contents_process(void* data, FS_Archive* archive, const char* path, u32 attributes) { - u32 currPathSize = strlen(path) + 1; - char* currPath = (char*) calloc(1, currPathSize); - if(currPath == NULL) { - return; - } - - strncpy(currPath, path, currPathSize); - - populate_data* populateData = (populate_data*) data; - (*populateData->contents)[populateData->index++] = currPath; -} - -Result util_populate_contents(char*** contentsOut, u32* countOut, FS_Archive* archive, const char* path, bool recursive, bool dirsFirst, void* data, bool (*filter)(void* data, FS_Archive* archive, const char* path, u32 attributes)) { - if(contentsOut == NULL || countOut == NULL) { - return 0; - } - - util_count_contents(countOut, archive, path, recursive, dirsFirst, data, filter); - *contentsOut = (char**) calloc(*countOut, sizeof(char*)); - - if(*contentsOut == NULL) { - return R_FBI_OUT_OF_MEMORY; - } - - populate_data populateData; - populateData.contents = contentsOut; - populateData.index = 0; - populateData.data = data; - populateData.filter = filter; - - Result res = util_traverse_contents(archive, path, recursive, dirsFirst, &populateData, util_populate_contents_filter, util_populate_contents_process); - if(R_FAILED(res)) { - util_free_contents(*contentsOut, *countOut); - } - - return res; -} - -void util_free_contents(char** contents, u32 count) { - for(u32 i = 0; i < count; i++) { - if(contents[i] != NULL) { - free(contents[i]); - } - } - - free(contents); -} - -int util_compare_u32(const void* e1, const void* e2) { - u32 id1 = *(u32*) e1; - u32 id2 = *(u32*) e2; - - return id1 > id2 ? 1 : id1 < id2 ? -1 : 0; -} - -int util_compare_u64(const void* e1, const void* e2) { - u64 id1 = *(u64*) e1; - u64 id2 = *(u64*) e2; - - return id1 > id2 ? 1 : id1 < id2 ? -1 : 0; -} - -int util_compare_directory_entries(const void* e1, const void* e2) { - FS_DirectoryEntry* ent1 = (FS_DirectoryEntry*) e1; - FS_DirectoryEntry* ent2 = (FS_DirectoryEntry*) e2; - - if((ent1->attributes & FS_ATTRIBUTE_DIRECTORY) && !(ent2->attributes & FS_ATTRIBUTE_DIRECTORY)) { - return -1; - } else if(!(ent1->attributes & FS_ATTRIBUTE_DIRECTORY) && (ent2->attributes & FS_ATTRIBUTE_DIRECTORY)) { - return 1; - } else { - char entryName1[0x213] = {'\0'}; - utf16_to_utf8((uint8_t*) entryName1, ent1->name, sizeof(entryName1) - 1); - - char entryName2[0x213] = {'\0'}; - utf16_to_utf8((uint8_t*) entryName2, ent2->name, sizeof(entryName2) - 1); - - return strcasecmp(entryName1, entryName2); - } } \ No newline at end of file diff --git a/source/core/util.h b/source/core/util.h index 1a5077c..d0219da 100644 --- a/source/core/util.h +++ b/source/core/util.h @@ -43,25 +43,10 @@ void util_panic(const char* s, ...); FS_Path* util_make_path_utf8(const char* path); void util_free_path_utf8(FS_Path* path); -bool util_exists(FS_Archive* archive, const char* path); -bool util_is_dir(FS_Archive* archive, const char* path); -Result util_ensure_dir(FS_Archive* archive, const char* path); +FS_Path util_make_binary_path(const void* data, u32 size); + +bool util_is_dir(FS_Archive archive, const char* path); +Result util_ensure_dir(FS_Archive archive, const char* path); void util_get_path_file(char* out, const char* path, u32 size); -void util_get_parent_path(char* out, const char* path, u32 size); - -bool util_filter_dirs(void* data, FS_Archive* archive, const char* path, u32 attributes); -bool util_filter_files(void* data, FS_Archive* archive, const char* path, u32 attributes); -bool util_filter_hidden(void* data, FS_Archive* archive, const char* path, u32 attributes); -bool util_filter_file_extension(void* data, FS_Archive* archive, const char* path, u32 attributes); -bool util_filter_not_path(void* data, FS_Archive* archive, const char* path, u32 attributes); - -Result util_traverse_contents(FS_Archive* archive, const char* path, bool recursive, bool dirsFirst, void* data, bool (*filter)(void* data, FS_Archive* archive, const char* path, u32 attributes), - void (*process)(void* data, FS_Archive* archive, const char* path, u32 attributes)); -Result util_count_contents(u32* out, FS_Archive* archive, const char* path, bool recursive, bool dirsFirst, void* data, bool (*filter)(void* data, FS_Archive* archive, const char* path, u32 attributes)); -Result util_populate_contents(char*** contentsOut, u32* countOut, FS_Archive* archive, const char* path, bool recursive, bool dirsFirst, void* data, bool (*filter)(void* data, FS_Archive* archive, const char* path, u32 attributes)); -void util_free_contents(char** contents, u32 count); - -int util_compare_u32(const void* e1, const void* e2); -int util_compare_u64(const void* e1, const void* e2); -int util_compare_directory_entries(const void* e1, const void* e2); \ No newline at end of file +void util_get_parent_path(char* out, const char* path, u32 size); \ No newline at end of file diff --git a/source/ui/error.c b/source/ui/error.c index 72990f6..a16624a 100644 --- a/source/ui/error.c +++ b/source/ui/error.c @@ -482,6 +482,23 @@ static const char* description_to_string(Result res) { } break; + case RM_APPLICATION: + switch(res) { + case R_FBI_CANCELLED: + return "Operation cancelled"; + case R_FBI_ERRNO: + return "I/O error"; + case R_FBI_HTTP_RESPONSE_CODE: + return "HTTP request returned error"; + case R_FBI_WRONG_SYSTEM: + return "Attempted to install an N3DS title on an O3DS"; + case R_FBI_INVALID_ARGUMENT: + return "Invalid argument"; + case R_FBI_THREAD_CREATE_FAILED: + return "Thread creation failed"; + default: + break; + } default: break; } diff --git a/source/ui/error.h b/source/ui/error.h index 2227ff5..900e546 100644 --- a/source/ui/error.h +++ b/source/ui/error.h @@ -1,5 +1,14 @@ #pragma once +#define R_FBI_CANCELLED MAKERESULT(RL_PERMANENT, RS_CANCELED, RM_APPLICATION, 1) +#define R_FBI_ERRNO MAKERESULT(RL_PERMANENT, RS_INTERNAL, RM_APPLICATION, 2) +#define R_FBI_HTTP_RESPONSE_CODE MAKERESULT(RL_PERMANENT, RS_INTERNAL, RM_APPLICATION, 3) +#define R_FBI_WRONG_SYSTEM MAKERESULT(RL_PERMANENT, RS_NOTSUPPORTED, RM_APPLICATION, 4) +#define R_FBI_INVALID_ARGUMENT MAKERESULT(RL_PERMANENT, RS_INVALIDARG, RM_APPLICATION, 5) +#define R_FBI_THREAD_CREATE_FAILED MAKERESULT(RL_PERMANENT, RS_INTERNAL, RM_APPLICATION, 6) + +#define R_FBI_OUT_OF_MEMORY MAKERESULT(RL_FATAL, RS_OUTOFRESOURCE, RM_APPLICATION, RD_OUT_OF_MEMORY) + typedef struct ui_view_s ui_view; void error_display(volatile bool* dismissed, void* data, void (*drawTop)(ui_view* view, void* data, float x1, float y1, float x2, float y2), const char* text, ...); diff --git a/source/ui/section/action/action.h b/source/ui/section/action/action.h index a4ce259..7869e08 100644 --- a/source/ui/section/action/action.h +++ b/source/ui/section/action/action.h @@ -1,6 +1,5 @@ #pragma once -typedef struct file_info_s file_info; typedef struct linked_list_s linked_list; typedef struct list_item_s list_item; @@ -11,22 +10,20 @@ void action_delete_ext_save_data(linked_list* items, list_item* selected); void action_browse_system_save_data(linked_list* items, list_item* selected); void action_delete_system_save_data(linked_list* items, list_item* selected); -void action_install_cia(linked_list* items, list_item* selected, file_info* target); -void action_install_cia_delete(linked_list* items, list_item* selected, file_info* target); -void action_install_cias(linked_list* items, list_item* selected, file_info* target); -void action_install_cias_delete(linked_list* items, list_item* selected, file_info* target); -void action_install_ticket(linked_list* items, list_item* selected, file_info* target); -void action_install_ticket_delete(linked_list* items, list_item* selected, file_info* target); -void action_install_tickets(linked_list* items, list_item* selected, file_info* target); -void action_install_tickets_delete(linked_list* items, list_item* selected, file_info* target); -void action_copy_content(linked_list* items, list_item* selected, file_info* target); -void action_copy_contents(linked_list* items, list_item* selected, file_info* target); -void action_delete_contents(linked_list* items, list_item* selected, file_info* target); -void action_delete_dir(linked_list* items, list_item* selected, file_info* target); -void action_delete_dir_contents(linked_list* items, list_item* selected, file_info* target); -void action_delete_dir_cias(linked_list* items, list_item* selected, file_info* target); -void action_delete_dir_tickets(linked_list* items, list_item* selected, file_info* target); -void action_paste_contents(linked_list* items, list_item* selected, file_info* target); +void action_install_cia(linked_list* items, list_item* selected); +void action_install_cia_delete(linked_list* items, list_item* selected); +void action_install_cias(linked_list* items, list_item* selected); +void action_install_cias_delete(linked_list* items, list_item* selected); +void action_install_ticket(linked_list* items, list_item* selected); +void action_install_ticket_delete(linked_list* items, list_item* selected); +void action_install_tickets(linked_list* items, list_item* selected); +void action_install_tickets_delete(linked_list* items, list_item* selected); +void action_delete_file(linked_list* items, list_item* selected); +void action_delete_dir(linked_list* items, list_item* selected); +void action_delete_dir_contents(linked_list* items, list_item* selected); +void action_delete_dir_cias(linked_list* items, list_item* selected); +void action_delete_dir_tickets(linked_list* items, list_item* selected); +void action_paste_contents(linked_list* items, list_item* selected); void action_delete_pending_title(linked_list* items, list_item* selected); void action_delete_all_pending_titles(linked_list* items, list_item* selected); diff --git a/source/ui/section/action/browsebossextsavedata.c b/source/ui/section/action/browsebossextsavedata.c index 248f2a8..a78e6aa 100644 --- a/source/ui/section/action/browsebossextsavedata.c +++ b/source/ui/section/action/browsebossextsavedata.c @@ -4,11 +4,11 @@ #include "../section.h" #include "../task/task.h" #include "../../list.h" +#include "../../../core/util.h" void action_browse_boss_ext_save_data(linked_list* items, list_item* selected) { ext_save_data_info* info = (ext_save_data_info*) selected->data; u32 path[3] = {info->mediaType, (u32) (info->extSaveDataId & 0xFFFFFFFF), (u32) ((info->extSaveDataId >> 32) & 0xFFFFFFFF)}; - FS_Archive archive = {ARCHIVE_BOSS_EXTDATA, {PATH_BINARY, 12, path}}; - files_open(archive); + files_open(ARCHIVE_BOSS_EXTDATA, util_make_binary_path(path, sizeof(path))); } \ No newline at end of file diff --git a/source/ui/section/action/browsesystemsavedata.c b/source/ui/section/action/browsesystemsavedata.c index 84a3e8f..4010f57 100644 --- a/source/ui/section/action/browsesystemsavedata.c +++ b/source/ui/section/action/browsesystemsavedata.c @@ -4,11 +4,11 @@ #include "../section.h" #include "../task/task.h" #include "../../list.h" +#include "../../../core/util.h" void action_browse_system_save_data(linked_list* items, list_item* selected) { system_save_data_info* info = (system_save_data_info*) selected->data; u32 path[2] = {MEDIATYPE_NAND, info->systemSaveDataId}; - FS_Archive archive = {ARCHIVE_SYSTEM_SAVEDATA, {PATH_BINARY, 8, path}}; - files_open(archive); + files_open(ARCHIVE_SYSTEM_SAVEDATA, util_make_binary_path(path, sizeof(path))); } \ No newline at end of file diff --git a/source/ui/section/action/browsetitlesavedata.c b/source/ui/section/action/browsetitlesavedata.c index 7928575..c2cc7eb 100644 --- a/source/ui/section/action/browsetitlesavedata.c +++ b/source/ui/section/action/browsetitlesavedata.c @@ -4,11 +4,11 @@ #include "../section.h" #include "../task/task.h" #include "../../list.h" +#include "../../../core/util.h" void action_browse_title_save_data(linked_list* items, list_item* selected) { title_info* info = (title_info*) selected->data; u32 path[3] = {info->mediaType, (u32) (info->titleId & 0xFFFFFFFF), (u32) ((info->titleId >> 32) & 0xFFFFFFFF)}; - FS_Archive archive = {ARCHIVE_USER_SAVEDATA, {PATH_BINARY, 12, path}}; - files_open(archive); + files_open(ARCHIVE_USER_SAVEDATA, util_make_binary_path(path, sizeof(path))); } \ No newline at end of file diff --git a/source/ui/section/action/browseuserextsavedata.c b/source/ui/section/action/browseuserextsavedata.c index cc94b46..6e1d842 100644 --- a/source/ui/section/action/browseuserextsavedata.c +++ b/source/ui/section/action/browseuserextsavedata.c @@ -4,11 +4,11 @@ #include "../section.h" #include "../task/task.h" #include "../../list.h" +#include "../../../core/util.h" void action_browse_user_ext_save_data(linked_list* items, list_item* selected) { ext_save_data_info* info = (ext_save_data_info*) selected->data; u32 path[3] = {info->mediaType, (u32) (info->extSaveDataId & 0xFFFFFFFF), (u32) ((info->extSaveDataId >> 32) & 0xFFFFFFFF)}; - FS_Archive archive = {info->shared ? ARCHIVE_SHARED_EXTDATA : ARCHIVE_EXTDATA, {PATH_BINARY, 12, path}}; - files_open(archive); + files_open(info->shared ? ARCHIVE_SHARED_EXTDATA : ARCHIVE_EXTDATA, util_make_binary_path(path, sizeof(path))); } \ No newline at end of file diff --git a/source/ui/section/action/clipboard.c b/source/ui/section/action/clipboard.c index 35fcba1..d501404 100644 --- a/source/ui/section/action/clipboard.c +++ b/source/ui/section/action/clipboard.c @@ -8,16 +8,16 @@ static bool clipboard_has = false; static bool clipboard_contents_only; + static FS_Archive clipboard_archive; -static void* clipboard_archive_path; static char clipboard_path[FILE_PATH_MAX]; bool clipboard_has_contents() { return clipboard_has; } -FS_Archive* clipboard_get_archive() { - return &clipboard_archive; +FS_Archive clipboard_get_archive() { + return clipboard_archive; } char* clipboard_get_path() { @@ -28,41 +28,30 @@ bool clipboard_is_contents_only() { return clipboard_contents_only; } -Result clipboard_set_contents(FS_Archive archive, const char* path, bool contentsOnly) { +Result clipboard_set_contents(FS_ArchiveID archiveId, FS_Path* archivePath, const char* path, bool contentsOnly) { clipboard_clear(); clipboard_has = true; clipboard_contents_only = contentsOnly; - clipboard_archive = archive; + strncpy(clipboard_path, path, FILE_PATH_MAX); - if(clipboard_archive.lowPath.size > 0) { - clipboard_archive_path = calloc(1, clipboard_archive.lowPath.size); - if(clipboard_archive_path == NULL) { - clipboard_clear(); - return R_FBI_OUT_OF_MEMORY; - } - - memcpy(clipboard_archive_path, clipboard_archive.lowPath.data, clipboard_archive.lowPath.size); - clipboard_archive.lowPath.data = clipboard_archive_path; + Result res = 0; + if(R_FAILED(res = FSUSER_OpenArchive(&clipboard_archive, archiveId, *archivePath))) { + clipboard_clear(); } - clipboard_archive.handle = 0; - return FSUSER_OpenArchive(&clipboard_archive); + return res; } void clipboard_clear() { - if(clipboard_archive.handle != 0) { - FSUSER_CloseArchive(&clipboard_archive); - clipboard_archive.handle = 0; - } - - if(clipboard_archive_path != NULL) { - free(clipboard_archive_path); - clipboard_archive_path = NULL; - } - clipboard_has = false; clipboard_contents_only = false; + memset(clipboard_path, '\0', FILE_PATH_MAX); + + if(clipboard_archive != 0) { + FSUSER_CloseArchive(clipboard_archive); + clipboard_archive = 0; + } } \ No newline at end of file diff --git a/source/ui/section/action/clipboard.h b/source/ui/section/action/clipboard.h index 7418e62..e4d009a 100644 --- a/source/ui/section/action/clipboard.h +++ b/source/ui/section/action/clipboard.h @@ -2,9 +2,11 @@ #include +typedef struct file_info_s file_info; + bool clipboard_has_contents(); -FS_Archive* clipboard_get_archive(); +FS_Archive clipboard_get_archive(); char* clipboard_get_path(); bool clipboard_is_contents_only(); -Result clipboard_set_contents(FS_Archive archive, const char* path, bool contentsOnly); +Result clipboard_set_contents(FS_ArchiveID archiveId, FS_Path* archivePath, const char* path, bool contentsOnly); void clipboard_clear(); \ No newline at end of file diff --git a/source/ui/section/action/copycontents.c b/source/ui/section/action/copycontents.c deleted file mode 100644 index f7dd4a6..0000000 --- a/source/ui/section/action/copycontents.c +++ /dev/null @@ -1,29 +0,0 @@ -#include <3ds.h> - -#include "action.h" -#include "clipboard.h" -#include "../task/task.h" -#include "../../error.h" -#include "../../list.h" -#include "../../prompt.h" -#include "../../ui.h" -#include "../../../core/screen.h" - -static void action_copy_contents_internal(linked_list* items, list_item* selected, file_info* target, const char* message, bool contentsOnly) { - Result res = 0; - if(R_FAILED(res = clipboard_set_contents(*target->archive, target->path, contentsOnly))) { - error_display_res(NULL, target, ui_draw_file_info, res, "Failed to copy to clipboard."); - - return; - } - - prompt_display("Success", message, COLOR_TEXT, false, target, NULL, ui_draw_file_info, NULL); -} - -void action_copy_content(linked_list* items, list_item* selected, file_info* target) { - action_copy_contents_internal(items, selected, target, "Selected content copied to clipboard.", false); -} - -void action_copy_contents(linked_list* items, list_item* selected, file_info* target) { - action_copy_contents_internal(items, selected, target, "Directory contents copied to clipboard.", true); -} \ No newline at end of file diff --git a/source/ui/section/action/deletecontents.c b/source/ui/section/action/deletecontents.c index 1edbd03..5d1fe72 100644 --- a/source/ui/section/action/deletecontents.c +++ b/source/ui/section/action/deletecontents.c @@ -19,30 +19,35 @@ typedef struct { linked_list* items; file_info* target; - char** contents; - list_item* curr; + linked_list contents; - data_op_info deleteInfo; - Handle cancelEvent; + data_op_data deleteInfo; } delete_contents_data; +static void action_delete_contents_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { + delete_contents_data* deleteData = (delete_contents_data*) data; + + u32 curr = deleteData->deleteInfo.processed; + if(curr < deleteData->deleteInfo.total) { + ui_draw_file_info(view, ((list_item*) linked_list_get(&deleteData->contents, curr))->data, x1, y1, x2, y2); + } else if(deleteData->target != NULL) { + ui_draw_file_info(view, deleteData->target, x1, y1, x2, y2); + } +} + static Result action_delete_contents_delete(void* data, u32 index) { delete_contents_data* deleteData = (delete_contents_data*) data; - list_item* old = deleteData->curr; - task_create_file_item(&deleteData->curr, deleteData->target->archive, deleteData->contents[index]); - if(old != NULL) { - task_free_file(old); - } - Result res = 0; - FS_Path* fsPath = util_make_path_utf8(deleteData->contents[index]); + file_info* info = (file_info*) ((list_item*) linked_list_get(&deleteData->contents, index))->data; + + FS_Path* fsPath = util_make_path_utf8(info->path); if(fsPath != NULL) { - if(util_is_dir(deleteData->target->archive, deleteData->contents[index])) { - res = FSUSER_DeleteDirectory(*deleteData->target->archive, *fsPath); + if(util_is_dir(deleteData->target->archive, info->path)) { + res = FSUSER_DeleteDirectory(deleteData->target->archive, *fsPath); } else { - res = FSUSER_DeleteFile(*deleteData->target->archive, *fsPath); + res = FSUSER_DeleteFile(deleteData->target->archive, *fsPath); } util_free_path_utf8(fsPath); @@ -51,6 +56,9 @@ static Result action_delete_contents_delete(void* data, u32 index) { } if(R_SUCCEEDED(res)) { + deleteData->target->containsCias = false; + deleteData->target->containsTickets = false; + linked_list_iter iter; linked_list_iterate(deleteData->items, &iter); @@ -58,9 +66,13 @@ static Result action_delete_contents_delete(void* data, u32 index) { list_item* item = (list_item*) linked_list_iter_next(&iter); file_info* currInfo = (file_info*) item->data; - if(strcmp(currInfo->path, deleteData->contents[index]) == 0) { + if(strncmp(currInfo->path, info->path, FILE_PATH_MAX) == 0) { linked_list_iter_remove(&iter); - break; + task_free_file(item); + } else if(currInfo->isCia) { + deleteData->target->containsCias = true; + } else if(currInfo->isTicket) { + deleteData->target->containsTickets = true; } } } @@ -72,11 +84,11 @@ static bool action_delete_contents_error(void* data, u32 index, Result res) { delete_contents_data* deleteData = (delete_contents_data*) data; if(res == R_FBI_CANCELLED) { - prompt_display("Failure", "Delete cancelled.", COLOR_TEXT, false, deleteData->target, NULL, ui_draw_file_info, NULL); + prompt_display("Failure", "Delete cancelled.", COLOR_TEXT, false, NULL, NULL, NULL, NULL); return false; } else { volatile bool dismissed = false; - error_display_res(&dismissed, deleteData->curr != NULL ? deleteData->curr->data : deleteData->target, ui_draw_file_info, res, "Failed to delete content."); + error_display_res(&dismissed, data, action_delete_contents_draw_top, res, "Failed to delete content."); while(!dismissed) { svcSleepThread(1000000); @@ -86,23 +98,9 @@ static bool action_delete_contents_error(void* data, u32 index, Result res) { return index < deleteData->deleteInfo.total - 1; } -static void action_delete_contents_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { - delete_contents_data* deleteData = (delete_contents_data*) data; - - if(deleteData->curr != NULL) { - ui_draw_file_info(view, ((delete_contents_data*) data)->curr->data, x1, y1, x2, y2); - } else if(deleteData->target != NULL) { - ui_draw_file_info(view, ((delete_contents_data*) data)->target, x1, y1, x2, y2); - } -} - static void action_delete_contents_free_data(delete_contents_data* data) { - if(data->curr != NULL) { - task_free_file(data->curr); - data->curr = NULL; - } - - util_free_contents(data->contents, data->deleteInfo.total); + task_clear_files(&data->contents); + linked_list_destroy(&data->contents); free(data); } @@ -110,15 +108,13 @@ static void action_delete_contents_update(ui_view* view, void* data, float* prog delete_contents_data* deleteData = (delete_contents_data*) data; if(deleteData->deleteInfo.finished) { - if(deleteData->target->archive->id == ARCHIVE_USER_SAVEDATA) { - FSUSER_ControlArchive(*deleteData->target->archive, ARCHIVE_ACTION_COMMIT_SAVE_DATA, NULL, 0, NULL, 0); - } + FSUSER_ControlArchive(deleteData->target->archive, ARCHIVE_ACTION_COMMIT_SAVE_DATA, NULL, 0, NULL, 0); ui_pop(); info_destroy(view); - if(!deleteData->deleteInfo.premature) { - prompt_display("Success", "Contents deleted.", COLOR_TEXT, false, deleteData->target, NULL, ui_draw_file_info, NULL); + if(R_SUCCEEDED(deleteData->deleteInfo.result)) { + prompt_display("Success", "Contents deleted.", COLOR_TEXT, false, NULL, NULL, NULL, NULL); } action_delete_contents_free_data(deleteData); @@ -126,8 +122,8 @@ static void action_delete_contents_update(ui_view* view, void* data, float* prog return; } - if(hidKeysDown() & KEY_B) { - svcSignalEvent(deleteData->cancelEvent); + if((hidKeysDown() & KEY_B) && !deleteData->deleteInfo.finished) { + svcSignalEvent(deleteData->deleteInfo.cancelEvent); } *progress = deleteData->deleteInfo.total > 0 ? (float) deleteData->deleteInfo.processed / (float) deleteData->deleteInfo.total : 0; @@ -138,18 +134,20 @@ static void action_delete_contents_onresponse(ui_view* view, void* data, bool re delete_contents_data* deleteData = (delete_contents_data*) data; if(response) { - deleteData->cancelEvent = task_data_op(&deleteData->deleteInfo); - if(deleteData->cancelEvent != 0) { + Result res = task_data_op(&deleteData->deleteInfo); + if(R_SUCCEEDED(res)) { info_display("Deleting Contents", "Press B to cancel.", true, data, action_delete_contents_update, action_delete_contents_draw_top); } else { - error_display(NULL, NULL, NULL, "Failed to initiate delete operation."); + error_display_res(NULL, deleteData->target, ui_draw_file_info, res, "Failed to initiate delete operation."); + + action_delete_contents_free_data(deleteData); } } else { action_delete_contents_free_data(deleteData); } } -static void action_delete_contents_internal(linked_list* items, list_item* selected, file_info* target, const char* message, bool recursive, void* filterData, bool (*filter)(void* data, FS_Archive* archive, const char* path, u32 attributes)) { +static void action_delete_contents_internal(linked_list* items, list_item* selected, const char* message, bool recursive, bool includeBase, bool ciasOnly, bool ticketsOnly) { delete_contents_data* data = (delete_contents_data*) calloc(1, sizeof(delete_contents_data)); if(data == NULL) { error_display(NULL, NULL, NULL, "Failed to allocate delete contents data."); @@ -158,7 +156,7 @@ static void action_delete_contents_internal(linked_list* items, list_item* selec } data->items = items; - data->target = target; + data->target = (file_info*) selected->data; data->deleteInfo.data = data; @@ -168,35 +166,67 @@ static void action_delete_contents_internal(linked_list* items, list_item* selec data->deleteInfo.error = action_delete_contents_error; - data->cancelEvent = 0; + linked_list_init(&data->contents); - Result res = 0; - if(R_FAILED(res = util_populate_contents(&data->contents, &data->deleteInfo.total, target->archive, target->path, recursive, false, filterData, filter))) { - error_display_res(NULL, target, ui_draw_file_info, res, "Failed to retrieve content list."); + populate_files_data popData; + popData.items = &data->contents; + popData.base = data->target; + popData.recursive = recursive; + popData.includeBase = includeBase; + popData.dirsFirst = false; - free(data); + Result listRes = task_populate_files(&popData); + if(R_FAILED(listRes)) { + error_display_res(NULL, NULL, NULL, listRes, "Failed to initiate content list population."); + + action_delete_contents_free_data(data); return; } + while(!popData.finished) { + svcSleepThread(1000000); + } + + if(R_FAILED(popData.result)) { + error_display_res(NULL, NULL, NULL, popData.result, "Failed to populate content list."); + + action_delete_contents_free_data(data); + return; + } + + linked_list_iter iter; + linked_list_iterate(&data->contents, &iter); + + while(linked_list_iter_has_next(&iter)) { + file_info* info = (file_info*) ((list_item*) linked_list_iter_next(&iter))->data; + + if((ciasOnly && (info->isDirectory || !info->isCia)) || (ticketsOnly && (info->isDirectory || !info->isTicket))) { + linked_list_iter_remove(&iter); + } + } + + data->deleteInfo.total = linked_list_size(&data->contents); + data->deleteInfo.processed = data->deleteInfo.total; + prompt_display("Confirmation", message, COLOR_TEXT, true, data, NULL, action_delete_contents_draw_top, action_delete_contents_onresponse); } -void action_delete_contents(linked_list* items, list_item* selected, file_info* target) { - action_delete_contents_internal(items, selected, target, "Delete the selected content?", true, NULL, NULL); +void action_delete_file(linked_list* items, list_item* selected) { + action_delete_contents_internal(items, selected, "Delete the selected file?", false, true, false, false); } -void action_delete_dir(linked_list* items, list_item* selected, file_info* target) { - action_delete_contents_internal(items, selected, target, "Delete the current directory?", true, NULL, NULL); +void action_delete_dir(linked_list* items, list_item* selected) { + action_delete_contents_internal(items, selected, "Delete the current directory?", true, true, false, false); } -void action_delete_dir_contents(linked_list* items, list_item* selected, file_info* target) { - action_delete_contents_internal(items, selected, target, "Delete all contents of the current directory?", true, target->path, util_filter_not_path); +void action_delete_dir_contents(linked_list* items, list_item* selected) { + action_delete_contents_internal(items, selected, "Delete all contents of the current directory?", true, false, false, false); } -void action_delete_dir_cias(linked_list* items, list_item* selected, file_info* target) { - action_delete_contents_internal(items, selected, target, "Delete all CIAs in the current directory?", false, ".cia", util_filter_file_extension); +void action_delete_dir_cias(linked_list* items, list_item* selected) { + action_delete_contents_internal(items, selected, "Delete all CIAs in the current directory?", false, false, true, false); } -void action_delete_dir_tickets(linked_list* items, list_item* selected, file_info* target) { - action_delete_contents_internal(items, selected, target, "Delete all tickets in the current directory?", false, ".tik", util_filter_file_extension); +void action_delete_dir_tickets(linked_list* items, list_item* selected) { + action_delete_contents_internal(items, selected, "Delete all tickets in the current directory?", false, false, false, true); } \ No newline at end of file diff --git a/source/ui/section/action/deletependingtitles.c b/source/ui/section/action/deletependingtitles.c index dc5989f..bff0ad1 100644 --- a/source/ui/section/action/deletependingtitles.c +++ b/source/ui/section/action/deletependingtitles.c @@ -1,5 +1,6 @@ #include #include +#include #include <3ds.h> @@ -17,23 +18,40 @@ typedef struct { linked_list* items; list_item* selected; - bool all; + linked_list contents; - data_op_info deleteInfo; - Handle cancelEvent; + data_op_data deleteInfo; } delete_pending_titles_data; +static void action_delete_pending_titles_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { + delete_pending_titles_data* deleteData = (delete_pending_titles_data*) data; + + u32 index = deleteData->deleteInfo.processed; + if(index < deleteData->deleteInfo.total) { + ui_draw_pending_title_info(view, (pending_title_info*) ((list_item*) linked_list_get(&deleteData->contents, index))->data, x1, y1, x2, y2); + } +} + static Result action_delete_pending_titles_delete(void* data, u32 index) { delete_pending_titles_data* deleteData = (delete_pending_titles_data*) data; - list_item* item = deleteData->all ? (list_item*) linked_list_get(deleteData->items, index) : deleteData->selected; + list_item* item = (list_item*) linked_list_get(&deleteData->contents, index); pending_title_info* info = (pending_title_info*) item->data; Result res = 0; if(R_SUCCEEDED(res = AM_DeletePendingTitle(info->mediaType, info->titleId))) { - linked_list_remove(deleteData->items, item); - task_free_pending_title(item); + linked_list_iter iter; + linked_list_iterate(deleteData->items, &iter); + + while(linked_list_iter_has_next(&iter)) { + list_item* currItem = (list_item*) linked_list_iter_next(&iter); + + if(strncmp(currItem->name, item->name, LIST_ITEM_NAME_MAX) == 0) { + linked_list_iter_remove(&iter); + task_free_file(currItem); + } + } } return res; @@ -42,14 +60,12 @@ static Result action_delete_pending_titles_delete(void* data, u32 index) { static bool action_delete_pending_titles_error(void* data, u32 index, Result res) { delete_pending_titles_data* deleteData = (delete_pending_titles_data*) data; - pending_title_info* info = (pending_title_info*) (deleteData->all ? ((list_item*) linked_list_get(deleteData->items, index))->data : deleteData->selected->data); - if(res == R_FBI_CANCELLED) { - prompt_display("Failure", "Delete cancelled.", COLOR_TEXT, false, info, NULL, ui_draw_pending_title_info, NULL); + prompt_display("Failure", "Delete cancelled.", COLOR_TEXT, false, NULL, NULL, NULL, NULL); return false; } else { volatile bool dismissed = false; - error_display_res(&dismissed, info, ui_draw_pending_title_info, res, "Failed to delete pending title."); + error_display_res(&dismissed, data, action_delete_pending_titles_draw_top, res, "Failed to delete pending title."); while(!dismissed) { svcSleepThread(1000000); @@ -59,13 +75,10 @@ static bool action_delete_pending_titles_error(void* data, u32 index, Result res return index < deleteData->deleteInfo.total - 1; } -static void action_delete_pending_titles_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { - delete_pending_titles_data* deleteData = (delete_pending_titles_data*) data; - - u32 index = deleteData->deleteInfo.processed; - if(index < deleteData->deleteInfo.total) { - ui_draw_pending_title_info(view, (pending_title_info*) (deleteData->all ? ((list_item*) linked_list_get(deleteData->items, index))->data : deleteData->selected->data), x1, y1, x2, y2); - } +static void action_delete_pending_titles_free_data(delete_pending_titles_data* data) { + task_clear_pending_titles(&data->contents); + linked_list_destroy(&data->contents); + free(data); } static void action_delete_pending_titles_update(ui_view* view, void* data, float* progress, char* text) { @@ -75,17 +88,17 @@ static void action_delete_pending_titles_update(ui_view* view, void* data, float ui_pop(); info_destroy(view); - if(!deleteData->deleteInfo.premature) { + if(R_SUCCEEDED(deleteData->deleteInfo.result)) { prompt_display("Success", "Pending title(s) deleted.", COLOR_TEXT, false, NULL, NULL, NULL, NULL); } - free(deleteData); + action_delete_pending_titles_free_data(deleteData); return; } - if(hidKeysDown() & KEY_B) { - svcSignalEvent(deleteData->cancelEvent); + if((hidKeysDown() & KEY_B) && !deleteData->deleteInfo.finished) { + svcSignalEvent(deleteData->deleteInfo.cancelEvent); } *progress = deleteData->deleteInfo.total > 0 ? (float) deleteData->deleteInfo.processed / (float) deleteData->deleteInfo.total : 0; @@ -96,14 +109,16 @@ static void action_delete_pending_titles_onresponse(ui_view* view, void* data, b delete_pending_titles_data* deleteData = (delete_pending_titles_data*) data; if(response) { - deleteData->cancelEvent = task_data_op(&deleteData->deleteInfo); - if(deleteData->cancelEvent != 0) { + Result res = task_data_op(&deleteData->deleteInfo); + if(R_SUCCEEDED(res)) { info_display("Deleting Pending Title(s)", "Press B to cancel.", true, data, action_delete_pending_titles_update, action_delete_pending_titles_draw_top); } else { - error_display(NULL, NULL, NULL, "Failed to initiate delete operation."); + error_display_res(NULL, NULL, NULL, res, "Failed to initiate delete operation."); + + action_delete_pending_titles_free_data(deleteData); } } else { - free(deleteData); + action_delete_pending_titles_free_data(deleteData); } } @@ -118,19 +133,44 @@ void action_delete_pending_titles(linked_list* items, list_item* selected, const data->items = items; data->selected = selected; - data->all = all; - data->deleteInfo.data = data; data->deleteInfo.op = DATAOP_DELETE; - data->deleteInfo.total = all ? linked_list_size(items) : 1; - data->deleteInfo.delete = action_delete_pending_titles_delete; data->deleteInfo.error = action_delete_pending_titles_error; - data->cancelEvent = 0; + linked_list_init(&data->contents); + + if(all) { + populate_pending_titles_data popData; + popData.items = &data->contents; + + Result listRes = task_populate_pending_titles(&popData); + if(R_FAILED(listRes)) { + error_display_res(NULL, NULL, NULL, listRes, "Failed to initiate pending title list population."); + + action_delete_pending_titles_free_data(data); + return; + } + + while(!popData.finished) { + svcSleepThread(1000000); + } + + if(R_FAILED(popData.result)) { + error_display_res(NULL, NULL, NULL, popData.result, "Failed to populate pending title list."); + + action_delete_pending_titles_free_data(data); + return; + } + } else { + linked_list_add(&data->contents, selected); + } + + data->deleteInfo.total = linked_list_size(&data->contents); + data->deleteInfo.processed = data->deleteInfo.total; prompt_display("Confirmation", message, COLOR_TEXT, true, data, NULL, !all ? action_delete_pending_titles_draw_top : NULL, action_delete_pending_titles_onresponse); } diff --git a/source/ui/section/action/exportsecurevalue.c b/source/ui/section/action/exportsecurevalue.c index a75a428..2f003ca 100644 --- a/source/ui/section/action/exportsecurevalue.c +++ b/source/ui/section/action/exportsecurevalue.c @@ -30,9 +30,9 @@ static void action_export_secure_value_update(ui_view* view, void* data, float* return; } - FS_Archive sdmcArchive = {ARCHIVE_SDMC, {PATH_BINARY, 0, (void*) ""}}; - if(R_SUCCEEDED(res = FSUSER_OpenArchive(&sdmcArchive))) { - if(R_SUCCEEDED(res = util_ensure_dir(&sdmcArchive, "/fbi/")) && R_SUCCEEDED(res = util_ensure_dir(&sdmcArchive, "/fbi/securevalue/"))) { + FS_Archive sdmcArchive = 0; + if(R_SUCCEEDED(res = FSUSER_OpenArchive(&sdmcArchive, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, "")))) { + if(R_SUCCEEDED(res = util_ensure_dir(sdmcArchive, "/fbi/")) && R_SUCCEEDED(res = util_ensure_dir(sdmcArchive, "/fbi/securevalue/"))) { char pathBuf[64]; snprintf(pathBuf, 64, "/fbi/securevalue/%016llX.dat", info->titleId); @@ -51,7 +51,7 @@ static void action_export_secure_value_update(ui_view* view, void* data, float* } } - FSUSER_CloseArchive(&sdmcArchive); + FSUSER_CloseArchive(sdmcArchive); } } diff --git a/source/ui/section/action/extractsmdh.c b/source/ui/section/action/extractsmdh.c index 385c7b3..7046419 100644 --- a/source/ui/section/action/extractsmdh.c +++ b/source/ui/section/action/extractsmdh.c @@ -19,40 +19,43 @@ static void action_extract_smdh_update(ui_view* view, void* data, float* progres Result res = 0; - static const u32 filePathData[] = {0x00000000, 0x00000000, 0x00000002, 0x6E6F6369, 0x00000000}; - static const FS_Path filePath = (FS_Path) {PATH_BINARY, 0x14, (u8*) filePathData}; - u32 archivePath[] = {(u32) (info->titleId & 0xFFFFFFFF), (u32) ((info->titleId >> 32) & 0xFFFFFFFF), info->mediaType, 0x00000000}; - FS_Archive archive = {ARCHIVE_SAVEDATA_AND_CONTENT, (FS_Path) {PATH_BINARY, 0x10, (u8*) archivePath}}; + static const u32 filePath[5] = {0x00000000, 0x00000000, 0x00000002, 0x6E6F6369, 0x00000000}; + u32 archivePath[4] = {(u32) (info->titleId & 0xFFFFFFFF), (u32) ((info->titleId >> 32) & 0xFFFFFFFF), info->mediaType, 0x00000000}; Handle fileHandle; - if(R_SUCCEEDED(res = FSUSER_OpenFileDirectly(&fileHandle, archive, filePath, FS_OPEN_READ, 0))) { - SMDH smdh; + if(R_SUCCEEDED(res = FSUSER_OpenFileDirectly(&fileHandle, ARCHIVE_SAVEDATA_AND_CONTENT, util_make_binary_path(archivePath, sizeof(archivePath)), util_make_binary_path(filePath, sizeof(filePath)), FS_OPEN_READ, 0))) { + SMDH* smdh = (SMDH*) calloc(1, sizeof(SMDH)); + if(smdh != NULL) { + u32 bytesRead = 0; + if(R_SUCCEEDED(res = FSFILE_Read(fileHandle, &bytesRead, 0, smdh, sizeof(SMDH))) && bytesRead == sizeof(SMDH)) { + FS_Archive sdmcArchive = 0; + if(R_SUCCEEDED(res = FSUSER_OpenArchive(&sdmcArchive, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, "")))) { + if(R_SUCCEEDED(res = util_ensure_dir(sdmcArchive, "/fbi/")) && R_SUCCEEDED(res = util_ensure_dir(sdmcArchive, "/fbi/smdh/"))) { + char pathBuf[64]; + snprintf(pathBuf, 64, "/fbi/smdh/%016llX.smdh", info->titleId); - u32 bytesRead = 0; - if(R_SUCCEEDED(res = FSFILE_Read(fileHandle, &bytesRead, 0, &smdh, sizeof(SMDH))) && bytesRead == sizeof(SMDH)) { - FS_Archive sdmcArchive = {ARCHIVE_SDMC, {PATH_BINARY, 0, (void*) ""}}; - if(R_SUCCEEDED(res = FSUSER_OpenArchive(&sdmcArchive))) { - if(R_SUCCEEDED(res = util_ensure_dir(&sdmcArchive, "/fbi/")) && R_SUCCEEDED(res = util_ensure_dir(&sdmcArchive, "/fbi/smdh/"))) { - char pathBuf[64]; - snprintf(pathBuf, 64, "/fbi/smdh/%016llX.smdh", info->titleId); + FS_Path* fsPath = util_make_path_utf8(pathBuf); + if(fsPath != NULL) { + Handle smdhHandle = 0; + if(R_SUCCEEDED(res = FSUSER_OpenFile(&smdhHandle, sdmcArchive, *fsPath, FS_OPEN_WRITE | FS_OPEN_CREATE, 0))) { + u32 bytesWritten = 0; + res = FSFILE_Write(smdhHandle, &bytesWritten, 0, smdh, sizeof(SMDH), FS_WRITE_FLUSH | FS_WRITE_UPDATE_TIME); + FSFILE_Close(smdhHandle); + } - FS_Path* fsPath = util_make_path_utf8(pathBuf); - if(fsPath != NULL) { - Handle smdhHandle = 0; - if(R_SUCCEEDED(res = FSUSER_OpenFile(&smdhHandle, sdmcArchive, *fsPath, FS_OPEN_WRITE | FS_OPEN_CREATE, 0))) { - u32 bytesWritten = 0; - res = FSFILE_Write(smdhHandle, &bytesWritten, 0, &smdh, sizeof(SMDH), FS_WRITE_FLUSH | FS_WRITE_UPDATE_TIME); - FSFILE_Close(smdhHandle); + util_free_path_utf8(fsPath); + } else { + res = R_FBI_OUT_OF_MEMORY; } - - util_free_path_utf8(fsPath); - } else { - res = R_FBI_OUT_OF_MEMORY; } - } - FSUSER_CloseArchive(&sdmcArchive); + FSUSER_CloseArchive(sdmcArchive); + } } + + free(smdh); + } else { + res = R_FBI_OUT_OF_MEMORY; } FSFILE_Close(fileHandle); diff --git a/source/ui/section/action/importsecurevalue.c b/source/ui/section/action/importsecurevalue.c index 528b924..78a19ba 100644 --- a/source/ui/section/action/importsecurevalue.c +++ b/source/ui/section/action/importsecurevalue.c @@ -23,9 +23,8 @@ static void action_import_secure_value_update(ui_view* view, void* data, float* FS_Path* fsPath = util_make_path_utf8(pathBuf); if(fsPath != NULL) { - FS_Archive sdmcArchive = {ARCHIVE_SDMC, {PATH_BINARY, 0, (void*) ""}}; Handle fileHandle = 0; - if(R_SUCCEEDED(res = FSUSER_OpenFileDirectly(&fileHandle, sdmcArchive, *fsPath, FS_OPEN_READ, 0))) { + if(R_SUCCEEDED(res = FSUSER_OpenFileDirectly(&fileHandle, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""), *fsPath, FS_OPEN_READ, 0))) { u32 bytesRead = 0; u64 value = 0; if(R_SUCCEEDED(res = FSFILE_Read(fileHandle, &bytesRead, 0, &value, sizeof(u64)))) { diff --git a/source/ui/section/action/installcdn.c b/source/ui/section/action/installcdn.c index a614631..19bcbf9 100644 --- a/source/ui/section/action/installcdn.c +++ b/source/ui/section/action/installcdn.c @@ -24,8 +24,7 @@ typedef struct { u32 responseCode; - data_op_info installInfo; - Handle cancelEvent; + data_op_data installInfo; } install_cdn_data; static Result action_install_cdn_is_src_directory(void* data, u32 index, bool* isDirectory) { @@ -173,7 +172,7 @@ static void action_install_cdn_update(ui_view* view, void* data, float* progress Result res = 0; - if(!installData->installInfo.premature) { + if(R_SUCCEEDED(installData->installInfo.result)) { if(R_SUCCEEDED(res = AM_InstallTitleFinish()) && R_SUCCEEDED(res = AM_CommitImportTitles(((installData->ticket->titleId >> 32) & 0x8010) != 0 ? MEDIATYPE_NAND : MEDIATYPE_SD, 1, false, &installData->ticket->titleId))) { if(installData->ticket->titleId == 0x0004013800000002 || installData->ticket->titleId == 0x0004013820000002) { @@ -182,7 +181,7 @@ static void action_install_cdn_update(ui_view* view, void* data, float* progress } } - if(!installData->installInfo.premature && R_SUCCEEDED(res)) { + if(R_SUCCEEDED(installData->installInfo.result) && R_SUCCEEDED(res)) { prompt_display("Success", "Install finished.", COLOR_TEXT, false, installData->ticket, NULL, ui_draw_ticket_info, NULL); } else { AM_InstallTitleAbort(); @@ -197,8 +196,8 @@ static void action_install_cdn_update(ui_view* view, void* data, float* progress return; } - if(hidKeysDown() & KEY_B) { - svcSignalEvent(installData->cancelEvent); + if((hidKeysDown() & KEY_B) && !installData->installInfo.finished) { + svcSignalEvent(installData->installInfo.cancelEvent); } *progress = installData->installInfo.currTotal != 0 ? (float) ((double) installData->installInfo.currProcessed / (double) installData->installInfo.currTotal) : 0; @@ -209,35 +208,30 @@ static void action_install_cdn_onresponse(ui_view* view, void* data, bool respon install_cdn_data* installData = (install_cdn_data*) data; if(response) { - u8 n3ds = false; - if(R_SUCCEEDED(APT_CheckNew3DS(&n3ds)) && !n3ds && ((installData->ticket->titleId >> 28) & 0xF) == 2) { - error_display(NULL, installData->ticket, ui_draw_ticket_info, "Failed to install CDN title.\nAttempted to install N3DS title to O3DS."); - - action_install_cdn_free_data(installData); - - return; - } - - FS_MediaType dest = ((installData->ticket->titleId >> 32) & 0x8010) != 0 ? MEDIATYPE_NAND : MEDIATYPE_SD; - - AM_DeleteTitle(dest, installData->ticket->titleId); - if(dest == MEDIATYPE_SD) { - AM_QueryAvailableExternalTitleDatabase(NULL); - } - Result res = 0; - if(R_SUCCEEDED(res = AM_InstallTitleBegin(dest, installData->ticket->titleId, false))) { - installData->cancelEvent = task_data_op(&installData->installInfo); - if(installData->cancelEvent != 0) { - info_display("Installing CDN Title", "Press B to cancel.", true, data, action_install_cdn_update, action_install_cdn_draw_top); - } else { - AM_InstallTitleAbort(); + u8 n3ds = false; + if(R_FAILED(APT_CheckNew3DS(&n3ds)) || n3ds || ((installData->ticket->titleId >> 28) & 0xF) != 2) { + FS_MediaType dest = ((installData->ticket->titleId >> 32) & 0x8010) != 0 ? MEDIATYPE_NAND : MEDIATYPE_SD; + + AM_DeleteTitle(dest, installData->ticket->titleId); + if(dest == MEDIATYPE_SD) { + AM_QueryAvailableExternalTitleDatabase(NULL); } + + if(R_SUCCEEDED(res = AM_InstallTitleBegin(dest, installData->ticket->titleId, false))) { + if(R_SUCCEEDED(res = task_data_op(&installData->installInfo))) { + info_display("Installing CDN Title", "Press B to cancel.", true, data, action_install_cdn_update, action_install_cdn_draw_top); + } else { + AM_InstallTitleAbort(); + } + } + } else { + res = R_FBI_WRONG_SYSTEM; } - if(R_FAILED(res) || installData->cancelEvent == 0) { - error_display(NULL, installData->ticket, ui_draw_ticket_info, "Failed to initiate CDN title installation."); + if(R_FAILED(res)) { + error_display_res(NULL, installData->ticket, ui_draw_ticket_info, res, "Failed to initiate CDN title installation."); action_install_cdn_free_data(installData); } @@ -280,7 +274,5 @@ void action_install_cdn(linked_list* items, list_item* selected) { data->installInfo.error = action_install_cdn_error; - data->cancelEvent = 0; - prompt_display("Confirmation", "Install the selected title from the CDN?", COLOR_TEXT, true, data, NULL, action_install_cdn_draw_top, action_install_cdn_onresponse); } \ No newline at end of file diff --git a/source/ui/section/action/installcias.c b/source/ui/section/action/installcias.c index b3fd95a..202a69a 100644 --- a/source/ui/section/action/installcias.c +++ b/source/ui/section/action/installcias.c @@ -17,21 +17,28 @@ typedef struct { linked_list* items; - list_item* selected; file_info* target; - list_item* curr; + linked_list contents; - bool all; bool delete; - u32 numDeleted; u64 currTitleId; - data_op_info installInfo; - Handle cancelEvent; + data_op_data installInfo; } install_cias_data; +static void action_install_cias_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { + install_cias_data* installData = (install_cias_data*) data; + + u32 curr = installData->installInfo.processed; + if(curr < installData->installInfo.total) { + ui_draw_file_info(view, ((list_item*) linked_list_get(&installData->contents, curr))->data, x1, y1, x2, y2); + } else if(installData->target != NULL) { + ui_draw_file_info(view, installData->target, x1, y1, x2, y2); + } +} + static Result action_install_cias_is_src_directory(void* data, u32 index, bool* isDirectory) { *isDirectory = false; return 0; @@ -44,32 +51,13 @@ static Result action_install_cias_make_dst_directory(void* data, u32 index) { static Result action_install_cias_open_src(void* data, u32 index, u32* handle) { install_cias_data* installData = (install_cias_data*) data; - if(installData->all) { - linked_list_iter iter; - linked_list_iterate(installData->items, &iter); - - u32 count = 0; - while(linked_list_iter_has_next(&iter) && count < index + 1 - installData->numDeleted) { - list_item* item = linked_list_iter_next(&iter); - file_info* info = (file_info*) item->data; - - size_t len = strlen(info->path); - if(len > 4 && strcmp(&info->path[len - 4], ".cia") == 0) { - installData->curr = item; - count++; - } - } - } else { - installData->curr = installData->selected; - } - - file_info* info = (file_info*) installData->curr->data; + file_info* info = (file_info*) ((list_item*) linked_list_get(&installData->contents, index))->data; Result res = 0; FS_Path* fsPath = util_make_path_utf8(info->path); if(fsPath != NULL) { - res = FSUSER_OpenFile(handle, *info->archive, *fsPath, FS_OPEN_READ, 0); + res = FSUSER_OpenFile(handle, info->archive, *fsPath, FS_OPEN_READ, 0); util_free_path_utf8(fsPath); } else { @@ -82,20 +70,33 @@ static Result action_install_cias_open_src(void* data, u32 index, u32* handle) { static Result action_install_cias_close_src(void* data, u32 index, bool succeeded, u32 handle) { install_cias_data* installData = (install_cias_data*) data; - file_info* info = (file_info*) installData->curr->data; + file_info* info = (file_info*) ((list_item*) linked_list_get(&installData->contents, index))->data; Result res = 0; if(R_SUCCEEDED(res = FSFILE_Close(handle)) && installData->delete && succeeded) { FS_Path* fsPath = util_make_path_utf8(info->path); if(fsPath != NULL) { - if(R_SUCCEEDED(FSUSER_DeleteFile(*info->archive, *fsPath))) { - linked_list_remove(installData->items, installData->curr); - task_free_file(installData->curr); + if(R_SUCCEEDED(FSUSER_DeleteFile(info->archive, *fsPath))) { + installData->target->containsCias = false; + installData->target->containsTickets = false; - installData->curr = NULL; + linked_list_iter iter; + linked_list_iterate(installData->items, &iter); - installData->numDeleted++; + while(linked_list_iter_has_next(&iter)) { + list_item* item = (list_item*) linked_list_iter_next(&iter); + file_info* currInfo = (file_info*) item->data; + + if(strncmp(currInfo->path, info->path, FILE_PATH_MAX) == 0) { + linked_list_iter_remove(&iter); + task_free_file(item); + } else if(currInfo->isCia) { + installData->target->containsCias = true; + } else if(currInfo->isTicket) { + installData->target->containsTickets = true; + } + } } util_free_path_utf8(fsPath); @@ -173,18 +174,12 @@ static Result action_install_cias_write_dst(void* data, u32 handle, u32* bytesWr bool action_install_cias_error(void* data, u32 index, Result res) { install_cias_data* installData = (install_cias_data*) data; - file_info* info = (file_info*) installData->curr->data; - if(res == R_FBI_CANCELLED) { - prompt_display("Failure", "Install cancelled.", COLOR_TEXT, false, info, NULL, ui_draw_file_info, NULL); + prompt_display("Failure", "Install cancelled.", COLOR_TEXT, false, NULL, NULL, NULL, NULL); return false; } else { volatile bool dismissed = false; - if(res == R_FBI_WRONG_SYSTEM) { - error_display(&dismissed, info, ui_draw_file_info, "Failed to install CIA file.\nAttempted to install N3DS title to O3DS."); - } else { - error_display_res(&dismissed, info, ui_draw_file_info, res, "Failed to install CIA file."); - } + error_display_res(&dismissed, data, action_install_cias_draw_top, res, "Failed to install CIA file."); while(!dismissed) { svcSleepThread(1000000); @@ -194,34 +189,34 @@ bool action_install_cias_error(void* data, u32 index, Result res) { return index < installData->installInfo.total - 1; } -static void action_install_cias_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { - install_cias_data* installData = (install_cias_data*) data; - - if(installData->curr != NULL) { - ui_draw_file_info(view, installData->curr->data, x1, y1, x2, y2); - } else if(installData->target != NULL) { - ui_draw_file_info(view, installData->target, x1, y1, x2, y2); - } +static void action_install_cias_free_data(install_cias_data* data) { + task_clear_files(&data->contents); + linked_list_destroy(&data->contents); + free(data); } static void action_install_cias_update(ui_view* view, void* data, float* progress, char* text) { install_cias_data* installData = (install_cias_data*) data; if(installData->installInfo.finished) { + if(installData->delete) { + FSUSER_ControlArchive(installData->target->archive, ARCHIVE_ACTION_COMMIT_SAVE_DATA, NULL, 0, NULL, 0); + } + ui_pop(); info_destroy(view); - if(!installData->installInfo.premature) { + if(R_SUCCEEDED(installData->installInfo.result)) { prompt_display("Success", "Install finished.", COLOR_TEXT, false, NULL, NULL, NULL, NULL); } - free(installData); + action_install_cias_free_data(installData); return; } - if(hidKeysDown() & KEY_B) { - svcSignalEvent(installData->cancelEvent); + if((hidKeysDown() & KEY_B) && !installData->installInfo.finished) { + svcSignalEvent(installData->installInfo.cancelEvent); } *progress = installData->installInfo.currTotal != 0 ? (float) ((double) installData->installInfo.currProcessed / (double) installData->installInfo.currTotal) : 0; @@ -232,20 +227,20 @@ static void action_install_cias_onresponse(ui_view* view, void* data, bool respo install_cias_data* installData = (install_cias_data*) data; if(response) { - installData->cancelEvent = task_data_op(&installData->installInfo); - if(installData->cancelEvent != 0) { + Result res = task_data_op(&installData->installInfo); + if(R_SUCCEEDED(res)) { info_display("Installing CIA(s)", "Press B to cancel.", true, data, action_install_cias_update, action_install_cias_draw_top); } else { - error_display(NULL, NULL, NULL, "Failed to initiate CIA installation."); + error_display_res(NULL, NULL, NULL, res, "Failed to initiate CIA installation."); - free(installData); + action_install_cias_free_data(installData); } } else { - free(installData); + action_install_cias_free_data(installData); } } -static void action_install_cias_internal(linked_list* items, list_item* selected, file_info* target, const char* message, bool all, bool delete) { +static void action_install_cias_internal(linked_list* items, list_item* selected, const char* message, bool delete) { install_cias_data* data = (install_cias_data*) calloc(1, sizeof(install_cias_data)); if(data == NULL) { error_display(NULL, NULL, NULL, "Failed to allocate install CIAs data."); @@ -254,13 +249,10 @@ static void action_install_cias_internal(linked_list* items, list_item* selected } data->items = items; - data->selected = selected; - data->target = target; + data->target = (file_info*) selected->data; - data->all = all; data->delete = delete; - data->numDeleted = 0; data->currTitleId = 0; data->installInfo.data = data; @@ -283,40 +275,63 @@ static void action_install_cias_internal(linked_list* items, list_item* selected data->installInfo.error = action_install_cias_error; - data->cancelEvent = 0; + linked_list_init(&data->contents); - if(all) { - linked_list_iter iter; - linked_list_iterate(data->items, &iter); + populate_files_data popData; + popData.items = &data->contents; + popData.base = data->target; + popData.recursive = false; + popData.includeBase = !data->target->isDirectory; + popData.dirsFirst = false; - while(linked_list_iter_has_next(&iter)) { - list_item* item = linked_list_iter_next(&iter); - file_info* info = (file_info*) item->data; + Result listRes = task_populate_files(&popData); + if(R_FAILED(listRes)) { + error_display_res(NULL, NULL, NULL, listRes, "Failed to initiate CIA list population."); - size_t len = strlen(info->path); - if(len > 4 && strcmp(&info->path[len - 4], ".cia") == 0) { - data->installInfo.total++; - } - } - } else { - data->installInfo.total = 1; + action_install_cias_free_data(data); + return; } + while(!popData.finished) { + svcSleepThread(1000000); + } + + if(R_FAILED(popData.result)) { + error_display_res(NULL, NULL, NULL, popData.result, "Failed to populate CIA list."); + + action_install_cias_free_data(data); + return; + } + + linked_list_iter iter; + linked_list_iterate(&data->contents, &iter); + + while(linked_list_iter_has_next(&iter)) { + file_info* info = (file_info*) ((list_item*) linked_list_iter_next(&iter))->data; + + if(!info->isCia) { + linked_list_iter_remove(&iter); + } + } + + data->installInfo.total = linked_list_size(&data->contents); + data->installInfo.processed = data->installInfo.total; + prompt_display("Confirmation", message, COLOR_TEXT, true, data, NULL, action_install_cias_draw_top, action_install_cias_onresponse); } -void action_install_cia(linked_list* items, list_item* selected, file_info* target) { - action_install_cias_internal(items, selected, target, "Install the selected CIA?", false, false); +void action_install_cia(linked_list* items, list_item* selected) { + action_install_cias_internal(items, selected, "Install the selected CIA?", false); } -void action_install_cia_delete(linked_list* items, list_item* selected, file_info* target) { - action_install_cias_internal(items, selected, target, "Install and delete the selected CIA?", false, true); +void action_install_cia_delete(linked_list* items, list_item* selected) { + action_install_cias_internal(items, selected, "Install and delete the selected CIA?", true); } -void action_install_cias(linked_list* items, list_item* selected, file_info* target) { - action_install_cias_internal(items, selected, target, "Install all CIAs in the current directory?", true, false); +void action_install_cias(linked_list* items, list_item* selected) { + action_install_cias_internal(items, selected, "Install all CIAs in the current directory?", false); } -void action_install_cias_delete(linked_list* items, list_item* selected, file_info* target) { - action_install_cias_internal(items, selected, target, "Install and delete all CIAs in the current directory?", true, true); +void action_install_cias_delete(linked_list* items, list_item* selected) { + action_install_cias_internal(items, selected, "Install and delete all CIAs in the current directory?", true); } \ No newline at end of file diff --git a/source/ui/section/action/installtickets.c b/source/ui/section/action/installtickets.c index 9818517..9662a0a 100644 --- a/source/ui/section/action/installtickets.c +++ b/source/ui/section/action/installtickets.c @@ -17,20 +17,26 @@ typedef struct { linked_list* items; - list_item* selected; file_info* target; - list_item* curr; + linked_list contents; - bool all; bool delete; - u32 numDeleted; - - data_op_info installInfo; - Handle cancelEvent; + data_op_data installInfo; } install_tickets_data; +static void action_install_tickets_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { + install_tickets_data* installData = (install_tickets_data*) data; + + u32 curr = installData->installInfo.processed; + if(curr < installData->installInfo.total) { + ui_draw_file_info(view, ((list_item*) linked_list_get(&installData->contents, curr))->data, x1, y1, x2, y2); + } else if(installData->target != NULL) { + ui_draw_file_info(view, installData->target, x1, y1, x2, y2); + } +} + static Result action_install_tickets_is_src_directory(void* data, u32 index, bool* isDirectory) { *isDirectory = false; return 0; @@ -43,32 +49,13 @@ static Result action_install_tickets_make_dst_directory(void* data, u32 index) { static Result action_install_tickets_open_src(void* data, u32 index, u32* handle) { install_tickets_data* installData = (install_tickets_data*) data; - if(installData->all) { - linked_list_iter iter; - linked_list_iterate(installData->items, &iter); - - u32 count = 0; - while(linked_list_iter_has_next(&iter) && count < index + 1 - installData->numDeleted) { - list_item* item = linked_list_iter_next(&iter); - file_info* info = (file_info*) item->data; - - size_t len = strlen(info->path); - if(len > 4 && strcmp(&info->path[len - 4], ".tik") == 0) { - installData->curr = item; - count++; - } - } - } else { - installData->curr = installData->selected; - } - - file_info* info = (file_info*) installData->curr->data; + file_info* info = (file_info*) ((list_item*) linked_list_get(&installData->contents, index))->data; Result res = 0; FS_Path* fsPath = util_make_path_utf8(info->path); if(fsPath != NULL) { - res = FSUSER_OpenFile(handle, *info->archive, *fsPath, FS_OPEN_READ, 0); + res = FSUSER_OpenFile(handle, info->archive, *fsPath, FS_OPEN_READ, 0); util_free_path_utf8(fsPath); } else { @@ -81,20 +68,33 @@ static Result action_install_tickets_open_src(void* data, u32 index, u32* handle static Result action_install_tickets_close_src(void* data, u32 index, bool succeeded, u32 handle) { install_tickets_data* installData = (install_tickets_data*) data; - file_info* info = (file_info*) installData->curr->data; + file_info* info = (file_info*) ((list_item*) linked_list_get(&installData->contents, index))->data; Result res = 0; if(R_SUCCEEDED(res = FSFILE_Close(handle)) && installData->delete && succeeded) { FS_Path* fsPath = util_make_path_utf8(info->path); if(fsPath != NULL) { - if(R_SUCCEEDED(FSUSER_DeleteFile(*info->archive, *fsPath))) { - linked_list_remove(installData->items, installData->curr); - task_free_file(installData->curr); + if(R_SUCCEEDED(FSUSER_DeleteFile(info->archive, *fsPath))) { + installData->target->containsCias = false; + installData->target->containsTickets = false; - installData->curr = NULL; + linked_list_iter iter; + linked_list_iterate(installData->items, &iter); - installData->numDeleted++; + while(linked_list_iter_has_next(&iter)) { + list_item* item = (list_item*) linked_list_iter_next(&iter); + file_info* currInfo = (file_info*) item->data; + + if(strncmp(currInfo->path, info->path, FILE_PATH_MAX) == 0) { + linked_list_iter_remove(&iter); + task_free_file(item); + } else if(currInfo->isCia) { + installData->target->containsCias = true; + } else if(currInfo->isTicket) { + installData->target->containsTickets = true; + } + } } util_free_path_utf8(fsPath); @@ -133,14 +133,12 @@ static Result action_install_tickets_write_dst(void* data, u32 handle, u32* byte static bool action_install_tickets_error(void* data, u32 index, Result res) { install_tickets_data* installData = (install_tickets_data*) data; - file_info* info = (file_info*) installData->curr->data; - if(res == R_FBI_CANCELLED) { - prompt_display("Failure", "Install cancelled.", COLOR_TEXT, false, info, NULL, ui_draw_file_info, NULL); + prompt_display("Failure", "Install cancelled.", COLOR_TEXT, false, NULL, NULL, NULL, NULL); return false; } else { volatile bool dismissed = false; - error_display_res(&dismissed, info, ui_draw_file_info, res, "Failed to install ticket."); + error_display_res(&dismissed, data, action_install_tickets_draw_top, res, "Failed to install ticket."); while(!dismissed) { svcSleepThread(1000000); @@ -150,34 +148,34 @@ static bool action_install_tickets_error(void* data, u32 index, Result res) { return index < installData->installInfo.total - 1; } -static void action_install_tickets_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { - install_tickets_data* installData = (install_tickets_data*) data; - - if(installData->curr != NULL) { - ui_draw_file_info(view, installData->curr->data, x1, y1, x2, y2); - } else if(installData->target != NULL) { - ui_draw_file_info(view, installData->target, x1, y1, x2, y2); - } +static void action_install_tickets_free_data(install_tickets_data* data) { + task_clear_files(&data->contents); + linked_list_destroy(&data->contents); + free(data); } static void action_install_tickets_update(ui_view* view, void* data, float* progress, char* text) { install_tickets_data* installData = (install_tickets_data*) data; if(installData->installInfo.finished) { + if(installData->delete) { + FSUSER_ControlArchive(installData->target->archive, ARCHIVE_ACTION_COMMIT_SAVE_DATA, NULL, 0, NULL, 0); + } + ui_pop(); info_destroy(view); - if(!installData->installInfo.premature) { + if(R_SUCCEEDED(installData->installInfo.result)) { prompt_display("Success", "Install finished.", COLOR_TEXT, false, NULL, NULL, NULL, NULL); } - free(installData); + action_install_tickets_free_data(installData); return; } - if(hidKeysDown() & KEY_B) { - svcSignalEvent(installData->cancelEvent); + if((hidKeysDown() & KEY_B) && !installData->installInfo.finished) { + svcSignalEvent(installData->installInfo.cancelEvent); } *progress = installData->installInfo.currTotal != 0 ? (float) ((double) installData->installInfo.currProcessed / (double) installData->installInfo.currTotal) : 0; @@ -188,20 +186,20 @@ static void action_install_tickets_onresponse(ui_view* view, void* data, bool re install_tickets_data* installData = (install_tickets_data*) data; if(response) { - installData->cancelEvent = task_data_op(&installData->installInfo); - if(installData->cancelEvent != 0) { + Result res = task_data_op(&installData->installInfo); + if(R_SUCCEEDED(res)) { info_display("Installing ticket(s)", "Press B to cancel.", true, data, action_install_tickets_update, action_install_tickets_draw_top); } else { - error_display(NULL, NULL, NULL, "Failed to initiate ticket installation."); + error_display_res(NULL, NULL, NULL, res, "Failed to initiate ticket installation."); - free(installData); + action_install_tickets_free_data(installData); } } else { - free(installData); + action_install_tickets_free_data(installData); } } -static void action_install_tickets_internal(linked_list* items, list_item* selected, file_info* target, const char* message, bool all, bool delete) { +static void action_install_tickets_internal(linked_list* items, list_item* selected, const char* message, bool delete) { install_tickets_data* data = (install_tickets_data*) calloc(1, sizeof(install_tickets_data)); if(data == NULL) { error_display(NULL, NULL, NULL, "Failed to allocate install tickets data."); @@ -210,14 +208,10 @@ static void action_install_tickets_internal(linked_list* items, list_item* selec } data->items = items; - data->selected = selected; - data->target = target; + data->target = (file_info*) selected->data; - data->all = all; data->delete = delete; - data->numDeleted = 0; - data->installInfo.data = data; data->installInfo.op = DATAOP_COPY; @@ -238,40 +232,63 @@ static void action_install_tickets_internal(linked_list* items, list_item* selec data->installInfo.error = action_install_tickets_error; - data->cancelEvent = 0; + linked_list_init(&data->contents); - if(all) { - linked_list_iter iter; - linked_list_iterate(data->items, &iter); + populate_files_data popData; + popData.items = &data->contents; + popData.base = data->target; + popData.recursive = false; + popData.includeBase = !data->target->isDirectory; + popData.dirsFirst = false; - while(linked_list_iter_has_next(&iter)) { - list_item* item = linked_list_iter_next(&iter); - file_info* info = (file_info*) item->data; + Result listRes = task_populate_files(&popData); + if(R_FAILED(listRes)) { + error_display_res(NULL, NULL, NULL, listRes, "Failed to initiate ticket file list population."); - size_t len = strlen(info->path); - if(len > 4 && strcmp(&info->path[len - 4], ".tik") == 0) { - data->installInfo.total++; - } - } - } else { - data->installInfo.total = 1; + action_install_tickets_free_data(data); + return; } + while(!popData.finished) { + svcSleepThread(1000000); + } + + if(R_FAILED(popData.result)) { + error_display_res(NULL, NULL, NULL, popData.result, "Failed to populate ticket file list."); + + action_install_tickets_free_data(data); + return; + } + + linked_list_iter iter; + linked_list_iterate(&data->contents, &iter); + + while(linked_list_iter_has_next(&iter)) { + file_info* info = (file_info*) ((list_item*) linked_list_iter_next(&iter))->data; + + if(!info->isTicket) { + linked_list_iter_remove(&iter); + } + } + + data->installInfo.total = linked_list_size(&data->contents); + data->installInfo.processed = data->installInfo.total; + prompt_display("Confirmation", message, COLOR_TEXT, true, data, NULL, action_install_tickets_draw_top, action_install_tickets_onresponse); } -void action_install_ticket(linked_list* items, list_item* selected, file_info* target) { - action_install_tickets_internal(items, selected, target, "Install the selected ticket?", false, false); +void action_install_ticket(linked_list* items, list_item* selected) { + action_install_tickets_internal(items, selected, "Install the selected ticket?", false); } -void action_install_ticket_delete(linked_list* items, list_item* selected, file_info* target) { - action_install_tickets_internal(items, selected, target, "Install and delete the selected ticket?", false, true); +void action_install_ticket_delete(linked_list* items, list_item* selected) { + action_install_tickets_internal(items, selected, "Install and delete the selected ticket?", true); } -void action_install_tickets(linked_list* items, list_item* selected, file_info* target) { - action_install_tickets_internal(items, selected, target, "Install all tickets in the current directory?", true, false); +void action_install_tickets(linked_list* items, list_item* selected) { + action_install_tickets_internal(items, selected, "Install all tickets in the current directory?", false); } -void action_install_tickets_delete(linked_list* items, list_item* selected, file_info* target) { - action_install_tickets_internal(items, selected, target, "Install and delete all tickets in the current directory?", true, true); +void action_install_tickets_delete(linked_list* items, list_item* selected) { + action_install_tickets_internal(items, selected, "Install and delete all tickets in the current directory?", true); } \ No newline at end of file diff --git a/source/ui/section/action/pastefiles.c b/source/ui/section/action/pastefiles.c index 17f31d5..ecc2118 100644 --- a/source/ui/section/action/pastefiles.c +++ b/source/ui/section/action/pastefiles.c @@ -20,15 +20,31 @@ typedef struct { linked_list* items; file_info* target; - char** contents; - list_item* currSrc; + linked_list contents; bool currExists; - data_op_info pasteInfo; - Handle cancelEvent; + data_op_data pasteInfo; } paste_files_data; +static void action_paste_files_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { + paste_files_data* pasteData = (paste_files_data*) data; + + u32 curr = pasteData->pasteInfo.processed; + if(curr < pasteData->pasteInfo.total) { + ui_draw_file_info(view, ((list_item*) linked_list_get(&pasteData->contents, curr))->data, x1, y1, x2, y2); + } else if(pasteData->target != NULL) { + ui_draw_file_info(view, pasteData->target, x1, y1, x2, y2); + } +} + static void action_paste_files_get_dst_path(paste_files_data* data, u32 index, char* dstPath) { + char baseSrcPath[FILE_PATH_MAX]; + if(clipboard_is_contents_only()) { + strncpy(baseSrcPath, clipboard_get_path(), FILE_PATH_MAX); + } else { + util_get_parent_path(baseSrcPath, clipboard_get_path(), FILE_PATH_MAX); + } + char baseDstPath[FILE_PATH_MAX]; if(data->target->isDirectory) { strncpy(baseDstPath, data->target->path, FILE_PATH_MAX); @@ -36,49 +52,33 @@ static void action_paste_files_get_dst_path(paste_files_data* data, u32 index, c util_get_parent_path(baseDstPath, data->target->path, FILE_PATH_MAX); } - util_get_parent_path(dstPath, clipboard_get_path(), FILE_PATH_MAX); - snprintf(dstPath, FILE_PATH_MAX, "%s%s", baseDstPath, data->contents[index] + strlen(dstPath)); + snprintf(dstPath, FILE_PATH_MAX, "%s%s", baseDstPath, ((file_info*) ((list_item*) linked_list_get(&data->contents, index))->data)->path + strlen(baseSrcPath)); } static Result action_paste_files_is_src_directory(void* data, u32 index, bool* isDirectory) { paste_files_data* pasteData = (paste_files_data*) data; - *isDirectory = util_is_dir(clipboard_get_archive(), pasteData->contents[index]); + *isDirectory = ((file_info*) ((list_item*) linked_list_get(&pasteData->contents, index))->data)->isDirectory; return 0; } static Result action_paste_files_make_dst_directory(void* data, u32 index) { paste_files_data* pasteData = (paste_files_data*) data; - list_item* old = pasteData->currSrc; - task_create_file_item(&pasteData->currSrc, clipboard_get_archive(), pasteData->contents[index]); - if(old != NULL) { - task_free_file(old); - } + Result res = 0; char dstPath[FILE_PATH_MAX]; action_paste_files_get_dst_path(pasteData, index, dstPath); - bool existed = util_exists(pasteData->target->archive, dstPath); + if(R_SUCCEEDED(res = util_ensure_dir(pasteData->target->archive, dstPath))) { + char parentPath[FILE_PATH_MAX]; + util_get_parent_path(parentPath, dstPath, FILE_PATH_MAX); - Result res = 0; - - FS_Path* fsPath = util_make_path_utf8(dstPath); - if(fsPath != NULL) { - res = FSUSER_CreateDirectory(*pasteData->target->archive, *fsPath, 0); - - util_free_path_utf8(fsPath); - } else { - res = R_FBI_OUT_OF_MEMORY; - } - - char parentPath[FILE_PATH_MAX]; - util_get_parent_path(parentPath, dstPath, FILE_PATH_MAX); - - if(!existed && strcmp(parentPath, pasteData->target->path) == 0) { - list_item* dstItem = NULL; - if(R_SUCCEEDED(res) && R_SUCCEEDED(task_create_file_item(&dstItem, pasteData->target->archive, dstPath))) { - linked_list_add(pasteData->items, dstItem); + if(strncmp(parentPath, pasteData->target->path, FILE_PATH_MAX) == 0) { + list_item* dstItem = NULL; + if(R_SUCCEEDED(res) && R_SUCCEEDED(task_create_file_item(&dstItem, pasteData->target->archive, dstPath))) { + linked_list_add(pasteData->items, dstItem); + } } } @@ -88,17 +88,11 @@ static Result action_paste_files_make_dst_directory(void* data, u32 index) { static Result action_paste_files_open_src(void* data, u32 index, u32* handle) { paste_files_data* pasteData = (paste_files_data*) data; - list_item* old = pasteData->currSrc; - task_create_file_item(&pasteData->currSrc, clipboard_get_archive(), pasteData->contents[index]); - if(old != NULL) { - task_free_file(old); - } - Result res = 0; - FS_Path* fsPath = util_make_path_utf8(pasteData->contents[index]); + FS_Path* fsPath = util_make_path_utf8(((file_info*) ((list_item*) linked_list_get(&pasteData->contents, index))->data)->path); if(fsPath != NULL) { - res = FSUSER_OpenFile(handle, *clipboard_get_archive(), *fsPath, FS_OPEN_READ, 0); + res = FSUSER_OpenFile(handle, clipboard_get_archive(), *fsPath, FS_OPEN_READ, 0); util_free_path_utf8(fsPath); } else { @@ -123,16 +117,20 @@ static Result action_paste_files_read_src(void* data, u32 handle, u32* bytesRead static Result action_paste_files_open_dst(void* data, u32 index, void* initialReadBlock, u32* handle) { paste_files_data* pasteData = (paste_files_data*) data; + Result res = 0; + char dstPath[FILE_PATH_MAX]; action_paste_files_get_dst_path(pasteData, index, dstPath); - pasteData->currExists = util_exists(pasteData->target->archive, dstPath); - - Result res = 0; - FS_Path* fsPath = util_make_path_utf8(dstPath); if(fsPath != NULL) { - res = FSUSER_OpenFile(handle, *pasteData->target->archive, *fsPath, FS_OPEN_WRITE | FS_OPEN_CREATE, 0); + Handle currHandle; + pasteData->currExists = R_SUCCEEDED(FSUSER_OpenFile(&currHandle, pasteData->target->archive, *fsPath, FS_OPEN_READ, 0)); + if(pasteData->currExists) { + FSFILE_Close(currHandle); + } + + res = FSUSER_OpenFile(handle, pasteData->target->archive, *fsPath, FS_OPEN_WRITE | FS_OPEN_CREATE, 0); util_free_path_utf8(fsPath); } else { @@ -145,19 +143,27 @@ static Result action_paste_files_open_dst(void* data, u32 index, void* initialRe static Result action_paste_files_close_dst(void* data, u32 index, bool succeeded, u32 handle) { paste_files_data* pasteData = (paste_files_data*) data; - Result res = FSFILE_Close(handle); + Result res = 0; - if(R_SUCCEEDED(res) && !pasteData->currExists) { + if(R_SUCCEEDED(res = FSFILE_Close(handle)) && !pasteData->currExists) { char dstPath[FILE_PATH_MAX]; action_paste_files_get_dst_path(pasteData, index, dstPath); char parentPath[FILE_PATH_MAX]; util_get_parent_path(parentPath, dstPath, FILE_PATH_MAX); - if(strcmp(parentPath, pasteData->target->path) == 0) { + if(strncmp(parentPath, pasteData->target->path, FILE_PATH_MAX) == 0) { list_item* dstItem = NULL; if(R_SUCCEEDED(task_create_file_item(&dstItem, pasteData->target->archive, dstPath))) { linked_list_add(pasteData->items, dstItem); + + file_info* dstInfo = (file_info*) dstItem->data; + + if(dstInfo->isCia) { + pasteData->target->containsCias = true; + } else if(dstInfo->isTicket) { + pasteData->target->containsTickets = true; + } } } } @@ -173,13 +179,11 @@ static bool action_paste_files_error(void* data, u32 index, Result res) { paste_files_data* pasteData = (paste_files_data*) data; if(res == R_FBI_CANCELLED) { - prompt_display("Failure", "Paste cancelled.", COLOR_TEXT, false, pasteData->target, NULL, ui_draw_file_info, NULL); + prompt_display("Failure", "Paste cancelled.", COLOR_TEXT, false, NULL, NULL, NULL, NULL); return false; } else { - char* path = pasteData->contents[index]; - volatile bool dismissed = false; - error_display_res(&dismissed, pasteData->currSrc != NULL ? pasteData->currSrc->data : pasteData->target, ui_draw_file_info, res, "Failed to paste content.", path); + error_display_res(&dismissed, data, action_paste_files_draw_top, res, "Failed to paste content."); while(!dismissed) { svcSleepThread(1000000); @@ -189,51 +193,41 @@ static bool action_paste_files_error(void* data, u32 index, Result res) { return index < pasteData->pasteInfo.total - 1; } -static void action_paste_files_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { - paste_files_data* pasteData = (paste_files_data*) data; - - if(pasteData->currSrc != NULL) { - ui_draw_file_info(view, ((paste_files_data*) data)->currSrc->data, x1, y1, x2, y2); - } else if(pasteData->target != NULL) { - ui_draw_file_info(view, ((paste_files_data*) data)->target, x1, y1, x2, y2); - } -} - static void action_paste_files_free_data(paste_files_data* data) { - if(data->currSrc != NULL) { - task_free_file(data->currSrc); - data->currSrc = NULL; - } - - util_free_contents(data->contents, data->pasteInfo.total); + task_clear_files(&data->contents); + linked_list_destroy(&data->contents); free(data); } -static int action_paste_files_compare(const void* p1, const void* p2) { - list_item* info1 = (list_item*) p1; - list_item* info2 = (list_item*) p2; +static int action_paste_files_compare(const void** p1, const void** p2) { + list_item* info1 = *(list_item**) p1; + list_item* info2 = *(list_item**) p2; file_info* f1 = (file_info*) info1->data; file_info* f2 = (file_info*) info2->data; - return strcasecmp(f1->name, f2->name); + if(f1->isDirectory && !f2->isDirectory) { + return -1; + } else if(!f1->isDirectory && f2->isDirectory) { + return 1; + } else { + return strcasecmp(f1->name, f2->name); + } } static void action_paste_files_update(ui_view* view, void* data, float* progress, char* text) { paste_files_data* pasteData = (paste_files_data*) data; if(pasteData->pasteInfo.finished) { - if(pasteData->target->archive->id == ARCHIVE_USER_SAVEDATA) { - FSUSER_ControlArchive(*pasteData->target->archive, ARCHIVE_ACTION_COMMIT_SAVE_DATA, NULL, 0, NULL, 0); - } + FSUSER_ControlArchive(pasteData->target->archive, ARCHIVE_ACTION_COMMIT_SAVE_DATA, NULL, 0, NULL, 0); linked_list_sort(pasteData->items, action_paste_files_compare); ui_pop(); info_destroy(view); - if(!pasteData->pasteInfo.premature) { - prompt_display("Success", "Contents pasted.", COLOR_TEXT, false, pasteData->target, NULL, ui_draw_file_info, NULL); + if(R_SUCCEEDED(pasteData->pasteInfo.result)) { + prompt_display("Success", "Contents pasted.", COLOR_TEXT, false, NULL, NULL, NULL, NULL); } action_paste_files_free_data(pasteData); @@ -241,8 +235,8 @@ static void action_paste_files_update(ui_view* view, void* data, float* progress return; } - if(hidKeysDown() & KEY_B) { - svcSignalEvent(pasteData->cancelEvent); + if((hidKeysDown() & KEY_B) && !pasteData->pasteInfo.finished) { + svcSignalEvent(pasteData->pasteInfo.cancelEvent); } *progress = pasteData->pasteInfo.currTotal != 0 ? (float) ((double) pasteData->pasteInfo.currProcessed / (double) pasteData->pasteInfo.currTotal) : 0; @@ -252,18 +246,20 @@ static void action_paste_files_update(ui_view* view, void* data, float* progress static void action_paste_files_onresponse(ui_view* view, void* data, bool response) { paste_files_data* pasteData = (paste_files_data*) data; if(response) { - pasteData->cancelEvent = task_data_op(&pasteData->pasteInfo); - if(pasteData->cancelEvent != 0) { + Result res = task_data_op(&pasteData->pasteInfo); + if(R_SUCCEEDED(res)) { info_display("Pasting Contents", "Press B to cancel.", true, data, action_paste_files_update, action_paste_files_draw_top); } else { - error_display(NULL, pasteData->target, ui_draw_file_info, "Failed to initiate paste operation."); + error_display_res(NULL, pasteData->target, ui_draw_file_info, res, "Failed to initiate paste operation."); + + action_paste_files_free_data(pasteData); } } else { action_paste_files_free_data(pasteData); } } -void action_paste_contents(linked_list* items, list_item* selected, file_info* target) { +void action_paste_contents(linked_list* items, list_item* selected) { if(!clipboard_has_contents()) { prompt_display("Failure", "Clipboard empty.", COLOR_TEXT, false, NULL, NULL, NULL, NULL); return; @@ -277,9 +273,7 @@ void action_paste_contents(linked_list* items, list_item* selected, file_info* t } data->items = items; - data->target = target; - - data->currSrc = NULL; + data->target = (file_info*) selected->data; data->pasteInfo.data = data; @@ -301,15 +295,48 @@ void action_paste_contents(linked_list* items, list_item* selected, file_info* t data->pasteInfo.error = action_paste_files_error; - data->cancelEvent = 0; + list_item* clipboardItem = NULL; + Result createRes = 0; + if(R_FAILED(createRes = task_create_file_item(&clipboardItem, clipboard_get_archive(), clipboard_get_path()))) { + error_display_res(NULL, NULL, NULL, createRes, "Failed to retrieve clipboard content info."); - Result res = 0; - if(R_FAILED(res = util_populate_contents(&data->contents, &data->pasteInfo.total, clipboard_get_archive(), clipboard_get_path(), true, true, NULL, NULL))) { - error_display_res(NULL, data->target, ui_draw_file_info, res, "Failed to retrieve content list."); - - free(data); + action_paste_files_free_data(data); return; } + linked_list_init(&data->contents); + + populate_files_data popData; + popData.items = &data->contents; + popData.base = (file_info*) clipboardItem->data; + popData.recursive = true; + popData.includeBase = !clipboard_is_contents_only() || !util_is_dir(clipboard_get_archive(), clipboard_get_path()); + popData.dirsFirst = true; + + Result listRes = task_populate_files(&popData); + if(R_FAILED(listRes)) { + error_display_res(NULL, NULL, NULL, listRes, "Failed to initiate clipboard content list population."); + + task_free_file(clipboardItem); + action_paste_files_free_data(data); + return; + } + + while(!popData.finished) { + svcSleepThread(1000000); + } + + task_free_file(clipboardItem); + + if(R_FAILED(popData.result)) { + error_display_res(NULL, NULL, NULL, popData.result, "Failed to populate clipboard content list."); + + action_paste_files_free_data(data); + return; + } + + data->pasteInfo.total = linked_list_size(&data->contents); + data->pasteInfo.processed = data->pasteInfo.total; + prompt_display("Confirmation", "Paste clipboard contents to the current directory?", COLOR_TEXT, true, data, NULL, action_paste_files_draw_top, action_paste_files_onresponse); } \ No newline at end of file diff --git a/source/ui/section/dumpnand.c b/source/ui/section/dumpnand.c index 45b70a1..cfadf2c 100644 --- a/source/ui/section/dumpnand.c +++ b/source/ui/section/dumpnand.c @@ -11,11 +11,6 @@ #include "../ui.h" #include "../../core/screen.h" -typedef struct { - data_op_info dumpInfo; - Handle cancelEvent; -} dump_nand_data; - static Result dumpnand_is_src_directory(void* data, u32 index, bool* isDirectory) { *isDirectory = false; return 0; @@ -26,8 +21,7 @@ static Result dumpnand_make_dst_directory(void* data, u32 index) { } static Result dumpnand_open_src(void* data, u32 index, u32* handle) { - FS_Archive wnandArchive = {ARCHIVE_NAND_W_FS, fsMakePath(PATH_EMPTY, "")}; - return FSUSER_OpenFileDirectly(handle, wnandArchive, fsMakePath(PATH_UTF16, u"/"), FS_OPEN_READ, 0); + return FSUSER_OpenFileDirectly(handle, ARCHIVE_NAND_W_FS, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_UTF16, u"/"), FS_OPEN_READ, 0); } static Result dumpnand_close_src(void* data, u32 index, bool succeeded, u32 handle) { @@ -43,8 +37,7 @@ static Result dumpnand_read_src(void* data, u32 handle, u32* bytesRead, void* bu } static Result dumpnand_open_dst(void* data, u32 index, void* initialReadBlock, u32* handle) { - FS_Archive sdmcArchive = {ARCHIVE_SDMC, {PATH_BINARY, 0, (u8*) ""}}; - return FSUSER_OpenFileDirectly(handle, sdmcArchive, fsMakePath(PATH_UTF16, u"/NAND.bin"), FS_OPEN_WRITE | FS_OPEN_CREATE, 0); + return FSUSER_OpenFileDirectly(handle, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_UTF16, u"/NAND.bin"), FS_OPEN_WRITE | FS_OPEN_CREATE, 0); } static Result dumpnand_close_dst(void* data, u32 index, bool succeeded, u32 handle) { @@ -66,13 +59,13 @@ static bool dumpnand_error(void* data, u32 index, Result res) { } static void dumpnand_update(ui_view* view, void* data, float* progress, char* text) { - dump_nand_data* dumpData = (dump_nand_data*) data; + data_op_data* dumpData = (data_op_data*) data; - if(dumpData->dumpInfo.finished) { + if(dumpData->finished) { ui_pop(); info_destroy(view); - if(!dumpData->dumpInfo.premature) { + if(R_SUCCEEDED(dumpData->result)) { prompt_display("Success", "NAND dumped.", COLOR_TEXT, false, NULL, NULL, NULL, NULL); } @@ -85,19 +78,19 @@ static void dumpnand_update(ui_view* view, void* data, float* progress, char* te svcSignalEvent(dumpData->cancelEvent); } - *progress = dumpData->dumpInfo.currTotal != 0 ? (float) ((double) dumpData->dumpInfo.currProcessed / (double) dumpData->dumpInfo.currTotal) : 0; - snprintf(text, PROGRESS_TEXT_MAX, "%.2f MB / %.2f MB", dumpData->dumpInfo.currProcessed / 1024.0f / 1024.0f, dumpData->dumpInfo.currTotal / 1024.0f / 1024.0f); + *progress = dumpData->currTotal != 0 ? (float) ((double) dumpData->currProcessed / (double) dumpData->currTotal) : 0; + snprintf(text, PROGRESS_TEXT_MAX, "%.2f MB / %.2f MB", dumpData->currProcessed / 1024.0f / 1024.0f, dumpData->currTotal / 1024.0f / 1024.0f); } static void dumpnand_onresponse(ui_view* view, void* data, bool response) { if(response) { - dump_nand_data* dumpData = (dump_nand_data*) data; + data_op_data* dumpData = (data_op_data*) data; - dumpData->cancelEvent = task_data_op(&dumpData->dumpInfo); - if(dumpData->cancelEvent != 0) { + Result res = task_data_op(dumpData); + if(R_SUCCEEDED(res)) { info_display("Dumping NAND", "Press B to cancel.", true, data, dumpnand_update, NULL); } else { - error_display(NULL, NULL, NULL, "Failed to initiate NAND dump."); + error_display_res(NULL, NULL, NULL, res, "Failed to initiate NAND dump."); } } else { free(data); @@ -105,36 +98,34 @@ static void dumpnand_onresponse(ui_view* view, void* data, bool response) { } void dumpnand_open() { - dump_nand_data* data = (dump_nand_data*) calloc(1, sizeof(dump_nand_data)); + data_op_data* data = (data_op_data*) calloc(1, sizeof(data_op_data)); if(data == NULL) { error_display(NULL, NULL, NULL, "Failed to allocate dump NAND data."); return; } - data->dumpInfo.data = data; + data->data = data; - data->dumpInfo.op = DATAOP_COPY; + data->op = DATAOP_COPY; - data->dumpInfo.copyEmpty = true; + data->copyEmpty = true; - data->dumpInfo.total = 1; + data->total = 1; - data->dumpInfo.isSrcDirectory = dumpnand_is_src_directory; - data->dumpInfo.makeDstDirectory = dumpnand_make_dst_directory; + data->isSrcDirectory = dumpnand_is_src_directory; + data->makeDstDirectory = dumpnand_make_dst_directory; - data->dumpInfo.openSrc = dumpnand_open_src; - data->dumpInfo.closeSrc = dumpnand_close_src; - data->dumpInfo.getSrcSize = dumpnand_get_src_size; - data->dumpInfo.readSrc = dumpnand_read_src; + data->openSrc = dumpnand_open_src; + data->closeSrc = dumpnand_close_src; + data->getSrcSize = dumpnand_get_src_size; + data->readSrc = dumpnand_read_src; - data->dumpInfo.openDst = dumpnand_open_dst; - data->dumpInfo.closeDst = dumpnand_close_dst; - data->dumpInfo.writeDst = dumpnand_write_dst; + data->openDst = dumpnand_open_dst; + data->closeDst = dumpnand_close_dst; + data->writeDst = dumpnand_write_dst; - data->dumpInfo.error = dumpnand_error; - - data->cancelEvent = 0; + data->error = dumpnand_error; prompt_display("Confirmation", "Dump raw NAND image to the SD card?", COLOR_TEXT, true, data, NULL, NULL, dumpnand_onresponse); } \ No newline at end of file diff --git a/source/ui/section/extsavedata.c b/source/ui/section/extsavedata.c index 89b0bd2..4277f7f 100644 --- a/source/ui/section/extsavedata.c +++ b/source/ui/section/extsavedata.c @@ -17,7 +17,8 @@ static list_item browse_spotpass_save_data = {"Browse SpotPass Save Data", COLOR static list_item delete_save_data = {"Delete Save Data", COLOR_TEXT, action_delete_ext_save_data}; typedef struct { - Handle cancelEvent; + populate_ext_save_data_data populateData; + bool populated; } extsavedata_data; @@ -86,13 +87,11 @@ static void extsavedata_update(ui_view* view, void* data, linked_list* items, li extsavedata_data* listData = (extsavedata_data*) data; if(hidKeysDown() & KEY_B) { - if(listData->cancelEvent != 0) { - svcSignalEvent(listData->cancelEvent); - while(svcWaitSynchronization(listData->cancelEvent, 0) == 0) { + if(!listData->populateData.finished) { + svcSignalEvent(listData->populateData.cancelEvent); + while(!listData->populateData.finished) { svcSleepThread(1000000); } - - listData->cancelEvent = 0; } ui_pop(); @@ -105,19 +104,28 @@ static void extsavedata_update(ui_view* view, void* data, linked_list* items, li } if(!listData->populated || (hidKeysDown() & KEY_X)) { - if(listData->cancelEvent != 0) { - svcSignalEvent(listData->cancelEvent); - while(svcWaitSynchronization(listData->cancelEvent, 0) == 0) { + if(!listData->populateData.finished) { + svcSignalEvent(listData->populateData.cancelEvent); + while(!listData->populateData.finished) { svcSleepThread(1000000); } - - listData->cancelEvent = 0; } - listData->cancelEvent = task_populate_ext_save_data(items); + listData->populateData.items = items; + Result res = task_populate_ext_save_data(&listData->populateData); + if(R_FAILED(res)) { + error_display_res(NULL, NULL, NULL, res, "Failed to initiate ext save data list population."); + } + listData->populated = true; } + if(listData->populateData.finished && R_FAILED(listData->populateData.result)) { + listData->populateData.result = 0; + + error_display_res(NULL, NULL, NULL, listData->populateData.result, "Failed to populate ext save data list."); + } + if(selected != NULL && selected->data != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) { extsavedata_action_open(items, selected); return; @@ -132,5 +140,7 @@ void extsavedata_open() { return; } + data->populateData.finished = true; + list_display("Ext Save Data", "A: Select, B: Return, X: Refresh", data, extsavedata_update, extsavedata_draw_top); } \ No newline at end of file diff --git a/source/ui/section/files.c b/source/ui/section/files.c index 2125d61..fcff82b 100644 --- a/source/ui/section/files.c +++ b/source/ui/section/files.c @@ -6,18 +6,20 @@ #include "section.h" #include "action/action.h" +#include "action/clipboard.h" #include "task/task.h" #include "../error.h" #include "../list.h" +#include "../prompt.h" #include "../ui.h" #include "../../core/linkedlist.h" #include "../../core/screen.h" #include "../../core/util.h" -static list_item copy = {"Copy", COLOR_TEXT, action_copy_content}; +static list_item copy = {"Copy", COLOR_TEXT, NULL}; static list_item paste = {"Paste", COLOR_TEXT, action_paste_contents}; -static list_item delete_file = {"Delete", COLOR_TEXT, action_delete_contents}; +static list_item delete_file = {"Delete", COLOR_TEXT, action_delete_file}; static list_item install_cia = {"Install CIA", COLOR_TEXT, action_install_cia}; static list_item install_and_delete_cia = {"Install and delete CIA", COLOR_TEXT, action_install_cia_delete}; @@ -27,7 +29,7 @@ static list_item install_and_delete_ticket = {"Install and delete ticket", COLOR static list_item delete_dir = {"Delete", COLOR_TEXT, action_delete_dir}; static list_item delete_all_contents = {"Delete all contents", COLOR_TEXT, action_delete_dir_contents}; -static list_item copy_all_contents = {"Copy all contents", COLOR_TEXT, action_copy_contents}; +static list_item copy_all_contents = {"Copy all contents", COLOR_TEXT, NULL}; static list_item install_all_cias = {"Install all CIAs", COLOR_TEXT, action_install_cias}; static list_item install_and_delete_all_cias = {"Install and delete all CIAs", COLOR_TEXT, action_install_cias_delete}; @@ -38,25 +40,26 @@ static list_item install_and_delete_all_tickets = {"Install and delete all ticke static list_item delete_all_tickets = {"Delete all tickets", COLOR_TEXT, action_delete_dir_tickets}; typedef struct { - Handle cancelEvent; + populate_files_data populateData; + bool populated; + FS_ArchiveID archiveId; + FS_Path archivePath; FS_Archive archive; - void* archivePath; - file_info currDir; - file_info parentDir; + char currDir[FILE_PATH_MAX]; + list_item* dirItem; } files_data; typedef struct { linked_list* items; list_item* selected; - - file_info* target; + files_data* parent; } files_action_data; static void files_action_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { - ui_draw_file_info(view, ((files_action_data*) data)->target, x1, y1, x2, y2); + ui_draw_file_info(view, ((files_action_data*) data)->selected->data, x1, y1, x2, y2); } static void files_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { @@ -71,13 +74,24 @@ static void files_action_update(ui_view* view, void* data, linked_list* items, l return; } - if(selected != NULL && selected->data != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) { - void(*action)(linked_list*, list_item*, file_info*) = (void(*)(linked_list*, list_item*, file_info*)) selected->data; + if(selected != NULL && (selected->data != NULL || selected == © || selected == ©_all_contents) && (selectedTouched || (hidKeysDown() & KEY_A))) { + void(*action)(linked_list*, list_item*) = (void(*)(linked_list*, list_item*)) selected->data; ui_pop(); list_destroy(view); - action(actionData->items, actionData->selected, actionData->target); + if(selected == © || selected == ©_all_contents) { + file_info* info = (file_info*) actionData->selected->data; + + Result res = 0; + if(R_SUCCEEDED(res = clipboard_set_contents(actionData->parent->archiveId, &actionData->parent->archivePath, info->path, selected == ©_all_contents))) { + prompt_display("Success", selected == ©_all_contents ? "Current directory contents copied to clipboard." : info->isDirectory ? "Current directory copied to clipboard." : "File copied to clipboard.", COLOR_TEXT, false, info, NULL, ui_draw_file_info, NULL); + } else { + error_display_res(NULL, info, ui_draw_file_info, res, "Failed to copy to clipboard."); + } + } else { + action(actionData->items, actionData->selected); + } free(data); @@ -85,14 +99,16 @@ static void files_action_update(ui_view* view, void* data, linked_list* items, l } if(linked_list_size(items) == 0) { - if(actionData->target->isDirectory) { - if(actionData->target->containsCias) { + file_info* info = (file_info*) actionData->selected->data; + + if(info->isDirectory) { + if(info->containsCias) { linked_list_add(items, &install_all_cias); linked_list_add(items, &install_and_delete_all_cias); linked_list_add(items, &delete_all_cias); } - if(actionData->target->containsTickets) { + if(info->containsTickets) { linked_list_add(items, &install_all_tickets); linked_list_add(items, &install_and_delete_all_tickets); linked_list_add(items, &delete_all_tickets); @@ -103,12 +119,12 @@ static void files_action_update(ui_view* view, void* data, linked_list* items, l linked_list_add(items, &delete_dir); } else { - if(actionData->target->isCia) { + if(info->isCia) { linked_list_add(items, &install_cia); linked_list_add(items, &install_and_delete_cia); } - if(actionData->target->isTicket) { + if(info->isTicket) { linked_list_add(items, &install_ticket); linked_list_add(items, &install_and_delete_ticket); } @@ -121,7 +137,7 @@ static void files_action_update(ui_view* view, void* data, linked_list* items, l } } -static void files_action_open(linked_list* items, list_item* selected, file_info* target) { +static void files_action_open(linked_list* items, list_item* selected, files_data* parent) { files_action_data* data = (files_action_data*) calloc(1, sizeof(files_action_data)); if(data == NULL) { error_display(NULL, NULL, NULL, "Failed to allocate files action data."); @@ -131,10 +147,9 @@ static void files_action_open(linked_list* items, list_item* selected, file_info data->items = items; data->selected = selected; + data->parent = parent; - data->target = target; - - list_display(target->isDirectory ? "Directory Action" : "File Action", "A: Select, B: Return", data, files_action_update, files_action_draw_top); + list_display(((file_info*) selected->data)->isDirectory ? "Directory Action" : "File Action", "A: Select, B: Return", data, files_action_update, files_action_draw_top); } static void files_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { @@ -144,91 +159,105 @@ static void files_draw_top(ui_view* view, void* data, float x1, float y1, float } static void files_repopulate(files_data* listData, linked_list* items) { - if(listData->cancelEvent != 0) { - svcSignalEvent(listData->cancelEvent); - while(svcWaitSynchronization(listData->cancelEvent, 0) == 0) { + if(!listData->populateData.finished) { + svcSignalEvent(listData->populateData.cancelEvent); + while(!listData->populateData.finished) { svcSleepThread(1000000); } - - listData->cancelEvent = 0; } - while(!util_is_dir(&listData->archive, listData->currDir.path)) { - char parentPath[FILE_PATH_MAX]; - - util_get_parent_path(parentPath, listData->currDir.path, FILE_PATH_MAX); - strncpy(listData->currDir.path, parentPath, FILE_PATH_MAX); - util_get_path_file(listData->currDir.name, listData->currDir.path, FILE_NAME_MAX); - - util_get_parent_path(parentPath, listData->currDir.path, FILE_PATH_MAX); - strncpy(listData->parentDir.path, parentPath, FILE_PATH_MAX); - util_get_path_file(listData->parentDir.name, listData->parentDir.path, FILE_NAME_MAX); + if(listData->dirItem != NULL) { + task_free_file(listData->dirItem); + listData->dirItem = NULL; + } + + Result res = 0; + if(R_SUCCEEDED(res = task_create_file_item(&listData->dirItem, listData->archive, listData->currDir))) { + listData->populateData.items = items; + listData->populateData.base = (file_info*) listData->dirItem->data; + + res = task_populate_files(&listData->populateData); + } + + if(R_FAILED(res)) { + error_display_res(NULL, NULL, NULL, res, "Failed to initiate file list population."); } - listData->cancelEvent = task_populate_files(items, &listData->currDir); listData->populated = true; } static void files_navigate(files_data* listData, linked_list* items, const char* path) { - strncpy(listData->currDir.path, path, FILE_PATH_MAX); - util_get_path_file(listData->currDir.name, listData->currDir.path, FILE_NAME_MAX); + strncpy(listData->currDir, path, FILE_PATH_MAX); - char parentPath[FILE_PATH_MAX]; - util_get_parent_path(parentPath, listData->currDir.path, FILE_PATH_MAX); - strncpy(listData->parentDir.path, parentPath, FILE_PATH_MAX); - util_get_path_file(listData->parentDir.name, listData->parentDir.path, FILE_NAME_MAX); + listData->populated = false; +} - files_repopulate(listData, items); +static void files_free_data(files_data* data) { + if(!data->populateData.finished) { + svcSignalEvent(data->populateData.cancelEvent); + while(!data->populateData.finished) { + svcSleepThread(1000000); + } + } + + if(data->dirItem != NULL) { + task_free_file(data->dirItem); + data->dirItem = NULL; + } + + if(data->archive != 0) { + FSUSER_CloseArchive(data->archive); + data->archive = 0; + } + + if(data->archivePath.data != NULL) { + free((void*) data->archivePath.data); + data->archivePath.data = NULL; + } + + free(data); } static void files_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { files_data* listData = (files_data*) data; + while(!util_is_dir(listData->archive, listData->currDir)) { + char parentDir[FILE_PATH_MAX] = {'\0'}; + util_get_parent_path(parentDir, listData->currDir, FILE_PATH_MAX); + + files_navigate(listData, items, parentDir); + } + if(hidKeysDown() & KEY_B) { - if(strcmp(listData->currDir.path, "/") == 0) { - if(listData->archive.handle != 0) { - FSUSER_CloseArchive(&listData->archive); - listData->archive.handle = 0; - } - - if(listData->archivePath != NULL) { - free(listData->archivePath); - listData->archivePath = NULL; - } - - if(listData->cancelEvent != 0) { - svcSignalEvent(listData->cancelEvent); - while(svcWaitSynchronization(listData->cancelEvent, 0) == 0) { - svcSleepThread(1000000); - } - - listData->cancelEvent = 0; - } - + if(strncmp(listData->currDir, "/", FILE_PATH_MAX) == 0) { ui_pop(); + files_free_data(listData); + task_clear_files(items); list_destroy(view); - free(listData); return; } else { - files_navigate(listData, items, listData->parentDir.path); + char parentDir[FILE_PATH_MAX] = {'\0'}; + util_get_parent_path(parentDir, listData->currDir, FILE_PATH_MAX); + + files_navigate(listData, items, parentDir); } } - if(hidKeysDown() & KEY_Y) { - files_action_open(items, selected, &listData->currDir); + if((hidKeysDown() & KEY_Y) && listData->dirItem != NULL) { + files_action_open(items, listData->dirItem, listData); return; } if(selected != NULL && selected->data != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) { file_info* fileInfo = (file_info*) selected->data; - if(util_is_dir(&listData->archive, fileInfo->path)) { + if(fileInfo->isDirectory) { files_navigate(listData, items, fileInfo->path); } else { - files_action_open(items, selected, fileInfo); + files_action_open(items, selected, listData); return; } } @@ -236,9 +265,15 @@ static void files_update(ui_view* view, void* data, linked_list* items, list_ite if(!listData->populated || (hidKeysDown() & KEY_X)) { files_repopulate(listData, items); } + + if(listData->populateData.finished && R_FAILED(listData->populateData.result)) { + listData->populateData.result = 0; + + error_display_res(NULL, NULL, NULL, listData->populateData.result, "Failed to populate file list."); + } } -void files_open(FS_Archive archive) { +void files_open(FS_ArchiveID archiveId, FS_Path archivePath) { files_data* data = (files_data*) calloc(1, sizeof(files_data)); if(data == NULL) { error_display(NULL, NULL, NULL, "Failed to allocate files data."); @@ -246,69 +281,61 @@ void files_open(FS_Archive archive) { return; } - data->archive = archive; + data->populateData.recursive = false; + data->populateData.includeBase = false; + data->populateData.dirsFirst = true; - if(data->archive.lowPath.size > 0) { - data->archivePath = calloc(1, data->archive.lowPath.size); - if(data->archivePath == NULL) { - error_display(NULL, NULL, NULL, "Failed to allocate files archive."); + data->populateData.finished = true; - free(data); + data->populated = false; + + data->archiveId = archiveId; + data->archivePath.type = archivePath.type; + data->archivePath.size = archivePath.size; + if(archivePath.data != NULL) { + data->archivePath.data = calloc(1, data->archivePath.size); + if(data->archivePath.data == NULL) { + error_display(NULL, NULL, NULL, "Failed to allocate files data."); + + files_free_data(data); return; } - memcpy(data->archivePath, data->archive.lowPath.data, data->archive.lowPath.size); - data->archive.lowPath.data = data->archivePath; + memcpy((void*) data->archivePath.data, archivePath.data, data->archivePath.size); + } else { + data->archivePath.data = NULL; } - data->archive.handle = 0; + snprintf(data->currDir, FILE_PATH_MAX, "/"); + data->dirItem = NULL; Result res = 0; - if(R_FAILED(res = FSUSER_OpenArchive(&data->archive))) { + if(R_FAILED(res = FSUSER_OpenArchive(&data->archive, archiveId, archivePath))) { error_display_res(NULL, NULL, NULL, res, "Failed to open file listing archive."); - if(data->archivePath != NULL) { - free(data->archivePath); - } - - free(data); + files_free_data(data); return; } - data->currDir.archive = &data->archive; - snprintf(data->currDir.path, FILE_PATH_MAX, "/"); - util_get_path_file(data->currDir.name, data->currDir.path, FILE_NAME_MAX); - data->currDir.isDirectory = true; - data->currDir.containsCias = false; - data->currDir.size = 0; - data->currDir.isCia = false; - - memcpy(&data->parentDir, &data->currDir, sizeof(data->parentDir)); - list_display("Files", "A: Select, B: Back, X: Refresh, Y: Directory Action", data, files_update, files_draw_top); } void files_open_sd() { - FS_Archive sdmcArchive = {ARCHIVE_SDMC, {PATH_BINARY, 0, (void*) ""}}; - files_open(sdmcArchive); + files_open(ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, "")); } void files_open_ctr_nand() { - FS_Archive ctrNandArchive = {ARCHIVE_NAND_CTR_FS, fsMakePath(PATH_EMPTY, "")}; - files_open(ctrNandArchive); + files_open(ARCHIVE_NAND_CTR_FS, fsMakePath(PATH_EMPTY, "")); } void files_open_twl_nand() { - FS_Archive twlNandArchive = {ARCHIVE_NAND_TWL_FS, fsMakePath(PATH_EMPTY, "")}; - files_open(twlNandArchive); + files_open(ARCHIVE_NAND_TWL_FS, fsMakePath(PATH_EMPTY, "")); } void files_open_twl_photo() { - FS_Archive twlPhotoArchive = {ARCHIVE_TWL_PHOTO, fsMakePath(PATH_EMPTY, "")}; - files_open(twlPhotoArchive); + files_open(ARCHIVE_TWL_PHOTO, fsMakePath(PATH_EMPTY, "")); } void files_open_twl_sound() { - FS_Archive twlSoundArchive = {ARCHIVE_TWL_SOUND, {PATH_EMPTY, 0, ""}}; - files_open(twlSoundArchive); + files_open(ARCHIVE_TWL_SOUND, fsMakePath(PATH_EMPTY, "")); } \ No newline at end of file diff --git a/source/ui/section/networkinstall.c b/source/ui/section/networkinstall.c index c4ef504..b319982 100644 --- a/source/ui/section/networkinstall.c +++ b/source/ui/section/networkinstall.c @@ -22,8 +22,7 @@ typedef struct { u64 currTitleId; bool ticket; - data_op_info installInfo; - Handle cancelEvent; + data_op_data installInfo; } network_install_data; static int recvwait(int sockfd, void* buf, size_t len, int flags) { @@ -174,8 +173,6 @@ static bool networkinstall_error(void* data, u32 index, Result res) { prompt_display("Failure", "Install cancelled.", COLOR_TEXT, false, NULL, NULL, NULL, NULL); } else if(res == R_FBI_ERRNO) { error_display_errno(NULL, NULL, NULL, errno, "Failed to install over the network."); - } else if(res == R_FBI_WRONG_SYSTEM) { - error_display(NULL, NULL, NULL, "Failed to install over the network.\nAttempted to install N3DS title to O3DS."); } else { error_display_res(NULL, NULL, NULL, res, "Failed to install over the network."); } @@ -190,7 +187,6 @@ static void networkinstall_close_client(network_install_data* data) { close(data->clientSocket); data->currTitleId = 0; - data->cancelEvent = 0; } static void networkinstall_install_update(ui_view* view, void* data, float* progress, char* text) { @@ -202,15 +198,15 @@ static void networkinstall_install_update(ui_view* view, void* data, float* prog ui_pop(); info_destroy(view); - if(!networkInstallData->installInfo.premature) { + if(R_SUCCEEDED(networkInstallData->installInfo.result)) { prompt_display("Success", "Install finished.", COLOR_TEXT, false, data, NULL, NULL, NULL); } return; } - if(hidKeysDown() & KEY_B) { - svcSignalEvent(networkInstallData->cancelEvent); + if((hidKeysDown() & KEY_B) && !networkInstallData->installInfo.finished) { + svcSignalEvent(networkInstallData->installInfo.cancelEvent); } *progress = networkInstallData->installInfo.currTotal != 0 ? (float) ((double) networkInstallData->installInfo.currProcessed / (double) networkInstallData->installInfo.currTotal) : 0; @@ -221,11 +217,11 @@ static void networkinstall_confirm_onresponse(ui_view* view, void* data, bool re network_install_data* networkInstallData = (network_install_data*) data; if(response) { - networkInstallData->cancelEvent = task_data_op(&networkInstallData->installInfo); - if(networkInstallData->cancelEvent != 0) { - info_display("Installing Over Network", "Press B to cancel.", true, data, networkinstall_install_update, NULL); + Result res = task_data_op(&networkInstallData->installInfo); + if(R_SUCCEEDED(res)) { + info_display("Installing Received Files", "Press B to cancel.", true, data, networkinstall_install_update, NULL); } else { - error_display(NULL, NULL, NULL, "Failed to initiate installation."); + error_display_res(NULL, NULL, NULL, res, "Failed to initiate installation."); networkinstall_close_client(networkInstallData); } @@ -339,7 +335,5 @@ void networkinstall_open() { data->installInfo.error = networkinstall_error; - data->cancelEvent = 0; - info_display("Network Install", "B: Return", false, data, networkinstall_wait_update, NULL); } diff --git a/source/ui/section/pendingtitles.c b/source/ui/section/pendingtitles.c index bd45bef..f753635 100644 --- a/source/ui/section/pendingtitles.c +++ b/source/ui/section/pendingtitles.c @@ -16,7 +16,8 @@ static list_item delete_pending_title = {"Delete Pending Title", COLOR_TEXT, act static list_item delete_all_pending_titles = {"Delete All Pending Titles", COLOR_TEXT, action_delete_all_pending_titles}; typedef struct { - Handle cancelEvent; + populate_pending_titles_data populateData; + bool populated; } pendingtitles_data; @@ -84,13 +85,11 @@ static void pendingtitles_update(ui_view* view, void* data, linked_list* items, pendingtitles_data* listData = (pendingtitles_data*) data; if(hidKeysDown() & KEY_B) { - if(listData->cancelEvent != 0) { - svcSignalEvent(listData->cancelEvent); - while(svcWaitSynchronization(listData->cancelEvent, 0) == 0) { + if(!listData->populateData.finished) { + svcSignalEvent(listData->populateData.cancelEvent); + while(!listData->populateData.finished) { svcSleepThread(1000000); } - - listData->cancelEvent = 0; } ui_pop(); @@ -103,19 +102,28 @@ static void pendingtitles_update(ui_view* view, void* data, linked_list* items, } if(!listData->populated || (hidKeysDown() & KEY_X)) { - if(listData->cancelEvent != 0) { - svcSignalEvent(listData->cancelEvent); - while(svcWaitSynchronization(listData->cancelEvent, 0) == 0) { + if(!listData->populateData.finished) { + svcSignalEvent(listData->populateData.cancelEvent); + while(!listData->populateData.finished) { svcSleepThread(1000000); } - - listData->cancelEvent = 0; } - listData->cancelEvent = task_populate_pending_titles(items); + listData->populateData.items = items; + Result res = task_populate_pending_titles(&listData->populateData); + if(R_FAILED(res)) { + error_display_res(NULL, NULL, NULL, res, "Failed to initiate pending title list population."); + } + listData->populated = true; } + if(listData->populateData.finished && R_FAILED(listData->populateData.result)) { + listData->populateData.result = 0; + + error_display_res(NULL, NULL, NULL, listData->populateData.result, "Failed to populate pending title list."); + } + if(selected != NULL && selected->data != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) { pendingtitles_action_open(items, selected); return; @@ -130,5 +138,7 @@ void pendingtitles_open() { return; } + data->populateData.finished = true; + list_display("Pending Titles", "A: Select, B: Return, X: Refresh", data, pendingtitles_update, pendingtitles_draw_top); } \ No newline at end of file diff --git a/source/ui/section/qrinstall.c b/source/ui/section/qrinstall.c index 6ad24b6..d7d7413 100644 --- a/source/ui/section/qrinstall.c +++ b/source/ui/section/qrinstall.c @@ -23,17 +23,14 @@ typedef struct { struct quirc* qrContext; char urls[URLS_MAX][URL_MAX]; - Handle mutex; - u16* buffer; u32 tex; - Handle camCancelEvent; u32 responseCode; u64 currTitleId; bool ticket; - data_op_info installInfo; - Handle installCancelEvent; + capture_cam_data captureInfo; + data_op_data installInfo; } qr_install_data; static Result qrinstall_is_src_directory(void* data, u32 index, bool* isDirectory) { @@ -182,13 +179,7 @@ static bool qrinstall_error(void* data, u32 index, Result res) { char* url = qrInstallData->urls[index]; volatile bool dismissed = false; - if(res == R_FBI_WRONG_SYSTEM) { - if(strlen(url) > 48) { - error_display(&dismissed, NULL, NULL, "Failed to install from QR code.\n%.45s...\nAttempted to install N3DS title to O3DS.", url); - } else { - error_display(&dismissed, NULL, NULL, "Failed to install from QR code.\n%.48s\nAttempted to install N3DS title to O3DS.", url); - } - } else if(res == R_FBI_HTTP_RESPONSE_CODE) { + if(res == R_FBI_HTTP_RESPONSE_CODE) { if(strlen(url) > 48) { error_display(&dismissed, NULL, NULL, "Failed to install from QR code.\n%.45s...\nHTTP server returned response code %d", url, qrInstallData->responseCode); } else { @@ -217,7 +208,7 @@ static void qrinstall_install_update(ui_view* view, void* data, float* progress, ui_pop(); info_destroy(view); - if(!qrInstallData->installInfo.premature) { + if(R_SUCCEEDED(qrInstallData->installInfo.result)) { prompt_display("Success", "Install finished.", COLOR_TEXT, false, data, NULL, NULL, NULL); } @@ -225,7 +216,7 @@ static void qrinstall_install_update(ui_view* view, void* data, float* progress, } if(hidKeysDown() & KEY_B) { - svcSignalEvent(qrInstallData->installCancelEvent); + svcSignalEvent(qrInstallData->installInfo.cancelEvent); } *progress = qrInstallData->installInfo.currTotal != 0 ? (float) ((double) qrInstallData->installInfo.currProcessed / (double) qrInstallData->installInfo.currTotal) : 0; @@ -236,33 +227,26 @@ static void qrinstall_confirm_onresponse(ui_view* view, void* data, bool respons qr_install_data* qrInstallData = (qr_install_data*) data; if(response) { - qrInstallData->installCancelEvent = task_data_op(&qrInstallData->installInfo); - if(qrInstallData->installCancelEvent != 0) { + Result res = task_data_op(&qrInstallData->installInfo); + if(R_SUCCEEDED(res)) { info_display("Installing From QR Code", "Press B to cancel.", true, data, qrinstall_install_update, NULL); } else { - error_display(NULL, NULL, NULL, "Failed to initiate installation."); + error_display_res(NULL, NULL, NULL, res, "Failed to initiate installation."); } } } static void qrinstall_free_data(qr_install_data* data) { - if(data->camCancelEvent != 0) { - svcSignalEvent(data->camCancelEvent); - while(svcWaitSynchronization(data->camCancelEvent, 0) == 0) { + if(!data->installInfo.finished) { + svcSignalEvent(data->installInfo.cancelEvent); + while(!data->installInfo.finished) { svcSleepThread(1000000); } - - data->camCancelEvent = 0; } - if(data->qrContext != NULL) { - quirc_destroy(data->qrContext); - data->qrContext = NULL; - } - - if(data->buffer != NULL) { - free(data->buffer); - data->buffer = NULL; + if(data->captureInfo.buffer != NULL) { + free(data->captureInfo.buffer); + data->captureInfo.buffer = NULL; } if(data->tex != 0) { @@ -270,6 +254,11 @@ static void qrinstall_free_data(qr_install_data* data) { data->tex = 0; } + if(data->qrContext != NULL) { + quirc_destroy(data->qrContext); + data->qrContext = NULL; + } + free(data); } @@ -293,6 +282,19 @@ static void qrinstall_wait_update(ui_view* view, void* data, float* progress, ch return; } + if(qrInstallData->captureInfo.finished) { + ui_pop(); + info_destroy(view); + + if(R_FAILED(qrInstallData->captureInfo.result)) { + error_display_res(NULL, NULL, NULL, qrInstallData->captureInfo.result, "Error while capturing camera frames."); + } + + qrinstall_free_data(qrInstallData); + + return; + } + if(qrInstallData->tex != 0) { screen_unload_texture(qrInstallData->tex); qrInstallData->tex = 0; @@ -302,18 +304,18 @@ static void qrinstall_wait_update(ui_view* view, void* data, float* progress, ch int h = 0; uint8_t* qrBuf = quirc_begin(qrInstallData->qrContext, &w, &h); - svcWaitSynchronization(qrInstallData->mutex, U64_MAX); + svcWaitSynchronization(qrInstallData->captureInfo.mutex, U64_MAX); - qrInstallData->tex = screen_load_texture_auto(qrInstallData->buffer, IMAGE_WIDTH * IMAGE_HEIGHT * sizeof(u16), IMAGE_WIDTH, IMAGE_HEIGHT, GPU_RGB565, false); + qrInstallData->tex = screen_load_texture_auto(qrInstallData->captureInfo.buffer, IMAGE_WIDTH * IMAGE_HEIGHT * sizeof(u16), IMAGE_WIDTH, IMAGE_HEIGHT, GPU_RGB565, false); for(int x = 0; x < w; x++) { for(int y = 0; y < h; y++) { - u16 px = qrInstallData->buffer[y * IMAGE_WIDTH + x]; + u16 px = qrInstallData->captureInfo.buffer[y * IMAGE_WIDTH + x]; qrBuf[y * w + x] = (u8) (((((px >> 11) & 0x1F) << 3) + (((px >> 5) & 0x3F) << 2) + ((px & 0x1F) << 3)) / 3); } } - svcReleaseMutex(qrInstallData->mutex); + svcReleaseMutex(qrInstallData->captureInfo.mutex); quirc_end(qrInstallData->qrContext); @@ -375,17 +377,19 @@ void qrinstall_open() { return; } - data->buffer = (u16*) calloc(1, IMAGE_WIDTH * IMAGE_HEIGHT * sizeof(u16)); - if(data->buffer == NULL) { + data->captureInfo.width = IMAGE_WIDTH; + data->captureInfo.height = IMAGE_HEIGHT; + data->captureInfo.buffer = (u16*) calloc(1, IMAGE_WIDTH * IMAGE_HEIGHT * sizeof(u16)); + if(data->captureInfo.buffer == NULL) { error_display(NULL, NULL, NULL, "Failed to create image buffer."); qrinstall_free_data(data); return; } - data->camCancelEvent = task_capture_cam(&data->mutex, data->buffer, IMAGE_WIDTH, IMAGE_HEIGHT); - if(data->camCancelEvent == 0) { - error_display(NULL, NULL, NULL, "Failed to start camera capture."); + Result capRes = task_capture_cam(&data->captureInfo); + if(R_FAILED(capRes)) { + error_display_res(NULL, NULL, NULL, capRes, "Failed to start camera capture."); qrinstall_free_data(data); return; @@ -419,7 +423,5 @@ void qrinstall_open() { data->installInfo.error = qrinstall_error; - data->installCancelEvent = 0; - info_display("QR Code Install", "B: Return", false, data, qrinstall_wait_update, qrinstall_wait_draw_top); } diff --git a/source/ui/section/section.h b/source/ui/section/section.h index ea28975..bc90e9e 100644 --- a/source/ui/section/section.h +++ b/source/ui/section/section.h @@ -2,7 +2,7 @@ void dumpnand_open(); void extsavedata_open(); -void files_open(FS_Archive archive); +void files_open(FS_ArchiveID archiveId, FS_Path archivePath); void files_open_sd(); void files_open_ctr_nand(); void files_open_twl_nand(); diff --git a/source/ui/section/systemsavedata.c b/source/ui/section/systemsavedata.c index 95d4320..39f7479 100644 --- a/source/ui/section/systemsavedata.c +++ b/source/ui/section/systemsavedata.c @@ -16,7 +16,8 @@ static list_item browse_save_data = {"Browse Save Data", COLOR_TEXT, action_brow static list_item delete_save_data = {"Delete Save Data", COLOR_TEXT, action_delete_system_save_data}; typedef struct { - Handle cancelEvent; + populate_system_save_data_data populateData; + bool populated; } systemsavedata_data; @@ -84,13 +85,11 @@ static void systemsavedata_update(ui_view* view, void* data, linked_list* items, systemsavedata_data* listData = (systemsavedata_data*) data; if(hidKeysDown() & KEY_B) { - if(listData->cancelEvent != 0) { - svcSignalEvent(listData->cancelEvent); - while(svcWaitSynchronization(listData->cancelEvent, 0) == 0) { + if(!listData->populateData.finished) { + svcSignalEvent(listData->populateData.cancelEvent); + while(!listData->populateData.finished) { svcSleepThread(1000000); } - - listData->cancelEvent = 0; } ui_pop(); @@ -103,19 +102,28 @@ static void systemsavedata_update(ui_view* view, void* data, linked_list* items, } if(!listData->populated || (hidKeysDown() & KEY_X)) { - if(listData->cancelEvent != 0) { - svcSignalEvent(listData->cancelEvent); - while(svcWaitSynchronization(listData->cancelEvent, 0) == 0) { + if(!listData->populateData.finished) { + svcSignalEvent(listData->populateData.cancelEvent); + while(!listData->populateData.finished) { svcSleepThread(1000000); } - - listData->cancelEvent = 0; } - listData->cancelEvent = task_populate_system_save_data(items); + listData->populateData.items = items; + Result res = task_populate_system_save_data(&listData->populateData); + if(R_FAILED(res)) { + error_display_res(NULL, NULL, NULL, res, "Failed to initiate system save data list population."); + } + listData->populated = true; } + if(listData->populateData.finished && R_FAILED(listData->populateData.result)) { + listData->populateData.result = 0; + + error_display_res(NULL, NULL, NULL, listData->populateData.result, "Failed to populate system save data list."); + } + if(selected != NULL && selected->data != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) { systemsavedata_action_open(items, selected); return; @@ -130,5 +138,7 @@ void systemsavedata_open() { return; } + data->populateData.finished = true; + list_display("System Save Data", "A: Select, B: Return, X: Refresh", data, systemsavedata_update, systemsavedata_draw_top); } \ No newline at end of file diff --git a/source/ui/section/task/capturecam.c b/source/ui/section/task/capturecam.c index cf3751f..9421630 100644 --- a/source/ui/section/task/capturecam.c +++ b/source/ui/section/task/capturecam.c @@ -13,16 +13,6 @@ #define EVENT_COUNT 3 -typedef struct { - u16* buffer; - s16 width; - s16 height; - - Handle mutex; - - Handle cancelEvent; -} capture_cam_data; - static void task_capture_cam_thread(void* arg) { capture_cam_data* data = (capture_cam_data*) arg; @@ -109,10 +99,6 @@ static void task_capture_cam_thread(void* arg) { res = R_FBI_OUT_OF_MEMORY; } - if(R_FAILED(res)) { - error_display_res(NULL, NULL, NULL, res, "Error capturing camera image."); - } - for(int i = 0; i < EVENT_COUNT; i++) { if(events[i] != 0) { svcCloseHandle(events[i]); @@ -121,51 +107,41 @@ static void task_capture_cam_thread(void* arg) { } svcCloseHandle(data->mutex); - free(data); + + data->result = res; + data->finished = true; } -Handle task_capture_cam(Handle* mutex, u16* buffer, s16 width, s16 height) { - if(buffer == NULL || width <= 0 || width > 640 || height <= 0 || height > 480 || mutex == 0) { - return 0; +Result task_capture_cam(capture_cam_data* data) { + if(data == NULL || data->buffer == NULL || data->width <= 0 || data->width > 640 || data->height <= 0 || data->height > 480 || data->mutex == 0) { + return R_FBI_INVALID_ARGUMENT; } - capture_cam_data* data = (capture_cam_data*) calloc(1, sizeof(capture_cam_data)); - if(data == NULL) { - error_display(NULL, NULL, NULL, "Failed to allocate camera capture data."); - return 0; + data->mutex = 0; + + data->finished = false; + data->result = 0; + data->cancelEvent = 0; + + Result res = 0; + if(R_SUCCEEDED(res = svcCreateEvent(&data->cancelEvent, 1)) && R_SUCCEEDED(res = svcCreateMutex(&data->mutex, false))) { + if(threadCreate(task_capture_cam_thread, data, 0x10000, 0x19, 1, true) == NULL) { + res = R_FBI_THREAD_CREATE_FAILED; + } } - data->buffer = buffer; - data->width = width; - data->height = height; + if(R_FAILED(res)) { + if(data->cancelEvent != 0) { + svcCloseHandle(data->cancelEvent); + data->cancelEvent = 0; + } - Result eventRes = svcCreateEvent(&data->cancelEvent, 1); - if(R_FAILED(eventRes)) { - error_display_res(NULL, NULL, NULL, eventRes, "Failed to create camera capture cancel event."); - - free(data); - return 0; + if(data->mutex != 0) { + svcCloseHandle(data->mutex); + data->mutex = 0; + } } - Result mutexRes = svcCreateMutex(&data->mutex, false); - if(R_FAILED(mutexRes)) { - error_display_res(NULL, NULL, NULL, mutexRes, "Failed to create camera capture buffer mutex."); - - svcCloseHandle(data->cancelEvent); - free(data); - return 0; - } - - if(threadCreate(task_capture_cam_thread, data, 0x10000, 0x19, 1, true) == NULL) { - error_display(NULL, NULL, NULL, "Failed to create camera capture thread."); - - svcCloseHandle(data->mutex); - svcCloseHandle(data->cancelEvent); - free(data); - return 0; - } - - *mutex = data->mutex; - return data->cancelEvent; + return res; } \ No newline at end of file diff --git a/source/ui/section/task/dataop.c b/source/ui/section/task/dataop.c index 7e148e4..5a4a921 100644 --- a/source/ui/section/task/dataop.c +++ b/source/ui/section/task/dataop.c @@ -7,30 +7,24 @@ #include "../../list.h" #include "../../error.h" -typedef struct { - data_op_info* info; - - Handle cancelEvent; -} data_op_data; - static bool task_data_op_copy(data_op_data* data, u32 index) { - data->info->currProcessed = 0; - data->info->currTotal = 0; + data->currProcessed = 0; + data->currTotal = 0; Result res = 0; bool isDir = false; - if(R_SUCCEEDED(res = data->info->isSrcDirectory(data->info->data, index, &isDir)) && isDir) { - res = data->info->makeDstDirectory(data->info->data, index); + if(R_SUCCEEDED(res = data->isSrcDirectory(data->data, index, &isDir)) && isDir) { + res = data->makeDstDirectory(data->data, index); } else { u32 srcHandle = 0; - if(R_SUCCEEDED(res = data->info->openSrc(data->info->data, index, &srcHandle))) { - if(R_SUCCEEDED(res = data->info->getSrcSize(data->info->data, srcHandle, &data->info->currTotal))) { - if(data->info->currTotal == 0) { - if(data->info->copyEmpty) { + if(R_SUCCEEDED(res = data->openSrc(data->data, index, &srcHandle))) { + if(R_SUCCEEDED(res = data->getSrcSize(data->data, srcHandle, &data->currTotal))) { + if(data->currTotal == 0) { + if(data->copyEmpty) { u32 dstHandle = 0; - if(R_SUCCEEDED(res = data->info->openDst(data->info->data, index, NULL, &dstHandle))) { - res = data->info->closeDst(data->info->data, index, true, dstHandle); + if(R_SUCCEEDED(res = data->openDst(data->data, index, NULL, &dstHandle))) { + res = data->closeDst(data->data, index, true, dstHandle); } } } else { @@ -40,7 +34,7 @@ static bool task_data_op_copy(data_op_data* data, u32 index) { u32 dstHandle = 0; bool firstRun = true; - while(data->info->currProcessed < data->info->currTotal) { + while(data->currProcessed < data->currTotal) { svcWaitSynchronization(task_get_pause_event(), U64_MAX); if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) { res = R_FBI_CANCELLED; @@ -48,33 +42,33 @@ static bool task_data_op_copy(data_op_data* data, u32 index) { } u32 currSize = bufferSize; - if((u64) currSize > data->info->currTotal - data->info->currProcessed) { - currSize = (u32) (data->info->currTotal - data->info->currProcessed); + if((u64) currSize > data->currTotal - data->currProcessed) { + currSize = (u32) (data->currTotal - data->currProcessed); } u32 bytesRead = 0; u32 bytesWritten = 0; - if(R_FAILED(res = data->info->readSrc(data->info->data, srcHandle, &bytesRead, buffer, data->info->currProcessed, currSize))) { + if(R_FAILED(res = data->readSrc(data->data, srcHandle, &bytesRead, buffer, data->currProcessed, currSize))) { break; } if(firstRun) { firstRun = false; - if(R_FAILED(res = data->info->openDst(data->info->data, index, buffer, &dstHandle))) { + if(R_FAILED(res = data->openDst(data->data, index, buffer, &dstHandle))) { break; } } - if(R_FAILED(res = data->info->writeDst(data->info->data, dstHandle, &bytesWritten, buffer, data->info->currProcessed, currSize))) { + if(R_FAILED(res = data->writeDst(data->data, dstHandle, &bytesWritten, buffer, data->currProcessed, currSize))) { break; } - data->info->currProcessed += bytesWritten; + data->currProcessed += bytesWritten; } if(dstHandle != 0) { - Result closeDstRes = data->info->closeDst(data->info->data, index, res == 0, dstHandle); + Result closeDstRes = data->closeDst(data->data, index, res == 0, dstHandle); if(R_SUCCEEDED(res)) { res = closeDstRes; } @@ -87,7 +81,7 @@ static bool task_data_op_copy(data_op_data* data, u32 index) { } } - Result closeSrcRes = data->info->closeSrc(data->info->data, index, res == 0, srcHandle); + Result closeSrcRes = data->closeSrc(data->data, index, res == 0, srcHandle); if(R_SUCCEEDED(res)) { res = closeSrcRes; } @@ -95,7 +89,8 @@ static bool task_data_op_copy(data_op_data* data, u32 index) { } if(R_FAILED(res)) { - return data->info->error(data->info->data, index, res); + data->result = res; + return data->error(data->data, index, res); } return true; @@ -103,8 +98,8 @@ static bool task_data_op_copy(data_op_data* data, u32 index) { static bool task_data_op_delete(data_op_data* data, u32 index) { Result res = 0; - if(R_FAILED(res = data->info->delete(data->info->data, index))) { - return data->info->error(data->info->data, index, res); + if(R_FAILED(res = data->delete(data->data, index))) { + return data->error(data->data, index, res); } return true; @@ -113,78 +108,57 @@ static bool task_data_op_delete(data_op_data* data, u32 index) { static void task_data_op_thread(void* arg) { data_op_data* data = (data_op_data*) arg; - data->info->finished = false; - data->info->premature = false; - - data->info->processed = 0; - - for(data->info->processed = 0; data->info->processed < data->info->total; data->info->processed++) { + for(data->processed = 0; data->processed < data->total; data->processed++) { bool cont = false; - switch(data->info->op) { + switch(data->op) { case DATAOP_COPY: - cont = task_data_op_copy(data, data->info->processed); + cont = task_data_op_copy(data, data->processed); break; case DATAOP_DELETE: - cont = task_data_op_delete(data, data->info->processed); + cont = task_data_op_delete(data, data->processed); break; default: break; } if(!cont) { - data->info->premature = true; break; } } - data->info->finished = true; - svcCloseHandle(data->cancelEvent); - free(data); + + data->finished = true; } -static void task_data_op_reset_info(data_op_info* info) { - info->finished = false; - info->premature = false; - - info->processed = 0; - - info->currProcessed = 0; - info->currTotal = 0; -} - -Handle task_data_op(data_op_info* info) { - if(info == NULL) { - return 0; - } - - task_data_op_reset_info(info); - - data_op_data* data = (data_op_data*) calloc(1, sizeof(data_op_data)); +Result task_data_op(data_op_data* data) { if(data == NULL) { - error_display(NULL, NULL, NULL, "Failed to allocate data operation data."); - - return 0; + return R_FBI_INVALID_ARGUMENT; } - data->info = info; + data->processed = 0; - Result eventRes = svcCreateEvent(&data->cancelEvent, 1); - if(R_FAILED(eventRes)) { - error_display_res(NULL, NULL, NULL, eventRes, "Failed to create data operation cancel event."); + data->currProcessed = 0; + data->currTotal = 0; - free(data); - return 0; + data->finished = false; + data->result = 0; + data->cancelEvent = 0; + + Result res = 0; + if(R_SUCCEEDED(res = svcCreateEvent(&data->cancelEvent, 1))) { + if(threadCreate(task_data_op_thread, data, 0x10000, 0x18, 1, true) == NULL) { + res = R_FBI_THREAD_CREATE_FAILED; + } } - if(threadCreate(task_data_op_thread, data, 0x10000, 0x18, 1, true) == NULL) { - error_display(NULL, NULL, NULL, "Failed to create data operation thread."); - - svcCloseHandle(data->cancelEvent); - free(data); - return 0; + if(R_FAILED(res)) { + if(data->cancelEvent != 0) { + svcCloseHandle(data->cancelEvent); + data->cancelEvent = 0; + } } - return data->cancelEvent; + return res; } \ No newline at end of file diff --git a/source/ui/section/task/listextsavedata.c b/source/ui/section/task/listextsavedata.c index 0019ffb..bc4f251 100644 --- a/source/ui/section/task/listextsavedata.c +++ b/source/ui/section/task/listextsavedata.c @@ -14,11 +14,12 @@ #define MAX_EXT_SAVE_DATA 512 -typedef struct { - linked_list* items; +static int task_populate_ext_save_data_compare_ids(const void* e1, const void* e2) { + u64 id1 = *(u64*) e1; + u64 id2 = *(u64*) e2; - Handle cancelEvent; -} populate_ext_save_data_data; + return id1 > id2 ? 1 : id1 < id2 ? -1 : 0; +} static Result task_populate_ext_save_data_from(populate_ext_save_data_data* data, FS_MediaType mediaType) { Result res = 0; @@ -26,9 +27,8 @@ static Result task_populate_ext_save_data_from(populate_ext_save_data_data* data u32 extSaveDataCount = 0; u64 extSaveDataIds[MAX_EXT_SAVE_DATA]; if(R_SUCCEEDED(res = FSUSER_EnumerateExtSaveData(&extSaveDataCount, MAX_EXT_SAVE_DATA, mediaType, 8, mediaType == MEDIATYPE_NAND, (u8*) extSaveDataIds))) { - qsort(extSaveDataIds, extSaveDataCount, sizeof(u64), util_compare_u64); + qsort(extSaveDataIds, extSaveDataCount, sizeof(u64), task_populate_ext_save_data_compare_ids); - SMDH smdh; for(u32 i = 0; i < extSaveDataCount && R_SUCCEEDED(res); i++) { svcWaitSynchronization(task_get_pause_event(), U64_MAX); if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) { @@ -45,18 +45,26 @@ static Result task_populate_ext_save_data_from(populate_ext_save_data_data* data extSaveDataInfo->hasMeta = false; FS_ExtSaveDataInfo info = {.mediaType = mediaType, .saveId = extSaveDataIds[i]}; - u32 smdhBytesRead = 0; - if(R_SUCCEEDED(FSUSER_ReadExtSaveDataIcon(&smdhBytesRead, info, sizeof(SMDH), (u8*) &smdh)) && smdhBytesRead == sizeof(SMDH)) { - u8 systemLanguage = CFG_LANGUAGE_EN; - CFGU_GetSystemLanguage(&systemLanguage); - utf16_to_utf8((uint8_t*) item->name, smdh.titles[systemLanguage].shortDescription, LIST_ITEM_NAME_MAX - 1); + SMDH* smdh = (SMDH*) calloc(1, sizeof(SMDH)); + if(smdh != NULL) { + u32 smdhBytesRead = 0; + if(R_SUCCEEDED(FSUSER_ReadExtSaveDataIcon(&smdhBytesRead, info, sizeof(SMDH), (u8*) smdh)) && smdhBytesRead == sizeof(SMDH)) { + if(smdh->magic[0] == 'S' && smdh->magic[1] == 'M' && smdh->magic[2] == 'D' && smdh->magic[3] == 'H') { + u8 systemLanguage = CFG_LANGUAGE_EN; + CFGU_GetSystemLanguage(&systemLanguage); - extSaveDataInfo->hasMeta = true; - utf16_to_utf8((uint8_t*) extSaveDataInfo->meta.shortDescription, smdh.titles[systemLanguage].shortDescription, sizeof(extSaveDataInfo->meta.shortDescription) - 1); - utf16_to_utf8((uint8_t*) extSaveDataInfo->meta.longDescription, smdh.titles[systemLanguage].longDescription, sizeof(extSaveDataInfo->meta.longDescription) - 1); - utf16_to_utf8((uint8_t*) extSaveDataInfo->meta.publisher, smdh.titles[systemLanguage].publisher, sizeof(extSaveDataInfo->meta.publisher) - 1); - extSaveDataInfo->meta.texture = screen_load_texture_tiled_auto(smdh.largeIcon, sizeof(smdh.largeIcon), 48, 48, GPU_RGB565, false); + utf16_to_utf8((uint8_t*) item->name, smdh->titles[systemLanguage].shortDescription, LIST_ITEM_NAME_MAX - 1); + + extSaveDataInfo->hasMeta = true; + utf16_to_utf8((uint8_t*) extSaveDataInfo->meta.shortDescription, smdh->titles[systemLanguage].shortDescription, sizeof(extSaveDataInfo->meta.shortDescription) - 1); + utf16_to_utf8((uint8_t*) extSaveDataInfo->meta.longDescription, smdh->titles[systemLanguage].longDescription, sizeof(extSaveDataInfo->meta.longDescription) - 1); + utf16_to_utf8((uint8_t*) extSaveDataInfo->meta.publisher, smdh->titles[systemLanguage].publisher, sizeof(extSaveDataInfo->meta.publisher) - 1); + extSaveDataInfo->meta.texture = screen_load_texture_tiled_auto(smdh->largeIcon, sizeof(smdh->largeIcon), 48, 48, GPU_RGB565, false); + } + } + + free(smdh); } bool empty = strlen(item->name) == 0; @@ -105,12 +113,15 @@ static void task_populate_ext_save_data_thread(void* arg) { populate_ext_save_data_data* data = (populate_ext_save_data_data*) arg; Result res = 0; - if(R_FAILED(res = task_populate_ext_save_data_from(data, MEDIATYPE_SD)) || R_FAILED(res = task_populate_ext_save_data_from(data, MEDIATYPE_NAND))) { - error_display_res(NULL, NULL, NULL, res, "Failed to load ext save data listing."); + + if(R_SUCCEEDED(res = task_populate_ext_save_data_from(data, MEDIATYPE_SD))) { + res = task_populate_ext_save_data_from(data, MEDIATYPE_NAND); } svcCloseHandle(data->cancelEvent); - free(data); + + data->result = res; + data->finished = true; } void task_free_ext_save_data(list_item* item) { @@ -145,37 +156,30 @@ void task_clear_ext_save_data(linked_list* items) { } } -Handle task_populate_ext_save_data(linked_list* items) { - if(items == NULL) { - return 0; +Result task_populate_ext_save_data(populate_ext_save_data_data* data) { + if(data == NULL || data->items == NULL) { + return R_FBI_INVALID_ARGUMENT; } - task_clear_ext_save_data(items); + task_clear_ext_save_data(data->items); - populate_ext_save_data_data* data = (populate_ext_save_data_data*) calloc(1, sizeof(populate_ext_save_data_data)); - if(data == NULL) { - error_display(NULL, NULL, NULL, "Failed to allocate ext save data list data."); + data->finished = false; + data->result = 0; + data->cancelEvent = 0; - return 0; + Result res = 0; + if(R_SUCCEEDED(res = svcCreateEvent(&data->cancelEvent, 1))) { + if(threadCreate(task_populate_ext_save_data_thread, data, 0x10000, 0x18, 1, true) == NULL) { + res = R_FBI_THREAD_CREATE_FAILED; + } } - data->items = items; - - Result eventRes = svcCreateEvent(&data->cancelEvent, 1); - if(R_FAILED(eventRes)) { - error_display_res(NULL, NULL, NULL, eventRes, "Failed to create ext save data list cancel event."); - - free(data); - return 0; + if(R_FAILED(res)) { + if(data->cancelEvent != 0) { + svcCloseHandle(data->cancelEvent); + data->cancelEvent = 0; + } } - if(threadCreate(task_populate_ext_save_data_thread, data, 0x10000, 0x18, 1, true) == NULL) { - error_display(NULL, NULL, NULL, "Failed to create ext save data list thread."); - - svcCloseHandle(data->cancelEvent); - free(data); - return 0; - } - - return data->cancelEvent; + return res; } \ No newline at end of file diff --git a/source/ui/section/task/listfiles.c b/source/ui/section/task/listfiles.c index d62c3cf..8c6a868 100644 --- a/source/ui/section/task/listfiles.c +++ b/source/ui/section/task/listfiles.c @@ -14,14 +14,7 @@ #define MAX_FILES 1024 -typedef struct { - linked_list* items; - file_info* dir; - - Handle cancelEvent; -} populate_files_data; - -Result task_create_file_item(list_item** out, FS_Archive* archive, const char* path) { +Result task_create_file_item(list_item** out, FS_Archive archive, const char* path) { Result res = 0; list_item* item = (list_item*) calloc(1, sizeof(list_item)); @@ -30,7 +23,6 @@ Result task_create_file_item(list_item** out, FS_Archive* archive, const char* p if(fileInfo != NULL) { fileInfo->archive = archive; util_get_path_file(fileInfo->name, path, FILE_NAME_MAX); - fileInfo->containsCias = false; fileInfo->size = 0; fileInfo->isCia = false; @@ -46,7 +38,7 @@ Result task_create_file_item(list_item** out, FS_Archive* archive, const char* p fileInfo->isDirectory = true; } else { - item->color = COLOR_TEXT; + item->color = COLOR_FILE; strncpy(fileInfo->path, path, FILE_PATH_MAX); fileInfo->isDirectory = false; @@ -54,7 +46,7 @@ Result task_create_file_item(list_item** out, FS_Archive* archive, const char* p FS_Path* fileFsPath = util_make_path_utf8(fileInfo->path); if(fileFsPath != NULL) { Handle fileHandle; - if(R_SUCCEEDED(FSUSER_OpenFile(&fileHandle, *archive, *fileFsPath, FS_OPEN_READ, 0))) { + if(R_SUCCEEDED(FSUSER_OpenFile(&fileHandle, archive, *fileFsPath, FS_OPEN_READ, 0))) { FSFILE_GetSize(fileHandle, &fileInfo->size); size_t len = strlen(fileInfo->path); @@ -72,16 +64,22 @@ Result task_create_file_item(list_item** out, FS_Archive* archive, const char* p fileInfo->ciaInfo.installedSize = titleEntry.size; } - SMDH smdh; - if(R_SUCCEEDED(AM_GetCiaIcon(&smdh, fileHandle))) { - u8 systemLanguage = CFG_LANGUAGE_EN; - CFGU_GetSystemLanguage(&systemLanguage); + SMDH* smdh = (SMDH*) calloc(1, sizeof(SMDH)); + if(smdh != NULL) { + if(R_SUCCEEDED(AM_GetCiaIcon(smdh, fileHandle))) { + if(smdh->magic[0] == 'S' && smdh->magic[1] == 'M' && smdh->magic[2] == 'D' && smdh->magic[3] == 'H') { + u8 systemLanguage = CFG_LANGUAGE_EN; + CFGU_GetSystemLanguage(&systemLanguage); - fileInfo->ciaInfo.hasMeta = true; - utf16_to_utf8((uint8_t*) fileInfo->ciaInfo.meta.shortDescription, smdh.titles[systemLanguage].shortDescription, sizeof(fileInfo->ciaInfo.meta.shortDescription) - 1); - utf16_to_utf8((uint8_t*) fileInfo->ciaInfo.meta.longDescription, smdh.titles[systemLanguage].longDescription, sizeof(fileInfo->ciaInfo.meta.longDescription) - 1); - utf16_to_utf8((uint8_t*) fileInfo->ciaInfo.meta.publisher, smdh.titles[systemLanguage].publisher, sizeof(fileInfo->ciaInfo.meta.publisher) - 1); - fileInfo->ciaInfo.meta.texture = screen_load_texture_tiled_auto(smdh.largeIcon, sizeof(smdh.largeIcon), 48, 48, GPU_RGB565, false); + fileInfo->ciaInfo.hasMeta = true; + utf16_to_utf8((uint8_t*) fileInfo->ciaInfo.meta.shortDescription, smdh->titles[systemLanguage].shortDescription, sizeof(fileInfo->ciaInfo.meta.shortDescription) - 1); + utf16_to_utf8((uint8_t*) fileInfo->ciaInfo.meta.longDescription, smdh->titles[systemLanguage].longDescription, sizeof(fileInfo->ciaInfo.meta.longDescription) - 1); + utf16_to_utf8((uint8_t*) fileInfo->ciaInfo.meta.publisher, smdh->titles[systemLanguage].publisher, sizeof(fileInfo->ciaInfo.meta.publisher) - 1); + fileInfo->ciaInfo.meta.texture = screen_load_texture_tiled_auto(smdh->largeIcon, sizeof(smdh->largeIcon), 48, 48, GPU_RGB565, false); + } + } + + free(smdh); } } } else if(strcasecmp(&fileInfo->path[len - 4], ".tik") == 0) { @@ -124,72 +122,128 @@ Result task_create_file_item(list_item** out, FS_Archive* archive, const char* p return res; } +static int task_populate_files_compare_directory_entries(const void* e1, const void* e2) { + FS_DirectoryEntry* ent1 = (FS_DirectoryEntry*) e1; + FS_DirectoryEntry* ent2 = (FS_DirectoryEntry*) e2; + + if((ent1->attributes & FS_ATTRIBUTE_DIRECTORY) && !(ent2->attributes & FS_ATTRIBUTE_DIRECTORY)) { + return -1; + } else if(!(ent1->attributes & FS_ATTRIBUTE_DIRECTORY) && (ent2->attributes & FS_ATTRIBUTE_DIRECTORY)) { + return 1; + } else { + char entryName1[0x213] = {'\0'}; + utf16_to_utf8((uint8_t*) entryName1, ent1->name, sizeof(entryName1) - 1); + + char entryName2[0x213] = {'\0'}; + utf16_to_utf8((uint8_t*) entryName2, ent2->name, sizeof(entryName2) - 1); + + return strcasecmp(entryName1, entryName2); + } +} + static void task_populate_files_thread(void* arg) { populate_files_data* data = (populate_files_data*) arg; - data->dir->containsCias = false; - data->dir->containsTickets = false; - Result res = 0; - FS_Path* fsPath = util_make_path_utf8(data->dir->path); - if(fsPath != NULL) { - Handle dirHandle = 0; - if(R_SUCCEEDED(res = FSUSER_OpenDirectory(&dirHandle, *data->dir->archive, *fsPath))) { - u32 entryCount = 0; - FS_DirectoryEntry* entries = (FS_DirectoryEntry*) calloc(MAX_FILES, sizeof(FS_DirectoryEntry)); - if(entries != NULL) { - if(R_SUCCEEDED(res = FSDIR_Read(dirHandle, &entryCount, MAX_FILES, entries)) && entryCount > 0) { - qsort(entries, entryCount, sizeof(FS_DirectoryEntry), util_compare_directory_entries); + data->base->containsCias = false; + data->base->containsTickets = false; - for(u32 i = 0; i < entryCount && R_SUCCEEDED(res); i++) { - svcWaitSynchronization(task_get_pause_event(), U64_MAX); - if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) { - break; - } + list_item* baseItem = NULL; + if(R_SUCCEEDED(res = task_create_file_item(&baseItem, data->base->archive, data->base->path))) { + linked_list queue; + linked_list_init(&queue); - if(entries[i].attributes & FS_ATTRIBUTE_HIDDEN) { - continue; - } + linked_list_add(&queue, baseItem); - char name[FILE_NAME_MAX] = {'\0'}; - utf16_to_utf8((uint8_t*) name, entries[i].name, FILE_NAME_MAX - 1); + bool quit = false; + while(!quit && R_SUCCEEDED(res) && linked_list_size(&queue) > 0) { + u32 tail = linked_list_size(&queue) - 1; + list_item* currItem = (list_item*) linked_list_get(&queue, tail); + file_info* curr = (file_info*) currItem->data; + linked_list_remove_at(&queue, tail); - char path[FILE_PATH_MAX] = {'\0'}; - snprintf(path, FILE_PATH_MAX, "%s%s", data->dir->path, name); - - list_item* item = NULL; - if(R_SUCCEEDED(res = task_create_file_item(&item, data->dir->archive, path))) { - if(((file_info*) item->data)->isCia) { - data->dir->containsCias = true; - } else if(((file_info*) item->data)->isTicket) { - data->dir->containsTickets = true; - } - - linked_list_add(data->items, item); - } - } - } - - free(entries); - } else { - res = R_FBI_OUT_OF_MEMORY; + if(data->dirsFirst && (data->includeBase || currItem != baseItem)) { + linked_list_add(data->items, currItem); } - FSDIR_Close(dirHandle); + if(curr->isDirectory) { + FS_Path* fsPath = util_make_path_utf8(curr->path); + if(fsPath != NULL) { + Handle dirHandle = 0; + if(R_SUCCEEDED(res = FSUSER_OpenDirectory(&dirHandle, curr->archive, *fsPath))) { + u32 entryCount = 0; + FS_DirectoryEntry* entries = (FS_DirectoryEntry*) calloc(MAX_FILES, sizeof(FS_DirectoryEntry)); + if(entries != NULL) { + if(R_SUCCEEDED(res = FSDIR_Read(dirHandle, &entryCount, MAX_FILES, entries)) && entryCount > 0) { + qsort(entries, entryCount, sizeof(FS_DirectoryEntry), task_populate_files_compare_directory_entries); + + for(u32 i = 0; i < entryCount && R_SUCCEEDED(res); i++) { + svcWaitSynchronization(task_get_pause_event(), U64_MAX); + if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) { + quit = true; + break; + } + + if(entries[i].attributes & FS_ATTRIBUTE_HIDDEN) { + continue; + } + + char name[FILE_NAME_MAX] = {'\0'}; + utf16_to_utf8((uint8_t*) name, entries[i].name, FILE_NAME_MAX - 1); + + char path[FILE_PATH_MAX] = {'\0'}; + snprintf(path, FILE_PATH_MAX, "%s%s", curr->path, name); + + list_item* item = NULL; + if(R_SUCCEEDED(res = task_create_file_item(&item, curr->archive, path))) { + if(curr->isDirectory && strncmp(curr->path, data->base->path, FILE_PATH_MAX) == 0) { + file_info* info = (file_info*) item->data; + + if(info->isCia) { + data->base->containsCias = true; + } else if(info->isTicket) { + data->base->containsTickets = true; + } + } + + if(data->recursive && ((file_info*) item->data)->isDirectory) { + linked_list_add(&queue, item); + } else { + linked_list_add(data->items, item); + } + } + } + } + + free(entries); + } else { + res = R_FBI_OUT_OF_MEMORY; + } + + FSDIR_Close(dirHandle); + } + + util_free_path_utf8(fsPath); + } else { + res = R_FBI_OUT_OF_MEMORY; + } + } + + if(!data->dirsFirst && (data->includeBase || currItem != baseItem)) { + linked_list_add(data->items, currItem); + } } - util_free_path_utf8(fsPath); - } else { - res = R_FBI_OUT_OF_MEMORY; - } - - if(R_FAILED(res)) { - error_display_res(NULL, NULL, NULL, res, "Failed to load file listing."); + if(!data->includeBase) { + task_free_file(baseItem); + } } svcCloseHandle(data->cancelEvent); - free(data); + + data->result = res; + data->finished = true; } void task_free_file(list_item* item) { @@ -219,43 +273,36 @@ void task_clear_files(linked_list* items) { while(linked_list_iter_has_next(&iter)) { list_item* item = (list_item*) linked_list_iter_next(&iter); - task_free_file(item); + linked_list_iter_remove(&iter); + task_free_file(item); } } -Handle task_populate_files(linked_list* items, file_info* dir) { - if(items == NULL || dir == NULL) { - return 0; +Result task_populate_files(populate_files_data* data) { + if(data == NULL || data->base == NULL || data->items == NULL) { + return R_FBI_INVALID_ARGUMENT; } - task_clear_files(items); + task_clear_files(data->items); - populate_files_data* data = (populate_files_data*) calloc(1, sizeof(populate_files_data)); - if(data == NULL) { - error_display(NULL, NULL, NULL, "Failed to allocate file list data."); + data->finished = false; + data->result = 0; + data->cancelEvent = 0; - return 0; + Result res = 0; + if(R_SUCCEEDED(res = svcCreateEvent(&data->cancelEvent, 1))) { + if(threadCreate(task_populate_files_thread, data, 0x10000, 0x18, 1, true) == NULL) { + res = R_FBI_THREAD_CREATE_FAILED; + } } - data->items = items; - data->dir = dir; - - Result eventRes = svcCreateEvent(&data->cancelEvent, 1); - if(R_FAILED(eventRes)) { - error_display_res(NULL, NULL, NULL, eventRes, "Failed to create file list cancel event."); - - free(data); - return 0; + if(R_FAILED(res)) { + if(data->cancelEvent != 0) { + svcCloseHandle(data->cancelEvent); + data->cancelEvent = 0; + } } - if(threadCreate(task_populate_files_thread, data, 0x10000, 0x18, 1, true) == NULL) { - error_display(NULL, NULL, NULL, "Failed to create file list thread."); - - svcCloseHandle(data->cancelEvent); - free(data); - return 0; - } - - return data->cancelEvent; + return res; } \ No newline at end of file diff --git a/source/ui/section/task/listpendingtitles.c b/source/ui/section/task/listpendingtitles.c index ef1a7d4..ac21571 100644 --- a/source/ui/section/task/listpendingtitles.c +++ b/source/ui/section/task/listpendingtitles.c @@ -11,11 +11,12 @@ #include "../../../core/screen.h" #include "../../../core/util.h" -typedef struct { - linked_list* items; +static int task_populate_pending_titles_compare_ids(const void* e1, const void* e2) { + u64 id1 = *(u64*) e1; + u64 id2 = *(u64*) e2; - Handle cancelEvent; -} populate_pending_titles_data; + return id1 > id2 ? 1 : id1 < id2 ? -1 : 0; +} static Result task_populate_pending_titles_from(populate_pending_titles_data* data, FS_MediaType mediaType) { Result res = 0; @@ -25,7 +26,7 @@ static Result task_populate_pending_titles_from(populate_pending_titles_data* da u64* pendingTitleIds = (u64*) calloc(pendingTitleCount, sizeof(u64)); if(pendingTitleIds != NULL) { if(R_SUCCEEDED(res = AM_GetPendingTitleList(&pendingTitleCount, pendingTitleCount, mediaType, AM_STATUS_MASK_INSTALLING | AM_STATUS_MASK_AWAITING_FINALIZATION, pendingTitleIds))) { - qsort(pendingTitleIds, pendingTitleCount, sizeof(u64), util_compare_u64); + qsort(pendingTitleIds, pendingTitleCount, sizeof(u64), task_populate_pending_titles_compare_ids); AM_PendingTitleEntry* pendingTitleInfos = (AM_PendingTitleEntry*) calloc(pendingTitleCount, sizeof(AM_PendingTitleEntry)); if(pendingTitleInfos != NULL) { @@ -84,12 +85,15 @@ static void task_populate_pending_titles_thread(void* arg) { populate_pending_titles_data* data = (populate_pending_titles_data*) arg; Result res = 0; - if(R_FAILED(res = task_populate_pending_titles_from(data, MEDIATYPE_SD)) || R_FAILED(res = task_populate_pending_titles_from(data, MEDIATYPE_NAND))) { - error_display_res(NULL, NULL, NULL, res, "Failed to load pending title listing."); + + if(R_SUCCEEDED(res = task_populate_pending_titles_from(data, MEDIATYPE_SD))) { + res = task_populate_pending_titles_from(data, MEDIATYPE_NAND); } svcCloseHandle(data->cancelEvent); - free(data); + + data->result = res; + data->finished = true; } void task_free_pending_title(list_item* item) { @@ -119,37 +123,30 @@ void task_clear_pending_titles(linked_list* items) { } } -Handle task_populate_pending_titles(linked_list* items) { - if(items == NULL) { - return 0; +Result task_populate_pending_titles(populate_pending_titles_data* data) { + if(data == NULL || data->items == NULL) { + return R_FBI_INVALID_ARGUMENT; } - task_clear_pending_titles(items); + task_clear_pending_titles(data->items); - populate_pending_titles_data* data = (populate_pending_titles_data*) calloc(1, sizeof(populate_pending_titles_data)); - if(data == NULL) { - error_display(NULL, NULL, NULL, "Failed to allocate pending title list data."); + data->finished = false; + data->result = 0; + data->cancelEvent = 0; - return 0; + Result res = 0; + if(R_SUCCEEDED(res = svcCreateEvent(&data->cancelEvent, 1))) { + if(threadCreate(task_populate_pending_titles_thread, data, 0x10000, 0x18, 1, true) == NULL) { + res = R_FBI_THREAD_CREATE_FAILED; + } } - data->items = items; - - Result eventRes = svcCreateEvent(&data->cancelEvent, 1); - if(R_FAILED(eventRes)) { - error_display_res(NULL, NULL, NULL, eventRes, "Failed to create pending title list cancel event."); - - free(data); - return 0; + if(R_FAILED(res)) { + if(data->cancelEvent != 0) { + svcCloseHandle(data->cancelEvent); + data->cancelEvent = 0; + } } - if(threadCreate(task_populate_pending_titles_thread, data, 0x10000, 0x18, 1, true) == NULL) { - error_display(NULL, NULL, NULL, "Failed to create pending title list thread."); - - svcCloseHandle(data->cancelEvent); - free(data); - return 0; - } - - return data->cancelEvent; + return res; } \ No newline at end of file diff --git a/source/ui/section/task/listsystemsavedata.c b/source/ui/section/task/listsystemsavedata.c index ca422f3..0af52ca 100644 --- a/source/ui/section/task/listsystemsavedata.c +++ b/source/ui/section/task/listsystemsavedata.c @@ -13,11 +13,12 @@ #define MAX_SYSTEM_SAVE_DATA 512 -typedef struct { - linked_list* items; +static int task_populate_system_save_data_compare_ids(const void* e1, const void* e2) { + u32 id1 = *(u32*) e1; + u32 id2 = *(u32*) e2; - Handle cancelEvent; -} populate_system_save_data_data; + return id1 > id2 ? 1 : id1 < id2 ? -1 : 0; +} static void task_populate_system_save_data_thread(void* arg) { populate_system_save_data_data* data = (populate_system_save_data_data*) arg; @@ -27,7 +28,7 @@ static void task_populate_system_save_data_thread(void* arg) { u32 systemSaveDataCount = 0; u32 systemSaveDataIds[MAX_SYSTEM_SAVE_DATA]; if(R_SUCCEEDED(res = FSUSER_EnumerateSystemSaveData(&systemSaveDataCount, MAX_SYSTEM_SAVE_DATA * sizeof(u32), systemSaveDataIds))) { - qsort(systemSaveDataIds, systemSaveDataCount, sizeof(u32), util_compare_u32); + qsort(systemSaveDataIds, systemSaveDataCount, sizeof(u32), task_populate_system_save_data_compare_ids); for(u32 i = 0; i < systemSaveDataCount && R_SUCCEEDED(res); i++) { svcWaitSynchronization(task_get_pause_event(), U64_MAX); @@ -57,12 +58,10 @@ static void task_populate_system_save_data_thread(void* arg) { } } - if(R_FAILED(res)) { - error_display_res(NULL, NULL, NULL, res, "Failed to load system save data listing."); - } - svcCloseHandle(data->cancelEvent); - free(data); + + data->result = res; + data->finished = true; } void task_free_system_save_data(list_item* item) { @@ -92,37 +91,30 @@ void task_clear_system_save_data(linked_list* items) { } } -Handle task_populate_system_save_data(linked_list* items) { - if(items == NULL) { - return 0; +Result task_populate_system_save_data(populate_system_save_data_data* data) { + if(data == NULL || data->items == NULL) { + return R_FBI_INVALID_ARGUMENT; } - task_clear_system_save_data(items); + task_clear_system_save_data(data->items); - populate_system_save_data_data* data = (populate_system_save_data_data*) calloc(1, sizeof(populate_system_save_data_data)); - if(data == NULL) { - error_display(NULL, NULL, NULL, "Failed to allocate system save data list data."); + data->finished = false; + data->result = 0; + data->cancelEvent = 0; - return 0; + Result res = 0; + if(R_SUCCEEDED(res = svcCreateEvent(&data->cancelEvent, 1))) { + if(threadCreate(task_populate_system_save_data_thread, data, 0x10000, 0x18, 1, true) == NULL) { + res = R_FBI_THREAD_CREATE_FAILED; + } } - data->items = items; - - Result eventRes = svcCreateEvent(&data->cancelEvent, 1); - if(R_FAILED(eventRes)) { - error_display_res(NULL, NULL, NULL, eventRes, "Failed to create system save data list cancel event."); - - free(data); - return 0; + if(R_FAILED(res)) { + if(data->cancelEvent != 0) { + svcCloseHandle(data->cancelEvent); + data->cancelEvent = 0; + } } - if(threadCreate(task_populate_system_save_data_thread, data, 0x10000, 0x18, 1, true) == NULL) { - error_display(NULL, NULL, NULL, "Failed to create system save data list thread."); - - svcCloseHandle(data->cancelEvent); - free(data); - return 0; - } - - return data->cancelEvent; + return res; } \ No newline at end of file diff --git a/source/ui/section/task/listtickets.c b/source/ui/section/task/listtickets.c index 25a9157..fbcc602 100644 --- a/source/ui/section/task/listtickets.c +++ b/source/ui/section/task/listtickets.c @@ -11,11 +11,12 @@ #include "../../../core/screen.h" #include "../../../core/util.h" -typedef struct { - linked_list* items; +static int task_populate_tickets_compare_ids(const void* e1, const void* e2) { + u64 id1 = *(u64*) e1; + u64 id2 = *(u64*) e2; - Handle cancelEvent; -} populate_tickets_data; + return id1 > id2 ? 1 : id1 < id2 ? -1 : 0; +} static void task_populate_tickets_thread(void* arg) { populate_tickets_data* data = (populate_tickets_data*) arg; @@ -27,7 +28,7 @@ static void task_populate_tickets_thread(void* arg) { u64* ticketIds = (u64*) calloc(ticketCount, sizeof(u64)); if(ticketIds != NULL) { if(R_SUCCEEDED(res = AM_GetTicketList(&ticketCount, ticketCount, 0, ticketIds))) { - qsort(ticketIds, ticketCount, sizeof(u64), util_compare_u64); + qsort(ticketIds, ticketCount, sizeof(u64), task_populate_tickets_compare_ids); for(u32 i = 0; i < ticketCount && R_SUCCEEDED(res); i++) { svcWaitSynchronization(task_get_pause_event(), U64_MAX); @@ -63,12 +64,10 @@ static void task_populate_tickets_thread(void* arg) { } } - if(R_FAILED(res)) { - error_display_res(NULL, NULL, NULL, res, "Failed to load ticket listing."); - } - svcCloseHandle(data->cancelEvent); - free(data); + + data->result = res; + data->finished = true; } void task_free_ticket(list_item* item) { @@ -98,37 +97,30 @@ void task_clear_tickets(linked_list* items) { } } -Handle task_populate_tickets(linked_list* items) { - if(items == NULL) { - return 0; +Result task_populate_tickets(populate_tickets_data* data) { + if(data == NULL || data->items == NULL) { + return R_FBI_INVALID_ARGUMENT; } - task_clear_tickets(items); + task_clear_tickets(data->items); - populate_tickets_data* data = (populate_tickets_data*) calloc(1, sizeof(populate_tickets_data)); - if(data == NULL) { - error_display(NULL, NULL, NULL, "Failed to allocate ticket list data."); + data->finished = false; + data->result = 0; + data->cancelEvent = 0; - return 0; + Result res = 0; + if(R_SUCCEEDED(res = svcCreateEvent(&data->cancelEvent, 1))) { + if(threadCreate(task_populate_tickets_thread, data, 0x10000, 0x18, 1, true) == NULL) { + res = R_FBI_THREAD_CREATE_FAILED; + } } - data->items = items; - - Result eventRes = svcCreateEvent(&data->cancelEvent, 1); - if(R_FAILED(eventRes)) { - error_display_res(NULL, NULL, NULL, eventRes, "Failed to create ticket list cancel event."); - - free(data); - return 0; + if(R_FAILED(res)) { + if(data->cancelEvent != 0) { + svcCloseHandle(data->cancelEvent); + data->cancelEvent = 0; + } } - if(threadCreate(task_populate_tickets_thread, data, 0x10000, 0x18, 1, true) == NULL) { - error_display(NULL, NULL, NULL, "Failed to create ticket list thread."); - - svcCloseHandle(data->cancelEvent); - free(data); - return 0; - } - - return data->cancelEvent; + return res; } \ No newline at end of file diff --git a/source/ui/section/task/listtitles.c b/source/ui/section/task/listtitles.c index 19748b2..5392f2a 100644 --- a/source/ui/section/task/listtitles.c +++ b/source/ui/section/task/listtitles.c @@ -13,12 +13,6 @@ #include "../../../core/screen.h" #include "../../../core/util.h" -typedef struct { - linked_list* items; - - Handle cancelEvent; -} populate_titles_data; - static Result task_populate_titles_add_ctr(populate_titles_data* data, FS_MediaType mediaType, u64 titleId) { Result res = 0; @@ -36,30 +30,31 @@ static Result task_populate_titles_add_ctr(populate_titles_data* data, FS_MediaT titleInfo->twl = false; titleInfo->hasMeta = false; - static const u32 filePathData[] = {0x00000000, 0x00000000, 0x00000002, 0x6E6F6369, 0x00000000}; - static const FS_Path filePath = (FS_Path) {PATH_BINARY, 0x14, (u8*) filePathData}; - u32 archivePath[] = {(u32) (titleId & 0xFFFFFFFF), (u32) ((titleId >> 32) & 0xFFFFFFFF), mediaType, 0x00000000}; - FS_Archive archive = {ARCHIVE_SAVEDATA_AND_CONTENT, (FS_Path) {PATH_BINARY, 0x10, (u8*) archivePath}}; + static const u32 filePath[5] = {0x00000000, 0x00000000, 0x00000002, 0x6E6F6369, 0x00000000}; + u32 archivePath[4] = {(u32) (titleId & 0xFFFFFFFF), (u32) ((titleId >> 32) & 0xFFFFFFFF), mediaType, 0x00000000}; Handle fileHandle; - if(R_SUCCEEDED(FSUSER_OpenFileDirectly(&fileHandle, archive, filePath, FS_OPEN_READ, 0))) { - SMDH smdh; + if(R_SUCCEEDED(FSUSER_OpenFileDirectly(&fileHandle, ARCHIVE_SAVEDATA_AND_CONTENT, util_make_binary_path(archivePath, sizeof(archivePath)), util_make_binary_path(filePath, sizeof(filePath)), FS_OPEN_READ, 0))) { + SMDH* smdh = (SMDH*) calloc(1, sizeof(SMDH)); + if(smdh != NULL) { + u32 bytesRead = 0; + if(R_SUCCEEDED(FSFILE_Read(fileHandle, &bytesRead, 0, smdh, sizeof(SMDH))) && bytesRead == sizeof(SMDH)) { + if(smdh->magic[0] == 'S' && smdh->magic[1] == 'M' && smdh->magic[2] == 'D' && smdh->magic[3] == 'H') { + titleInfo->hasMeta = true; - u32 bytesRead = 0; - if(R_SUCCEEDED(FSFILE_Read(fileHandle, &bytesRead, 0, &smdh, sizeof(SMDH))) && bytesRead == sizeof(SMDH)) { - if(smdh.magic[0] == 'S' && smdh.magic[1] == 'M' && smdh.magic[2] == 'D' && smdh.magic[3] == 'H') { - titleInfo->hasMeta = true; + u8 systemLanguage = CFG_LANGUAGE_EN; + CFGU_GetSystemLanguage(&systemLanguage); - u8 systemLanguage = CFG_LANGUAGE_EN; - CFGU_GetSystemLanguage(&systemLanguage); + utf16_to_utf8((uint8_t*) item->name, smdh->titles[systemLanguage].shortDescription, NAME_MAX - 1); - utf16_to_utf8((uint8_t*) item->name, smdh.titles[systemLanguage].shortDescription, NAME_MAX - 1); - - utf16_to_utf8((uint8_t*) titleInfo->meta.shortDescription, smdh.titles[systemLanguage].shortDescription, sizeof(titleInfo->meta.shortDescription) - 1); - utf16_to_utf8((uint8_t*) titleInfo->meta.longDescription, smdh.titles[systemLanguage].longDescription, sizeof(titleInfo->meta.longDescription) - 1); - utf16_to_utf8((uint8_t*) titleInfo->meta.publisher, smdh.titles[systemLanguage].publisher, sizeof(titleInfo->meta.publisher) - 1); - titleInfo->meta.texture = screen_load_texture_tiled_auto(smdh.largeIcon, sizeof(smdh.largeIcon), 48, 48, GPU_RGB565, false); + utf16_to_utf8((uint8_t*) titleInfo->meta.shortDescription, smdh->titles[systemLanguage].shortDescription, sizeof(titleInfo->meta.shortDescription) - 1); + utf16_to_utf8((uint8_t*) titleInfo->meta.longDescription, smdh->titles[systemLanguage].longDescription, sizeof(titleInfo->meta.longDescription) - 1); + utf16_to_utf8((uint8_t*) titleInfo->meta.publisher, smdh->titles[systemLanguage].publisher, sizeof(titleInfo->meta.publisher) - 1); + titleInfo->meta.texture = screen_load_texture_tiled_auto(smdh->largeIcon, sizeof(smdh->largeIcon), 48, 48, GPU_RGB565, false); + } } + + free(smdh); } FSFILE_Close(fileHandle); @@ -153,59 +148,63 @@ static Result task_populate_titles_add_twl(populate_titles_data* data, FS_MediaT titleInfo->twl = true; titleInfo->hasMeta = false; - BNR bnr; - if(R_SUCCEEDED(FSUSER_GetLegacyBannerData(mediaType, titleId, (u8*) &bnr))) { - titleInfo->hasMeta = true; + BNR* bnr = (BNR*) calloc(1, sizeof(BNR)); + if(bnr != NULL) { + if(R_SUCCEEDED(FSUSER_GetLegacyBannerData(mediaType, titleId, (u8*) bnr))) { + titleInfo->hasMeta = true; - u8 systemLanguage = CFG_LANGUAGE_EN; - CFGU_GetSystemLanguage(&systemLanguage); + u8 systemLanguage = CFG_LANGUAGE_EN; + CFGU_GetSystemLanguage(&systemLanguage); - char title[0x100] = {'\0'}; - utf16_to_utf8((uint8_t*) title, bnr.titles[systemLanguage], sizeof(title) - 1); + char title[0x100] = {'\0'}; + utf16_to_utf8((uint8_t*) title, bnr->titles[systemLanguage], sizeof(title) - 1); - if(strchr(title, '\n') == NULL) { - size_t len = strlen(title); - strncpy(item->name, title, len); - strncpy(titleInfo->meta.shortDescription, title, len); - } else { - char* destinations[] = {titleInfo->meta.shortDescription, titleInfo->meta.longDescription, titleInfo->meta.publisher}; - int currDest = 0; + if(strchr(title, '\n') == NULL) { + size_t len = strlen(title); + strncpy(item->name, title, len); + strncpy(titleInfo->meta.shortDescription, title, len); + } else { + char* destinations[] = {titleInfo->meta.shortDescription, titleInfo->meta.longDescription, titleInfo->meta.publisher}; + int currDest = 0; - char* last = title; - char* curr = NULL; + char* last = title; + char* curr = NULL; - while(currDest < 3 && (curr = strchr(last, '\n')) != NULL) { - strncpy(destinations[currDest++], last, curr - last); - last = curr + 1; - *curr = ' '; + while(currDest < 3 && (curr = strchr(last, '\n')) != NULL) { + strncpy(destinations[currDest++], last, curr - last); + last = curr + 1; + *curr = ' '; + } + + strncpy(item->name, title, last - title); + if(currDest < 3) { + strncpy(destinations[currDest], last, strlen(title) - (last - title)); + } } - strncpy(item->name, title, last - title); - if(currDest < 3) { - strncpy(destinations[currDest], last, strlen(title) - (last - title)); + u8 icon[32 * 32 * 2]; + for(u32 x = 0; x < 32; x++) { + for(u32 y = 0; y < 32; y++) { + u32 srcPos = (((y >> 3) * 4 + (x >> 3)) * 8 + (y & 7)) * 4 + ((x & 7) >> 1); + u32 srcShift = (x & 1) * 4; + u16 srcPx = bnr->mainIconPalette[(bnr->mainIconBitmap[srcPos] >> srcShift) & 0xF]; + + u8 r = (u8) (srcPx & 0x1F); + u8 g = (u8) ((srcPx >> 5) & 0x1F); + u8 b = (u8) ((srcPx >> 10) & 0x1F); + + u16 reversedPx = (u16) ((r << 11) | (g << 6) | (b << 1) | 1); + + u32 dstPos = (y * 32 + x) * 2; + icon[dstPos + 0] = (u8) (reversedPx & 0xFF); + icon[dstPos + 1] = (u8) ((reversedPx >> 8) & 0xFF); + } } + + titleInfo->meta.texture = screen_load_texture_auto(icon, sizeof(icon), 32, 32, GPU_RGBA5551, false); } - u8 icon[32 * 32 * 2]; - for(u32 x = 0; x < 32; x++) { - for(u32 y = 0; y < 32; y++) { - u32 srcPos = (((y >> 3) * 4 + (x >> 3)) * 8 + (y & 7)) * 4 + ((x & 7) >> 1); - u32 srcShift = (x & 1) * 4; - u16 srcPx = bnr.mainIconPalette[(bnr.mainIconBitmap[srcPos] >> srcShift) & 0xF]; - - u8 r = (u8) (srcPx & 0x1F); - u8 g = (u8) ((srcPx >> 5) & 0x1F); - u8 b = (u8) ((srcPx >> 10) & 0x1F); - - u16 reversedPx = (u16) ((r << 11) | (g << 6) | (b << 1) | 1); - - u32 dstPos = (y * 32 + x) * 2; - icon[dstPos + 0] = (u8) (reversedPx & 0xFF); - icon[dstPos + 1] = (u8) ((reversedPx >> 8) & 0xFF); - } - } - - titleInfo->meta.texture = screen_load_texture_auto(icon, sizeof(icon), 32, 32, GPU_RGBA5551, false); + free(bnr); } bool empty = strlen(item->name) == 0; @@ -244,6 +243,13 @@ static Result task_populate_titles_add_twl(populate_titles_data* data, FS_MediaT return res; } +static int task_populate_titles_compare_ids(const void* e1, const void* e2) { + u64 id1 = *(u64*) e1; + u64 id2 = *(u64*) e2; + + return id1 > id2 ? 1 : id1 < id2 ? -1 : 0; +} + static Result task_populate_titles_from(populate_titles_data* data, FS_MediaType mediaType, bool useDSiWare) { bool inserted; FS_CardType type; @@ -259,7 +265,7 @@ static Result task_populate_titles_from(populate_titles_data* data, FS_MediaType u64* titleIds = (u64*) calloc(titleCount, sizeof(u64)); if(titleIds != NULL) { if(R_SUCCEEDED(res = AM_GetTitleList(&titleCount, mediaType, titleCount, titleIds))) { - qsort(titleIds, titleCount, sizeof(u64), util_compare_u64); + qsort(titleIds, titleCount, sizeof(u64), task_populate_titles_compare_ids); for(u32 i = 0; i < titleCount && R_SUCCEEDED(res); i++) { svcWaitSynchronization(task_get_pause_event(), U64_MAX); @@ -292,12 +298,19 @@ static void task_populate_titles_thread(void* arg) { populate_titles_data* data = (populate_titles_data*) arg; Result res = 0; - if(R_FAILED(res = task_populate_titles_from(data, MEDIATYPE_GAME_CARD, false)) || R_FAILED(res = task_populate_titles_from(data, MEDIATYPE_SD, false)) || R_FAILED(res = task_populate_titles_from(data, MEDIATYPE_NAND, false)) || R_FAILED(res = task_populate_titles_from(data, MEDIATYPE_NAND, true))) { - error_display_res(NULL, NULL, NULL, res, "Failed to load title listing."); + + if(R_SUCCEEDED(res = task_populate_titles_from(data, MEDIATYPE_GAME_CARD, false))) { + if(R_SUCCEEDED(res = task_populate_titles_from(data, MEDIATYPE_SD, false))) { + if(R_SUCCEEDED(res = task_populate_titles_from(data, MEDIATYPE_NAND, false))) { + res = task_populate_titles_from(data, MEDIATYPE_NAND, true); + } + } } svcCloseHandle(data->cancelEvent); - free(data); + + data->result = res; + data->finished = true; } void task_free_title(list_item* item) { @@ -332,37 +345,30 @@ void task_clear_titles(linked_list* items) { } } -Handle task_populate_titles(linked_list* items) { - if(items == NULL) { - return 0; +Result task_populate_titles(populate_titles_data* data) { + if(data == NULL || data->items == NULL) { + return R_FBI_INVALID_ARGUMENT; } - task_clear_titles(items); + task_clear_titles(data->items); - populate_titles_data* data = (populate_titles_data*) calloc(1, sizeof(populate_titles_data)); - if(data == NULL) { - error_display(NULL, NULL, NULL, "Failed to allocate title list data."); + data->finished = false; + data->result = 0; + data->cancelEvent = 0; - return 0; + Result res = 0; + if(R_SUCCEEDED(res = svcCreateEvent(&data->cancelEvent, 1))) { + if(threadCreate(task_populate_titles_thread, data, 0x10000, 0x18, 1, true) == NULL) { + res = R_FBI_THREAD_CREATE_FAILED; + } } - data->items = items; - - Result eventRes = svcCreateEvent(&data->cancelEvent, 1); - if(R_FAILED(eventRes)) { - error_display_res(NULL, NULL, NULL, eventRes, "Failed to create title list cancel event."); - - free(data); - return 0; + if(R_FAILED(res)) { + if(data->cancelEvent != 0) { + svcCloseHandle(data->cancelEvent); + data->cancelEvent = 0; + } } - if(threadCreate(task_populate_titles_thread, data, 0x10000, 0x18, 1, true) == NULL) { - error_display(NULL, NULL, NULL, "Failed to create title list thread."); - - svcCloseHandle(data->cancelEvent); - free(data); - return 0; - } - - return data->cancelEvent; + return res; } \ No newline at end of file diff --git a/source/ui/section/task/task.h b/source/ui/section/task/task.h index c4346bb..12bb5c7 100644 --- a/source/ui/section/task/task.h +++ b/source/ui/section/task/task.h @@ -3,13 +3,6 @@ #define FILE_NAME_MAX 512 #define FILE_PATH_MAX 512 -#define R_FBI_CANCELLED MAKERESULT(RL_PERMANENT, RS_CANCELED, RM_APPLICATION, 1) -#define R_FBI_ERRNO MAKERESULT(RL_PERMANENT, RS_INTERNAL, RM_APPLICATION, 2) -#define R_FBI_HTTP_RESPONSE_CODE MAKERESULT(RL_PERMANENT, RS_INTERNAL, RM_APPLICATION, 3) -#define R_FBI_WRONG_SYSTEM MAKERESULT(RL_PERMANENT, RS_NOTSUPPORTED, RM_APPLICATION, 4) - -#define R_FBI_OUT_OF_MEMORY MAKERESULT(RL_FATAL, RS_OUTOFRESOURCE, RM_APPLICATION, RD_OUT_OF_MEMORY) - typedef struct linked_list_s linked_list; typedef struct list_item_s list_item; @@ -62,21 +55,33 @@ typedef struct cia_info_s { } cia_info; typedef struct file_info_s { - FS_Archive* archive; + FS_Archive archive; char name[FILE_NAME_MAX]; char path[FILE_PATH_MAX]; bool isDirectory; - u64 size; - bool containsCias; + u64 size; bool isCia; cia_info ciaInfo; - - bool containsTickets; bool isTicket; ticket_info ticketInfo; + + bool containsCias; + bool containsTickets; } file_info; +typedef struct { + u16* buffer; + s16 width; + s16 height; + + Handle mutex; + + volatile bool finished; + Result result; + Handle cancelEvent; +} capture_cam_data; + typedef enum data_op_e { DATAOP_COPY, DATAOP_DELETE @@ -90,9 +95,6 @@ typedef struct data_op_info_s { // Copy bool copyEmpty; - bool finished; - bool premature; - u32 processed; u32 total; @@ -118,38 +120,97 @@ typedef struct data_op_info_s { // Errors bool (*error)(void* data, u32 index, Result res); -} data_op_info; + + // General + volatile bool finished; + Result result; + Handle cancelEvent; +} data_op_data; + +typedef struct { + linked_list* items; + + volatile bool finished; + Result result; + Handle cancelEvent; +} populate_ext_save_data_data; + +typedef struct { + linked_list* items; + + file_info* base; + + bool recursive; + bool includeBase; + bool dirsFirst; + + volatile bool finished; + Result result; + Handle cancelEvent; +} populate_files_data; + +typedef struct { + linked_list* items; + + volatile bool finished; + Result result; + Handle cancelEvent; +} populate_pending_titles_data; + +typedef struct { + linked_list* items; + + volatile bool finished; + Result result; + Handle cancelEvent; +} populate_system_save_data_data; + +typedef struct { + linked_list* items; + + volatile bool finished; + Result result; + Handle cancelEvent; +} populate_tickets_data; + +typedef struct { + linked_list* items; + + volatile bool finished; + Result result; + Handle cancelEvent; +} populate_titles_data; void task_init(); void task_exit(); bool task_is_quit_all(); Handle task_get_pause_event(); -Handle task_capture_cam(Handle* mutex, u16* buffer, s16 width, s16 height); +Result task_capture_cam(capture_cam_data* data); -Handle task_data_op(data_op_info* info); +Result task_data_op(data_op_data* data); void task_free_ext_save_data(list_item* item); void task_clear_ext_save_data(linked_list* items); -Handle task_populate_ext_save_data(linked_list* items); +Result task_populate_ext_save_data(populate_ext_save_data_data* data); void task_free_file(list_item* item); void task_clear_files(linked_list* items); -Result task_create_file_item(list_item** out, FS_Archive* archive, const char* path); -Handle task_populate_files(linked_list* items, file_info* dir); +Result task_create_file_item(list_item** out, FS_Archive archive, const char* path); +Result task_populate_files(populate_files_data* data); void task_free_pending_title(list_item* item); void task_clear_pending_titles(linked_list* items); -Handle task_populate_pending_titles(linked_list* items); +Result task_populate_pending_titles(populate_pending_titles_data* data); void task_free_system_save_data(list_item* item); void task_clear_system_save_data(linked_list* items); -Handle task_populate_system_save_data(linked_list* items); +Result task_populate_system_save_data(populate_system_save_data_data* data); void task_free_ticket(list_item* item); void task_clear_tickets(linked_list* items); -Handle task_populate_tickets(linked_list* items); +Result task_populate_tickets(populate_tickets_data* data); void task_free_title(list_item* item); void task_clear_titles(linked_list* items); -Handle task_populate_titles(linked_list* items); \ No newline at end of file +Result task_populate_titles(populate_titles_data* data); \ No newline at end of file diff --git a/source/ui/section/tickets.c b/source/ui/section/tickets.c index 0bcdc90..bc2dbe0 100644 --- a/source/ui/section/tickets.c +++ b/source/ui/section/tickets.c @@ -16,7 +16,8 @@ static list_item install_from_cdn = {"Install from CDN", COLOR_TEXT, action_inst static list_item delete_ticket = {"Delete Ticket", COLOR_TEXT, action_delete_ticket}; typedef struct { - Handle cancelEvent; + populate_tickets_data populateData; + bool populated; } tickets_data; @@ -84,13 +85,11 @@ static void tickets_update(ui_view* view, void* data, linked_list* items, list_i tickets_data* listData = (tickets_data*) data; if(hidKeysDown() & KEY_B) { - if(listData->cancelEvent != 0) { - svcSignalEvent(listData->cancelEvent); - while(svcWaitSynchronization(listData->cancelEvent, 0) == 0) { + if(!listData->populateData.finished) { + svcSignalEvent(listData->populateData.cancelEvent); + while(!listData->populateData.finished) { svcSleepThread(1000000); } - - listData->cancelEvent = 0; } ui_pop(); @@ -103,19 +102,28 @@ static void tickets_update(ui_view* view, void* data, linked_list* items, list_i } if(!listData->populated || (hidKeysDown() & KEY_X)) { - if(listData->cancelEvent != 0) { - svcSignalEvent(listData->cancelEvent); - while(svcWaitSynchronization(listData->cancelEvent, 0) == 0) { + if(!listData->populateData.finished) { + svcSignalEvent(listData->populateData.cancelEvent); + while(!listData->populateData.finished) { svcSleepThread(1000000); } - - listData->cancelEvent = 0; } - listData->cancelEvent = task_populate_tickets(items); + listData->populateData.items = items; + Result res = task_populate_tickets(&listData->populateData); + if(R_FAILED(res)) { + error_display_res(NULL, NULL, NULL, res, "Failed to initiate ticket list population."); + } + listData->populated = true; } + if(listData->populateData.finished && R_FAILED(listData->populateData.result)) { + listData->populateData.result = 0; + + error_display_res(NULL, NULL, NULL, listData->populateData.result, "Failed to populate ticket list."); + } + if(selected != NULL && selected->data != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) { tickets_action_open(items, selected); return; @@ -130,5 +138,7 @@ void tickets_open() { return; } + data->populateData.finished = true; + list_display("Tickets", "A: Select, B: Return, X: Refresh", data, tickets_update, tickets_draw_top); } \ No newline at end of file diff --git a/source/ui/section/titles.c b/source/ui/section/titles.c index d179f66..5366908 100644 --- a/source/ui/section/titles.c +++ b/source/ui/section/titles.c @@ -21,7 +21,8 @@ static list_item export_secure_value = {"Export Secure Value", COLOR_TEXT, actio static list_item delete_secure_value = {"Delete Secure Value", COLOR_TEXT, action_delete_secure_value}; typedef struct { - Handle cancelEvent; + populate_titles_data populateData; + bool populated; } titles_data; @@ -105,13 +106,11 @@ static void titles_update(ui_view* view, void* data, linked_list* items, list_it titles_data* listData = (titles_data*) data; if(hidKeysDown() & KEY_B) { - if(listData->cancelEvent != 0) { - svcSignalEvent(listData->cancelEvent); - while(svcWaitSynchronization(listData->cancelEvent, 0) == 0) { + if(!listData->populateData.finished) { + svcSignalEvent(listData->populateData.cancelEvent); + while(!listData->populateData.finished) { svcSleepThread(1000000); } - - listData->cancelEvent = 0; } ui_pop(); @@ -124,19 +123,28 @@ static void titles_update(ui_view* view, void* data, linked_list* items, list_it } if(!listData->populated || (hidKeysDown() & KEY_X)) { - if(listData->cancelEvent != 0) { - svcSignalEvent(listData->cancelEvent); - while(svcWaitSynchronization(listData->cancelEvent, 0) == 0) { + if(!listData->populateData.finished) { + svcSignalEvent(listData->populateData.cancelEvent); + while(!listData->populateData.finished) { svcSleepThread(1000000); } - - listData->cancelEvent = 0; } - listData->cancelEvent = task_populate_titles(items); + listData->populateData.items = items; + Result res = task_populate_titles(&listData->populateData); + if(R_FAILED(res)) { + error_display_res(NULL, NULL, NULL, res, "Failed to initiate title list population."); + } + listData->populated = true; } + if(listData->populateData.finished && R_FAILED(listData->populateData.result)) { + listData->populateData.result = 0; + + error_display_res(NULL, NULL, NULL, listData->populateData.result, "Failed to populate title list."); + } + if(selected != NULL && selected->data != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) { titles_action_open(items, selected); return; @@ -151,5 +159,7 @@ void titles_open() { return; } + data->populateData.finished = true; + list_display("Titles", "A: Select, B: Return, X: Refresh", data, titles_update, titles_draw_top); } \ No newline at end of file