mirror of
https://gitlab.com/Theopse/fbi-i18n-zh.git
synced 2025-06-15 19:49:17 +08:00
Clean up file handling.
This commit is contained in:
parent
a20a389cd9
commit
8583d62ec3
@ -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;
|
||||
}
|
||||
}
|
@ -1,12 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
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();
|
@ -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, "<current directory>", LIST_ITEM_NAME_MAX) == 0 || strncmp(info1->name, "<current file>", LIST_ITEM_NAME_MAX) == 0;
|
||||
bool info2Base = strncmp(info2->name, "<current directory>", LIST_ITEM_NAME_MAX) == 0 || strncmp(info2->name, "<current file>", 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);
|
||||
}
|
@ -66,3 +66,7 @@ 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);
|
||||
|
||||
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);
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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, "<current directory>", LIST_ITEM_NAME_MAX) != 0 && strncmp(renameData->target->name, "<current file>", 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);
|
||||
}
|
@ -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, "<current directory>", 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() {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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, "<current directory>", LIST_ITEM_NAME_MAX);
|
||||
} else {
|
||||
strncpy(baseItem->name, "<current file>", 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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user