diff --git a/source/ui/section/action/clipboard.c b/source/core/clipboard.c similarity index 62% rename from source/ui/section/action/clipboard.c rename to source/core/clipboard.c index d501404..2f34809 100644 --- a/source/ui/section/action/clipboard.c +++ b/source/core/clipboard.c @@ -4,7 +4,8 @@ #include <3ds.h> #include "clipboard.h" -#include "../task/task.h" +#include "util.h" +#include "../ui/section/task/task.h" static bool clipboard_has = false; static bool clipboard_contents_only; @@ -28,30 +29,29 @@ bool clipboard_is_contents_only() { return clipboard_contents_only; } -Result clipboard_set_contents(FS_ArchiveID archiveId, FS_Path* archivePath, const char* path, bool contentsOnly) { +Result clipboard_set_contents(FS_Archive archive, const char* path, bool contentsOnly) { clipboard_clear(); - clipboard_has = true; - clipboard_contents_only = contentsOnly; - - strncpy(clipboard_path, path, FILE_PATH_MAX); - Result res = 0; - if(R_FAILED(res = FSUSER_OpenArchive(&clipboard_archive, archiveId, *archivePath))) { - clipboard_clear(); + if(R_SUCCEEDED(res = util_ref_archive(archive))) { + clipboard_has = true; + clipboard_contents_only = contentsOnly; + + clipboard_archive = archive; + strncpy(clipboard_path, path, FILE_PATH_MAX); } return res; } void clipboard_clear() { + if(clipboard_archive != 0) { + util_close_archive(clipboard_archive); + } + clipboard_has = false; clipboard_contents_only = false; + clipboard_archive = 0; 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/core/clipboard.h similarity index 60% rename from source/ui/section/action/clipboard.h rename to source/core/clipboard.h index e4d009a..00a5eda 100644 --- a/source/ui/section/action/clipboard.h +++ b/source/core/clipboard.h @@ -1,12 +1,10 @@ #pragma once -#include - typedef struct file_info_s file_info; bool clipboard_has_contents(); FS_Archive clipboard_get_archive(); char* clipboard_get_path(); bool clipboard_is_contents_only(); -Result clipboard_set_contents(FS_ArchiveID archiveId, FS_Path* archivePath, const char* path, bool contentsOnly); +Result clipboard_set_contents(FS_Archive archive, const char* path, bool contentsOnly); void clipboard_clear(); \ No newline at end of file diff --git a/source/core/util.c b/source/core/util.c index 9ecf1ee..837f050 100644 --- a/source/core/util.c +++ b/source/core/util.c @@ -9,6 +9,7 @@ #include "../ui/error.h" #include "../ui/list.h" #include "../ui/section/task/task.h" +#include "linkedlist.h" extern void cleanup(); @@ -361,24 +362,111 @@ int util_compare_file_infos(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; + bool info1Base = strncmp(info1->name, "", LIST_ITEM_NAME_MAX) == 0 || strncmp(info1->name, "", LIST_ITEM_NAME_MAX) == 0; + bool info2Base = strncmp(info2->name, "", LIST_ITEM_NAME_MAX) == 0 || strncmp(info2->name, "", LIST_ITEM_NAME_MAX) == 0; - if(f1->isDirectory && !f2->isDirectory) { + if(info1Base && !info2Base) { return -1; - } else if(!f1->isDirectory && f2->isDirectory) { + } else if(!info1Base && info2Base) { return 1; } else { - return strcasecmp(f1->name, f2->name); + file_info* f1 = (file_info*) info1->data; + file_info* f2 = (file_info*) info2->data; + + if(f1->isDirectory && !f2->isDirectory) { + return -1; + } else if(!f1->isDirectory && f2->isDirectory) { + return 1; + } else { + return strncasecmp(f1->name, f2->name, FILE_NAME_MAX); + } } } -static const char* path3dsx = NULL; +static const char* path_3dsx = NULL; const char* util_get_3dsx_path() { - return path3dsx; + return path_3dsx; } void util_set_3dsx_path(const char* path) { - path3dsx = path; + path_3dsx = path; +} + +typedef struct { + FS_Archive archive; + u32 refs; +} archive_ref; + +static linked_list opened_archives; + +static Result util_add_archive_ref(FS_Archive archive) { + Result res = 0; + + archive_ref* ref = (archive_ref*) calloc(1, sizeof(archive_ref)); + if(ref != NULL) { + ref->archive = archive; + ref->refs = 1; + + linked_list_add(&opened_archives, ref); + } else { + res = R_FBI_OUT_OF_MEMORY; + } + + return res; +} + +Result util_open_archive(FS_Archive* archive, FS_ArchiveID id, FS_Path path) { + if(archive == NULL) { + return R_FBI_INVALID_ARGUMENT; + } + + Result res = 0; + + FS_Archive arch = 0; + if(R_SUCCEEDED(res = FSUSER_OpenArchive(&arch, id, path))) { + if(R_SUCCEEDED(res = util_add_archive_ref(arch))) { + *archive = arch; + } else { + FSUSER_CloseArchive(arch); + } + } + + return res; +} + +Result util_ref_archive(FS_Archive archive) { + linked_list_iter iter; + linked_list_iterate(&opened_archives, &iter); + + while(linked_list_iter_has_next(&iter)) { + archive_ref* ref = (archive_ref*) linked_list_iter_next(&iter); + if(ref->archive == archive) { + ref->refs++; + return 0; + } + } + + return util_add_archive_ref(archive); +} + +Result util_close_archive(FS_Archive archive) { + linked_list_iter iter; + linked_list_iterate(&opened_archives, &iter); + + while(linked_list_iter_has_next(&iter)) { + archive_ref* ref = (archive_ref*) linked_list_iter_next(&iter); + if(ref->archive == archive) { + ref->refs--; + + if(ref->refs == 0) { + linked_list_iter_remove(&iter); + free(ref); + } else { + return 0; + } + } + } + + return FSUSER_CloseArchive(archive); } \ No newline at end of file diff --git a/source/core/util.h b/source/core/util.h index 17146b6..1104023 100644 --- a/source/core/util.h +++ b/source/core/util.h @@ -65,4 +65,8 @@ bool util_filter_tickets(void* data, const char* name, u32 attributes); int util_compare_file_infos(const void** p1, const void** p2); const char* util_get_3dsx_path(); -void util_set_3dsx_path(const char* path); \ No newline at end of file +void util_set_3dsx_path(const char* path); + +Result util_open_archive(FS_Archive* archive, FS_ArchiveID id, FS_Path path); +Result util_ref_archive(FS_Archive archive); +Result util_close_archive(FS_Archive archive); \ No newline at end of file diff --git a/source/main.c b/source/main.c index 6959361..5d1848f 100644 --- a/source/main.c +++ b/source/main.c @@ -2,12 +2,12 @@ #include <3ds.h> +#include "core/clipboard.h" #include "core/screen.h" #include "core/util.h" #include "svchax/svchax.h" #include "ui/mainmenu.h" #include "ui/ui.h" -#include "ui/section/action/clipboard.h" #include "ui/section/task/task.h" static void* soc_buffer; diff --git a/source/ui/section/action/deletecontents.c b/source/ui/section/action/deletecontents.c index 3bd1ecb..d982349 100644 --- a/source/ui/section/action/deletecontents.c +++ b/source/ui/section/action/deletecontents.c @@ -22,10 +22,10 @@ typedef struct { linked_list contents; data_op_data deleteInfo; -} delete_contents_data; +} delete_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; +static void action_delete_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { + delete_data* deleteData = (delete_data*) data; u32 curr = deleteData->deleteInfo.processed; if(curr < deleteData->deleteInfo.total) { @@ -35,8 +35,8 @@ static void action_delete_contents_draw_top(ui_view* view, void* data, float x1, } } -static Result action_delete_contents_delete(void* data, u32 index) { - delete_contents_data* deleteData = (delete_contents_data*) data; +static Result action_delete_delete(void* data, u32 index) { + delete_data* deleteData = (delete_data*) data; Result res = 0; @@ -56,9 +56,6 @@ 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); @@ -69,10 +66,6 @@ static Result action_delete_contents_delete(void* data, u32 index) { if(strncmp(currInfo->path, info->path, FILE_PATH_MAX) == 0) { linked_list_iter_remove(&iter); task_free_file(item); - } else if(currInfo->isCia) { - deleteData->target->containsCias = true; - } else if(currInfo->isTicket) { - deleteData->target->containsTickets = true; } } } @@ -80,23 +73,23 @@ static Result action_delete_contents_delete(void* data, u32 index) { return res; } -static Result action_delete_contents_suspend(void* data, u32 index) { +static Result action_delete_suspend(void* data, u32 index) { return 0; } -static Result action_delete_contents_restore(void* data, u32 index) { +static Result action_delete_restore(void* data, u32 index) { return 0; } -static bool action_delete_contents_error(void* data, u32 index, Result res) { - delete_contents_data* deleteData = (delete_contents_data*) data; +static bool action_delete_error(void* data, u32 index, Result res) { + delete_data* deleteData = (delete_data*) data; if(res == R_FBI_CANCELLED) { prompt_display("Failure", "Delete cancelled.", COLOR_TEXT, false, NULL, NULL, NULL); return false; } else { volatile bool dismissed = false; - error_display_res(&dismissed, data, action_delete_contents_draw_top, res, "Failed to delete content."); + error_display_res(&dismissed, data, action_delete_draw_top, res, "Failed to delete content."); while(!dismissed) { svcSleepThread(1000000); @@ -106,14 +99,14 @@ static bool action_delete_contents_error(void* data, u32 index, Result res) { return index < deleteData->deleteInfo.total - 1; } -static void action_delete_contents_free_data(delete_contents_data* data) { +static void action_delete_free_data(delete_data* data) { task_clear_files(&data->contents); linked_list_destroy(&data->contents); free(data); } -static void action_delete_contents_update(ui_view* view, void* data, float* progress, char* text) { - delete_contents_data* deleteData = (delete_contents_data*) data; +static void action_delete_update(ui_view* view, void* data, float* progress, char* text) { + delete_data* deleteData = (delete_data*) data; if(deleteData->deleteInfo.finished) { FSUSER_ControlArchive(deleteData->target->archive, ARCHIVE_ACTION_COMMIT_SAVE_DATA, NULL, 0, NULL, 0); @@ -125,7 +118,7 @@ static void action_delete_contents_update(ui_view* view, void* data, float* prog prompt_display("Success", "Deleted.", COLOR_TEXT, false, NULL, NULL, NULL); } - action_delete_contents_free_data(deleteData); + action_delete_free_data(deleteData); return; } @@ -138,25 +131,25 @@ static void action_delete_contents_update(ui_view* view, void* data, float* prog snprintf(text, PROGRESS_TEXT_MAX, "%lu / %lu", deleteData->deleteInfo.processed, deleteData->deleteInfo.total); } -static void action_delete_contents_onresponse(ui_view* view, void* data, bool response) { - delete_contents_data* deleteData = (delete_contents_data*) data; +static void action_delete_onresponse(ui_view* view, void* data, bool response) { + delete_data* deleteData = (delete_data*) data; if(response) { Result res = task_data_op(&deleteData->deleteInfo); if(R_SUCCEEDED(res)) { - info_display("Deleting", "Press B to cancel.", true, data, action_delete_contents_update, action_delete_contents_draw_top); + info_display("Deleting", "Press B to cancel.", true, data, action_delete_update, action_delete_draw_top); } else { error_display_res(NULL, deleteData->target, ui_draw_file_info, res, "Failed to initiate delete operation."); - action_delete_contents_free_data(deleteData); + action_delete_free_data(deleteData); } } else { - action_delete_contents_free_data(deleteData); + action_delete_free_data(deleteData); } } -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)); +static void action_delete_internal(linked_list* items, list_item* selected, const char* message, bool recursive, bool includeBase, bool ciasOnly, bool ticketsOnly) { + delete_data* data = (delete_data*) calloc(1, sizeof(delete_data)); if(data == NULL) { error_display(NULL, NULL, NULL, "Failed to allocate delete data."); @@ -170,12 +163,12 @@ static void action_delete_contents_internal(linked_list* items, list_item* selec data->deleteInfo.op = DATAOP_DELETE; - data->deleteInfo.delete = action_delete_contents_delete; + data->deleteInfo.delete = action_delete_delete; - data->deleteInfo.suspend = action_delete_contents_suspend; - data->deleteInfo.restore = action_delete_contents_restore; + data->deleteInfo.suspend = action_delete_suspend; + data->deleteInfo.restore = action_delete_restore; - data->deleteInfo.error = action_delete_contents_error; + data->deleteInfo.error = action_delete_error; data->deleteInfo.finished = false; @@ -183,7 +176,8 @@ static void action_delete_contents_internal(linked_list* items, list_item* selec populate_files_data popData; popData.items = &data->contents; - popData.base = data->target; + popData.archive = data->target->archive; + strncpy(popData.path, data->target->path, FILE_PATH_MAX); popData.recursive = recursive; popData.includeBase = includeBase; popData.filter = ciasOnly ? util_filter_cias : ticketsOnly ? util_filter_tickets : NULL; @@ -193,7 +187,7 @@ static void action_delete_contents_internal(linked_list* items, list_item* selec if(R_FAILED(listRes)) { error_display_res(NULL, NULL, NULL, listRes, "Failed to initiate content list population."); - action_delete_contents_free_data(data); + action_delete_free_data(data); return; } @@ -204,32 +198,32 @@ static void action_delete_contents_internal(linked_list* items, list_item* selec if(R_FAILED(popData.result)) { error_display_res(NULL, NULL, NULL, popData.result, "Failed to populate content list."); - action_delete_contents_free_data(data); + action_delete_free_data(data); return; } data->deleteInfo.total = linked_list_size(&data->contents); data->deleteInfo.processed = data->deleteInfo.total; - prompt_display("Confirmation", message, COLOR_TEXT, true, data, action_delete_contents_draw_top, action_delete_contents_onresponse); + prompt_display("Confirmation", message, COLOR_TEXT, true, data, action_delete_draw_top, action_delete_onresponse); } void action_delete_file(linked_list* items, list_item* selected) { - action_delete_contents_internal(items, selected, "Delete the selected file?", false, true, false, false); + action_delete_internal(items, selected, "Delete the selected file?", false, true, false, false); } void action_delete_dir(linked_list* items, list_item* selected) { - action_delete_contents_internal(items, selected, "Delete the current directory?", true, true, false, false); + action_delete_internal(items, selected, "Delete the current directory?", true, true, false, false); } 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); + action_delete_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) { - action_delete_contents_internal(items, selected, "Delete all CIAs in the current directory?", false, false, true, false); + action_delete_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) { - action_delete_contents_internal(items, selected, "Delete all tickets in the current directory?", false, false, false, true); + action_delete_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 37b7d81..2abccde 100644 --- a/source/ui/section/action/deletependingtitles.c +++ b/source/ui/section/action/deletependingtitles.c @@ -46,10 +46,11 @@ static Result action_delete_pending_titles_delete(void* data, u32 index) { while(linked_list_iter_has_next(&iter)) { list_item* currItem = (list_item*) linked_list_iter_next(&iter); + pending_title_info* currInfo = (pending_title_info*) currItem->data; - if(strncmp(currItem->name, item->name, LIST_ITEM_NAME_MAX) == 0) { + if(currInfo->titleId == info->titleId && currInfo->mediaType == info->mediaType) { linked_list_iter_remove(&iter); - task_free_file(currItem); + task_free_pending_title(currItem); } } } diff --git a/source/ui/section/action/installcias.c b/source/ui/section/action/installcias.c index 6f7d9ad..ae47927 100644 --- a/source/ui/section/action/installcias.c +++ b/source/ui/section/action/installcias.c @@ -78,9 +78,6 @@ static Result action_install_cias_close_src(void* data, u32 index, bool succeede FS_Path* fsPath = util_make_path_utf8(info->path); if(fsPath != NULL) { if(R_SUCCEEDED(FSUSER_DeleteFile(info->archive, *fsPath))) { - installData->target->containsCias = false; - installData->target->containsTickets = false; - linked_list_iter iter; linked_list_iterate(installData->items, &iter); @@ -91,10 +88,6 @@ static Result action_install_cias_close_src(void* data, u32 index, bool succeede 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; } } } @@ -303,7 +296,8 @@ static void action_install_cias_internal(linked_list* items, list_item* selected populate_files_data popData; popData.items = &data->contents; - popData.base = data->target; + popData.archive = data->target->archive; + strncpy(popData.path, data->target->path, FILE_PATH_MAX); popData.recursive = false; popData.includeBase = !data->target->isDirectory; popData.filter = util_filter_cias; diff --git a/source/ui/section/action/installtickets.c b/source/ui/section/action/installtickets.c index c261275..86c717f 100644 --- a/source/ui/section/action/installtickets.c +++ b/source/ui/section/action/installtickets.c @@ -77,9 +77,6 @@ static Result action_install_tickets_close_src(void* data, u32 index, bool succe FS_Path* fsPath = util_make_path_utf8(info->path); if(fsPath != NULL) { if(R_SUCCEEDED(FSUSER_DeleteFile(info->archive, *fsPath))) { - installData->target->containsCias = false; - installData->target->containsTickets = false; - linked_list_iter iter; linked_list_iterate(installData->items, &iter); @@ -90,10 +87,6 @@ static Result action_install_tickets_close_src(void* data, u32 index, bool succe 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; } } } @@ -280,7 +273,8 @@ static void action_install_tickets_internal(linked_list* items, list_item* selec populate_files_data popData; popData.items = &data->contents; - popData.base = data->target; + popData.archive = data->target->archive; + strncpy(popData.path, data->target->path, FILE_PATH_MAX); popData.recursive = false; popData.includeBase = !data->target->isDirectory; popData.filter = util_filter_tickets; diff --git a/source/ui/section/action/pastefiles.c b/source/ui/section/action/pastefiles.c index bc115e9..8648105 100644 --- a/source/ui/section/action/pastefiles.c +++ b/source/ui/section/action/pastefiles.c @@ -5,13 +5,13 @@ #include <3ds.h> #include "action.h" -#include "clipboard.h" #include "../task/task.h" #include "../../error.h" #include "../../info.h" #include "../../list.h" #include "../../prompt.h" #include "../../ui.h" +#include "../../../core/clipboard.h" #include "../../../core/linkedlist.h" #include "../../../core/screen.h" #include "../../../core/util.h" @@ -74,7 +74,14 @@ static Result action_paste_files_make_dst_directory(void* data, u32 index) { char parentPath[FILE_PATH_MAX]; util_get_parent_path(parentPath, dstPath, FILE_PATH_MAX); - if(strncmp(parentPath, pasteData->target->path, FILE_PATH_MAX) == 0) { + char baseDstPath[FILE_PATH_MAX]; + if(pasteData->target->isDirectory) { + strncpy(baseDstPath, pasteData->target->path, FILE_PATH_MAX); + } else { + util_get_parent_path(baseDstPath, pasteData->target->path, FILE_PATH_MAX); + } + + if(strncmp(parentPath, baseDstPath, 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); @@ -152,18 +159,17 @@ static Result action_paste_files_close_dst(void* data, u32 index, bool succeeded char parentPath[FILE_PATH_MAX]; util_get_parent_path(parentPath, dstPath, FILE_PATH_MAX); - if(strncmp(parentPath, pasteData->target->path, FILE_PATH_MAX) == 0) { + char baseDstPath[FILE_PATH_MAX]; + if(pasteData->target->isDirectory) { + strncpy(baseDstPath, pasteData->target->path, FILE_PATH_MAX); + } else { + util_get_parent_path(baseDstPath, pasteData->target->path, FILE_PATH_MAX); + } + + if(strncmp(parentPath, baseDstPath, 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; - } } } } @@ -316,7 +322,8 @@ void action_paste_contents(linked_list* items, list_item* selected) { populate_files_data popData; popData.items = &data->contents; - popData.base = (file_info*) clipboardItem->data; + popData.archive = ((file_info*) clipboardItem->data)->archive; + strncpy(popData.path, ((file_info*) clipboardItem->data)->path, FILE_PATH_MAX); popData.recursive = true; popData.includeBase = !clipboard_is_contents_only() || !util_is_dir(clipboard_get_archive(), clipboard_get_path()); popData.filter = NULL; diff --git a/source/ui/section/action/rename.c b/source/ui/section/action/rename.c index ea0154c..035df35 100644 --- a/source/ui/section/action/rename.c +++ b/source/ui/section/action/rename.c @@ -59,7 +59,10 @@ static void action_rename_kbd_finished(void* data, char* input) { } if(R_SUCCEEDED(res)) { - strncpy(renameData->target->name, input, LIST_ITEM_NAME_MAX); + if(strncmp(renameData->target->name, "", LIST_ITEM_NAME_MAX) != 0 && strncmp(renameData->target->name, "", LIST_ITEM_NAME_MAX) != 0) { + strncpy(renameData->target->name, input, LIST_ITEM_NAME_MAX); + } + strncpy(targetInfo->name, input, FILE_NAME_MAX); strncpy(targetInfo->path, dstPath, FILE_PATH_MAX); @@ -88,5 +91,5 @@ void action_rename(linked_list* items, list_item* selected) { data->items = items; data->target = selected; - kbd_display("Enter New Name", data->target->name, data, NULL, action_rename_kbd_finished, action_rename_kbd_canceled); + kbd_display("Enter New Name", ((file_info*) selected->data)->name, data, NULL, action_rename_kbd_finished, action_rename_kbd_canceled); } \ No newline at end of file diff --git a/source/ui/section/files.c b/source/ui/section/files.c index 0cf3d4a..291e888 100644 --- a/source/ui/section/files.c +++ b/source/ui/section/files.c @@ -6,12 +6,12 @@ #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/clipboard.h" #include "../../core/linkedlist.h" #include "../../core/screen.h" #include "../../core/util.h" @@ -28,10 +28,10 @@ static list_item install_and_delete_cia = {"Install and delete CIA", COLOR_TEXT, static list_item install_ticket = {"Install ticket", COLOR_TEXT, action_install_ticket}; static list_item install_and_delete_ticket = {"Install and delete ticket", COLOR_TEXT, action_install_ticket_delete}; -static list_item new_folder = {"New folder", COLOR_TEXT, action_new_folder}; 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, NULL}; +static list_item new_folder = {"New folder", COLOR_TEXT, action_new_folder}; 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}; @@ -57,13 +57,15 @@ typedef struct { bool showTickets; char currDir[FILE_PATH_MAX]; - list_item* dirItem; } files_data; typedef struct { linked_list* items; list_item* selected; files_data* parent; + + bool containsCias; + bool containsTickets; } 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) { @@ -92,7 +94,7 @@ static void files_action_update(ui_view* view, void* data, linked_list* items, l 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))) { + if(R_SUCCEEDED(res = clipboard_set_contents(actionData->parent->archive, 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, ui_draw_file_info, NULL); } else { error_display_res(NULL, info, ui_draw_file_info, res, "Failed to copy to clipboard."); @@ -110,24 +112,24 @@ static void files_action_update(ui_view* view, void* data, linked_list* items, l file_info* info = (file_info*) actionData->selected->data; if(info->isDirectory) { - if(info->containsCias) { + if(actionData->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(info->containsTickets) { + if(actionData->containsTickets) { linked_list_add(items, &install_all_tickets); linked_list_add(items, &install_and_delete_all_tickets); linked_list_add(items, &delete_all_tickets); } - linked_list_add(items, &new_folder); - linked_list_add(items, &delete_all_contents); linked_list_add(items, ©_all_contents); linked_list_add(items, &delete_dir); + + linked_list_add(items, &new_folder); } else { if(info->isCia) { linked_list_add(items, &install_cia); @@ -160,6 +162,22 @@ static void files_action_open(linked_list* items, list_item* selected, files_dat data->selected = selected; data->parent = parent; + data->containsCias = false; + data->containsTickets = false; + + linked_list_iter iter; + linked_list_iterate(data->items, &iter); + + while(linked_list_iter_has_next(&iter)) { + file_info* info = (file_info*) ((list_item*) linked_list_iter_next(&iter))->data; + + if(info->isCia) { + data->containsCias = true; + } else if(info->isTicket) { + data->containsTickets = true; + } + } + list_display(((file_info*) selected->data)->isDirectory ? "Directory Action" : "File Action", "A: Select, B: Return", data, files_action_update, files_action_draw_top); } @@ -228,19 +246,11 @@ static void files_repopulate(files_data* listData, linked_list* items) { } } - 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); - } + listData->populateData.items = items; + listData->populateData.archive = listData->archive; + strncpy(listData->populateData.path, listData->currDir, FILE_PATH_MAX); + Result res = task_populate_files(&listData->populateData); if(R_FAILED(res)) { error_display_res(NULL, NULL, NULL, res, "Failed to initiate file list population."); } @@ -262,13 +272,8 @@ static void files_free_data(files_data* data) { } } - if(data->dirItem != NULL) { - task_free_file(data->dirItem); - data->dirItem = NULL; - } - if(data->archive != 0) { - FSUSER_CloseArchive(data->archive); + util_close_archive(data->archive); data->archive = 0; } @@ -283,9 +288,12 @@ static void files_free_data(files_data* data) { static void files_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { files_data* listData = (files_data*) data; - // Detect whether the current directory was renamed by an action. - if(listData->populated && listData->dirItem != NULL && strncmp(listData->currDir, ((file_info*) listData->dirItem->data)->path, FILE_PATH_MAX) != 0) { - strncpy(listData->currDir, ((file_info*) listData->dirItem->data)->path, FILE_PATH_MAX); + if(listData->populated) { + // Detect whether the current directory was renamed by an action. + list_item* currDirItem = linked_list_get(items, 0); + if(currDirItem != NULL && strncmp(listData->currDir, ((file_info*) currDirItem->data)->path, FILE_PATH_MAX) != 0) { + strncpy(listData->currDir, ((file_info*) currDirItem->data)->path, FILE_PATH_MAX); + } } while(!util_is_dir(listData->archive, listData->currDir)) { @@ -318,15 +326,10 @@ static void files_update(ui_view* view, void* data, linked_list* items, list_ite return; } - 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(fileInfo->isDirectory) { + if(fileInfo->isDirectory && strncmp(selected->name, "", LIST_ITEM_NAME_MAX) != 0) { files_navigate(listData, items, fileInfo->path); } else { files_action_open(items, selected, listData); @@ -376,7 +379,7 @@ void files_open(FS_ArchiveID archiveId, FS_Path archivePath) { } data->populateData.recursive = false; - data->populateData.includeBase = false; + data->populateData.includeBase = true; data->populateData.filter = files_filter; data->populateData.filterData = data; @@ -409,17 +412,16 @@ void files_open(FS_ArchiveID archiveId, FS_Path archivePath) { } snprintf(data->currDir, FILE_PATH_MAX, "/"); - data->dirItem = NULL; Result res = 0; - if(R_FAILED(res = FSUSER_OpenArchive(&data->archive, archiveId, archivePath))) { + if(R_FAILED(res = util_open_archive(&data->archive, archiveId, archivePath))) { error_display_res(NULL, NULL, NULL, res, "Failed to open file listing archive."); files_free_data(data); return; } - list_display("Files", "A: Select, B: Back, X: Refresh, Y: Dir, Select: Filter", data, files_update, files_draw_top); + list_display("Files", "A: Select, B: Back, X: Refresh, Select: Filters", data, files_update, files_draw_top); } void files_open_sd() { diff --git a/source/ui/section/task/listextsavedata.c b/source/ui/section/task/listextsavedata.c index 32d5a4a..64d9a11 100644 --- a/source/ui/section/task/listextsavedata.c +++ b/source/ui/section/task/listextsavedata.c @@ -153,8 +153,9 @@ void task_clear_ext_save_data(linked_list* items) { while(linked_list_iter_has_next(&iter)) { list_item* item = (list_item*) linked_list_iter_next(&iter); - task_free_ext_save_data(item); + linked_list_iter_remove(&iter); + task_free_ext_save_data(item); } } diff --git a/source/ui/section/task/listfiles.c b/source/ui/section/task/listfiles.c index 0a807ea..07e4228 100644 --- a/source/ui/section/task/listfiles.c +++ b/source/ui/section/task/listfiles.c @@ -147,11 +147,15 @@ static void task_populate_files_thread(void* arg) { Result res = 0; - data->base->containsCias = false; - data->base->containsTickets = false; - list_item* baseItem = NULL; - if(R_SUCCEEDED(res = task_create_file_item(&baseItem, data->base->archive, data->base->path))) { + if(R_SUCCEEDED(res = task_create_file_item(&baseItem, data->archive, data->path))) { + file_info* baseInfo = (file_info*) baseItem->data; + if(baseInfo->isDirectory) { + strncpy(baseItem->name, "", LIST_ITEM_NAME_MAX); + } else { + strncpy(baseItem->name, "", LIST_ITEM_NAME_MAX); + } + linked_list queue; linked_list_init(&queue); @@ -195,16 +199,6 @@ static void task_populate_files_thread(void* arg) { list_item* item = NULL; if(R_SUCCEEDED(res = task_create_file_item(&item, curr->archive, path))) { - if(currItem == baseItem) { - 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 { @@ -275,7 +269,7 @@ void task_clear_files(linked_list* items) { } Result task_populate_files(populate_files_data* data) { - if(data == NULL || data->base == NULL || data->items == NULL) { + if(data == NULL || data->items == NULL) { return R_FBI_INVALID_ARGUMENT; } diff --git a/source/ui/section/task/listpendingtitles.c b/source/ui/section/task/listpendingtitles.c index 4ff74be..bdeb345 100644 --- a/source/ui/section/task/listpendingtitles.c +++ b/source/ui/section/task/listpendingtitles.c @@ -118,8 +118,9 @@ void task_clear_pending_titles(linked_list* items) { while(linked_list_iter_has_next(&iter)) { list_item* item = (list_item*) linked_list_iter_next(&iter); - task_free_pending_title(item); + linked_list_iter_remove(&iter); + task_free_pending_title(item); } } diff --git a/source/ui/section/task/listsystemsavedata.c b/source/ui/section/task/listsystemsavedata.c index facab85..fc164b7 100644 --- a/source/ui/section/task/listsystemsavedata.c +++ b/source/ui/section/task/listsystemsavedata.c @@ -86,8 +86,9 @@ void task_clear_system_save_data(linked_list* items) { while(linked_list_iter_has_next(&iter)) { list_item* item = (list_item*) linked_list_iter_next(&iter); - task_free_system_save_data(item); + linked_list_iter_remove(&iter); + task_free_system_save_data(item); } } diff --git a/source/ui/section/task/listtickets.c b/source/ui/section/task/listtickets.c index 148101a..5868b57 100644 --- a/source/ui/section/task/listtickets.c +++ b/source/ui/section/task/listtickets.c @@ -92,8 +92,9 @@ void task_clear_tickets(linked_list* items) { while(linked_list_iter_has_next(&iter)) { list_item* item = (list_item*) linked_list_iter_next(&iter); - task_free_ticket(item); + linked_list_iter_remove(&iter); + task_free_ticket(item); } } diff --git a/source/ui/section/task/listtitles.c b/source/ui/section/task/listtitles.c index 6a3fd61..6c5c015 100644 --- a/source/ui/section/task/listtitles.c +++ b/source/ui/section/task/listtitles.c @@ -342,8 +342,9 @@ void task_clear_titles(linked_list* items) { while(linked_list_iter_has_next(&iter)) { list_item* item = (list_item*) linked_list_iter_next(&iter); - task_free_title(item); + linked_list_iter_remove(&iter); + task_free_title(item); } } diff --git a/source/ui/section/task/task.h b/source/ui/section/task/task.h index 3c6c624..33a2371 100644 --- a/source/ui/section/task/task.h +++ b/source/ui/section/task/task.h @@ -60,14 +60,12 @@ typedef struct file_info_s { char path[FILE_PATH_MAX]; bool isDirectory; + // Files only u64 size; bool isCia; cia_info ciaInfo; bool isTicket; ticket_info ticketInfo; - - bool containsCias; - bool containsTickets; } file_info; typedef struct { @@ -148,7 +146,8 @@ typedef struct { typedef struct { linked_list* items; - file_info* base; + FS_Archive archive; + char path[FILE_PATH_MAX]; bool recursive; bool includeBase;