More reorganization work.

This commit is contained in:
Steven Smith 2018-02-06 17:49:25 -08:00
parent 52a2dbbf0f
commit 9fc47a1941
80 changed files with 2115 additions and 2333 deletions

14
source/core/core.h Normal file
View File

@ -0,0 +1,14 @@
#pragma once
#include "data/data.h"
#include "task/task.h"
#include "ui/ui.h"
#include "clipboard.h"
#include "error.h"
#include "fs.h"
#include "http.h"
#include "linkedlist.h"
#include "screen.h"
#include "spi.h"
#include "stringutil.h"

7
source/core/data/data.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include "bnr.h"
#include "cia.h"
#include "smdh.h"
#include "ticket.h"
#include "tmd.h"

View File

@ -11,6 +11,8 @@ typedef struct __sFILE FILE;
#define MAX_TEXTURES 1024 #define MAX_TEXTURES 1024
#define MAX_COLORS 32 #define MAX_COLORS 32
#define COLOR_TEXT 0
void screen_init(); void screen_init();
void screen_exit(); void screen_exit();
void screen_set_base_alpha(u8 alpha); void screen_set_base_alpha(u8 alpha);

View File

@ -5,15 +5,8 @@
#include <curl/curl.h> #include <curl/curl.h>
#include <jansson.h> #include <jansson.h>
#include "uitask.h" #include "dataop.h"
#include "../../prompt.h" #include "../core.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/error.h"
#include "../../../core/fs.h"
#include "../../../core/http.h"
#include "../../../core/screen.h"
#include "../../../core/task/task.h"
static Result task_data_op_check_running(data_op_data* data, u32 index, u32* srcHandle, u32* dstHandle) { static Result task_data_op_check_running(data_op_data* data, u32 index, u32* srcHandle, u32* dstHandle) {
Result res = 0; Result res = 0;

77
source/core/task/dataop.h Normal file
View File

@ -0,0 +1,77 @@
#pragma once
typedef struct json_t json_t;
typedef struct ui_view_s ui_view;
#define DOWNLOAD_URL_MAX 1024
typedef enum data_op_e {
DATAOP_COPY,
DATAOP_DOWNLOAD,
DATAOP_DELETE
} data_op;
typedef struct data_op_data_s {
void* data;
data_op op;
u32 processed;
u32 total;
// Copy
bool copyEmpty;
Result (*isSrcDirectory)(void* data, u32 index, bool* isDirectory);
Result (*makeDstDirectory)(void* data, u32 index);
Result (*openSrc)(void* data, u32 index, u32* handle);
Result (*closeSrc)(void* data, u32 index, bool succeeded, u32 handle);
Result (*getSrcSize)(void* data, u32 handle, u64* size);
Result (*readSrc)(void* data, u32 handle, u32* bytesRead, void* buffer, u64 offset, u32 size);
// Download
char (*downloadUrls)[DOWNLOAD_URL_MAX];
// Copy/Download
u64 currProcessed;
u64 currTotal;
u32 bytesPerSecond;
u32 estimatedRemainingSeconds;
u32 bufferSize;
Result (*openDst)(void* data, u32 index, void* initialReadBlock, u64 size, u32* handle);
Result (*closeDst)(void* data, u32 index, bool succeeded, u32 handle);
Result (*writeDst)(void* data, u32 handle, u32* bytesWritten, void* buffer, u64 offset, u32 size);
Result (*suspendTransfer)(void* data, u32 index, u32* srcHandle, u32* dstHandle);
Result (*restoreTransfer)(void* data, u32 index, u32* srcHandle, u32* dstHandle);
// Delete
Result (*delete)(void* data, u32 index);
// Suspend
Result (*suspend)(void* data, u32 index);
Result (*restore)(void* data, u32 index);
// Errors
bool (*error)(void* data, u32 index, Result res, ui_view** errorView);
// General
volatile bool finished;
Result result;
Handle cancelEvent;
// Internal
volatile bool retryResponse;
} data_op_data;
Result task_download_sync(const char* url, u32* downloadedSize, void* buf, size_t size);
Result task_download_json_sync(const char* url, json_t** json, size_t maxSize);
Result task_download_seed_sync(u64 titleId);
Result task_data_op(data_op_data* data);

View File

@ -4,4 +4,7 @@ void task_init();
void task_exit(); void task_exit();
bool task_is_quit_all(); bool task_is_quit_all();
Handle task_get_pause_event(); Handle task_get_pause_event();
Handle task_get_suspend_event(); Handle task_get_suspend_event();
#include "capturecam.h"
#include "dataop.h"

View File

@ -8,9 +8,9 @@
#include "error.h" #include "error.h"
#include "prompt.h" #include "prompt.h"
#include "resources.h" #include "../error.h"
#include "../core/error.h" #include "../screen.h"
#include "../core/screen.h" #include "../../fbi/resources.h"
static const char* level_to_string(Result res) { static const char* level_to_string(Result res) {
switch(R_LEVEL(res)) { switch(R_LEVEL(res)) {

View File

@ -5,9 +5,9 @@
#include "error.h" #include "error.h"
#include "info.h" #include "info.h"
#include "resources.h"
#include "ui.h" #include "ui.h"
#include "../core/screen.h" #include "../screen.h"
#include "../../fbi/resources.h"
typedef struct { typedef struct {
bool bar; bool bar;

View File

@ -4,10 +4,10 @@
#include "error.h" #include "error.h"
#include "list.h" #include "list.h"
#include "resources.h"
#include "ui.h" #include "ui.h"
#include "../core/screen.h" #include "../screen.h"
#include "../core/linkedlist.h" #include "../linkedlist.h"
#include "../../fbi/resources.h"
typedef struct { typedef struct {
void* data; void* data;

View File

@ -6,9 +6,9 @@
#include "error.h" #include "error.h"
#include "prompt.h" #include "prompt.h"
#include "resources.h"
#include "ui.h" #include "ui.h"
#include "../core/screen.h" #include "../screen.h"
#include "../../fbi/resources.h"
typedef struct { typedef struct {
const char* text; const char* text;

File diff suppressed because it is too large Load Diff

33
source/core/ui/ui.h Normal file
View File

@ -0,0 +1,33 @@
#pragma once
typedef struct ui_view_s {
const char* name;
const char* info;
void* data;
void (*update)(struct ui_view_s* view, void* data, float bx1, float by1, float bx2, float by2);
void (*drawTop)(struct ui_view_s* view, void* data, float x1, float y1, float x2, float y2);
void (*drawBottom)(struct ui_view_s* view, void* data, float x1, float y1, float x2, float y2);
Handle active;
} ui_view;
void ui_init();
void ui_exit();
ui_view* ui_create();
void ui_destroy(ui_view* view);
ui_view* ui_top();
bool ui_push(ui_view* view);
void ui_pop();
bool ui_update();
const char* ui_get_display_eta(u32 seconds);
double ui_get_display_size(u64 size);
const char* ui_get_display_size_units(u64 size);
#include "error.h"
#include "info.h"
#include "kbd.h"
#include "list.h"
#include "prompt.h"

View File

@ -3,8 +3,7 @@
#include "action.h" #include "action.h"
#include "../section.h" #include "../section.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../list.h" #include "../../core/core.h"
#include "../../../core/fs.h"
void action_browse_boss_ext_save_data(linked_list* items, list_item* selected) { void action_browse_boss_ext_save_data(linked_list* items, list_item* selected) {
ext_save_data_info* info = (ext_save_data_info*) selected->data; ext_save_data_info* info = (ext_save_data_info*) selected->data;

View File

@ -3,8 +3,7 @@
#include "action.h" #include "action.h"
#include "../section.h" #include "../section.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../list.h" #include "../../core/core.h"
#include "../../../core/fs.h"
void action_browse_system_save_data(linked_list* items, list_item* selected) { void action_browse_system_save_data(linked_list* items, list_item* selected) {
system_save_data_info* info = (system_save_data_info*) selected->data; system_save_data_info* info = (system_save_data_info*) selected->data;

View File

@ -3,8 +3,7 @@
#include "action.h" #include "action.h"
#include "../section.h" #include "../section.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../list.h" #include "../../core/core.h"
#include "../../../core/fs.h"
void action_browse_title_save_data(linked_list* items, list_item* selected) { void action_browse_title_save_data(linked_list* items, list_item* selected) {
title_info* info = (title_info*) selected->data; title_info* info = (title_info*) selected->data;

View File

@ -3,8 +3,7 @@
#include "action.h" #include "action.h"
#include "../section.h" #include "../section.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../list.h" #include "../../core/core.h"
#include "../../../core/fs.h"
void action_browse_user_ext_save_data(linked_list* items, list_item* selected) { void action_browse_user_ext_save_data(linked_list* items, list_item* selected) {
ext_save_data_info* info = (ext_save_data_info*) selected->data; ext_save_data_info* info = (ext_save_data_info*) selected->data;

View File

@ -5,17 +5,9 @@
#include <3ds.h> #include <3ds.h>
#include "action.h" #include "action.h"
#include "../resources.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../info.h"
#include "../../list.h"
#include "../../prompt.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/error.h"
#include "../../../core/fs.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
typedef struct { typedef struct {
linked_list* items; linked_list* items;
@ -33,9 +25,9 @@ static void action_delete_draw_top(ui_view* view, void* data, float x1, float y1
u32 curr = deleteData->deleteInfo.processed; u32 curr = deleteData->deleteInfo.processed;
if(curr < deleteData->deleteInfo.total) { if(curr < deleteData->deleteInfo.total) {
ui_draw_file_info(view, ((list_item*) linked_list_get(&deleteData->contents, linked_list_size(&deleteData->contents) - curr - 1))->data, x1, y1, x2, y2); task_draw_file_info(view, ((list_item*) linked_list_get(&deleteData->contents, linked_list_size(&deleteData->contents) - curr - 1))->data, x1, y1, x2, y2);
} else { } else {
ui_draw_file_info(view, deleteData->target, x1, y1, x2, y2); task_draw_file_info(view, deleteData->target, x1, y1, x2, y2);
} }
} }

View File

@ -3,15 +3,9 @@
#include <3ds.h> #include <3ds.h>
#include "action.h" #include "action.h"
#include "../resources.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../info.h"
#include "../../list.h"
#include "../../prompt.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
typedef struct { typedef struct {
linked_list* items; linked_list* items;
@ -19,7 +13,7 @@ typedef struct {
} delete_ext_save_data_data; } delete_ext_save_data_data;
static void action_delete_ext_save_data_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { static void action_delete_ext_save_data_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
ui_draw_ext_save_data_info(view, ((delete_ext_save_data_data*) data)->selected->data, x1, y1, x2, y2); task_draw_ext_save_data_info(view, ((delete_ext_save_data_data*) data)->selected->data, x1, y1, x2, y2);
} }
static void action_delete_ext_save_data_update(ui_view* view, void* data, float* progress, char* text) { static void action_delete_ext_save_data_update(ui_view* view, void* data, float* progress, char* text) {
@ -33,7 +27,7 @@ static void action_delete_ext_save_data_update(ui_view* view, void* data, float*
info_destroy(view); info_destroy(view);
if(R_FAILED(res)) { if(R_FAILED(res)) {
error_display_res(info, ui_draw_ext_save_data_info, res, "Failed to delete ext save data."); error_display_res(info, task_draw_ext_save_data_info, res, "Failed to delete ext save data.");
} else { } else {
linked_list_remove(deleteData->items, deleteData->selected); linked_list_remove(deleteData->items, deleteData->selected);
task_free_ext_save_data(deleteData->selected); task_free_ext_save_data(deleteData->selected);

View File

@ -5,15 +5,9 @@
#include <3ds.h> #include <3ds.h>
#include "action.h" #include "action.h"
#include "../resources.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../info.h"
#include "../../list.h"
#include "../../prompt.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
typedef struct { typedef struct {
linked_list* items; linked_list* items;
@ -30,7 +24,7 @@ static void action_delete_pending_titles_draw_top(ui_view* view, void* data, flo
u32 index = deleteData->deleteInfo.processed; u32 index = deleteData->deleteInfo.processed;
if(index < deleteData->deleteInfo.total) { 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); task_draw_pending_title_info(view, (pending_title_info*) ((list_item*) linked_list_get(&deleteData->contents, index))->data, x1, y1, x2, y2);
} }
} }

View File

@ -3,15 +3,9 @@
#include <3ds.h> #include <3ds.h>
#include "action.h" #include "action.h"
#include "../resources.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../info.h"
#include "../../list.h"
#include "../../prompt.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
static void action_delete_secure_value_update(ui_view* view, void* data, float* progress, char* text) { static void action_delete_secure_value_update(ui_view* view, void* data, float* progress, char* text) {
title_info* info = (title_info*) data; title_info* info = (title_info*) data;
@ -24,18 +18,18 @@ static void action_delete_secure_value_update(ui_view* view, void* data, float*
info_destroy(view); info_destroy(view);
if(R_FAILED(res)) { if(R_FAILED(res)) {
error_display_res(info, ui_draw_title_info, res, "Failed to delete secure value."); error_display_res(info, task_draw_title_info, res, "Failed to delete secure value.");
} else { } else {
prompt_display_notify("Success", "Secure value deleted.", COLOR_TEXT, info, ui_draw_title_info, NULL); prompt_display_notify("Success", "Secure value deleted.", COLOR_TEXT, info, task_draw_title_info, NULL);
} }
} }
static void action_delete_secure_value_onresponse(ui_view* view, void* data, u32 response) { static void action_delete_secure_value_onresponse(ui_view* view, void* data, u32 response) {
if(response == PROMPT_YES) { if(response == PROMPT_YES) {
info_display("Deleting Secure Value", "", false, data, action_delete_secure_value_update, ui_draw_title_info); info_display("Deleting Secure Value", "", false, data, action_delete_secure_value_update, task_draw_title_info);
} }
} }
void action_delete_secure_value(linked_list* items, list_item* selected) { void action_delete_secure_value(linked_list* items, list_item* selected) {
prompt_display_yes_no("Confirmation", "Delete the secure value of the selected title?", COLOR_TEXT, selected->data, ui_draw_title_info, action_delete_secure_value_onresponse); prompt_display_yes_no("Confirmation", "Delete the secure value of the selected title?", COLOR_TEXT, selected->data, task_draw_title_info, action_delete_secure_value_onresponse);
} }

View File

@ -3,15 +3,9 @@
#include <3ds.h> #include <3ds.h>
#include "action.h" #include "action.h"
#include "../resources.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../info.h"
#include "../../list.h"
#include "../../prompt.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
typedef struct { typedef struct {
linked_list* items; linked_list* items;
@ -19,7 +13,7 @@ typedef struct {
} delete_system_save_data_data; } delete_system_save_data_data;
static void action_delete_system_save_data_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { static void action_delete_system_save_data_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
ui_draw_system_save_data_info(view, ((delete_system_save_data_data*) data)->selected->data, x1, y1, x2, y2); task_draw_system_save_data_info(view, ((delete_system_save_data_data*) data)->selected->data, x1, y1, x2, y2);
} }
static void action_delete_system_save_data_update(ui_view* view, void* data, float* progress, char* text) { static void action_delete_system_save_data_update(ui_view* view, void* data, float* progress, char* text) {
@ -34,7 +28,7 @@ static void action_delete_system_save_data_update(ui_view* view, void* data, flo
info_destroy(view); info_destroy(view);
if(R_FAILED(res)) { if(R_FAILED(res)) {
error_display_res(info, ui_draw_system_save_data_info, res, "Failed to delete system save data."); error_display_res(info, task_draw_system_save_data_info, res, "Failed to delete system save data.");
} else { } else {
linked_list_remove(deleteData->items, deleteData->selected); linked_list_remove(deleteData->items, deleteData->selected);
task_free_system_save_data(deleteData->selected); task_free_system_save_data(deleteData->selected);

View File

@ -4,15 +4,9 @@
#include <3ds.h> #include <3ds.h>
#include "action.h" #include "action.h"
#include "../resources.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../info.h"
#include "../../list.h"
#include "../../prompt.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
typedef struct { typedef struct {
linked_list* items; linked_list* items;
@ -28,7 +22,7 @@ static void action_delete_tickets_draw_top(ui_view* view, void* data, float x1,
u32 curr = deleteData->deleteInfo.processed; u32 curr = deleteData->deleteInfo.processed;
if(curr < deleteData->deleteInfo.total) { if(curr < deleteData->deleteInfo.total) {
ui_draw_ticket_info(view, ((list_item*) linked_list_get(&deleteData->contents, curr))->data, x1, y1, x2, y2); task_draw_ticket_info(view, ((list_item*) linked_list_get(&deleteData->contents, curr))->data, x1, y1, x2, y2);
} }
} }

View File

@ -3,15 +3,9 @@
#include <3ds.h> #include <3ds.h>
#include "action.h" #include "action.h"
#include "../resources.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../info.h"
#include "../../list.h"
#include "../../prompt.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
typedef struct { typedef struct {
linked_list* items; linked_list* items;
@ -20,7 +14,7 @@ typedef struct {
} delete_title_data; } delete_title_data;
static void action_delete_title_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { static void action_delete_title_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
ui_draw_title_info(view, ((delete_title_data*) data)->selected->data, x1, y1, x2, y2); task_draw_title_info(view, ((delete_title_data*) data)->selected->data, x1, y1, x2, y2);
} }
static void action_delete_title_update(ui_view* view, void* data, float* progress, char* text) { static void action_delete_title_update(ui_view* view, void* data, float* progress, char* text) {
@ -38,7 +32,7 @@ static void action_delete_title_update(ui_view* view, void* data, float* progres
info_destroy(view); info_destroy(view);
if(R_FAILED(res)) { if(R_FAILED(res)) {
error_display_res(info, ui_draw_title_info, res, "Failed to delete title."); error_display_res(info, task_draw_title_info, res, "Failed to delete title.");
} else { } else {
linked_list_remove(deleteData->items, deleteData->selected); linked_list_remove(deleteData->items, deleteData->selected);
task_free_title(deleteData->selected); task_free_title(deleteData->selected);

View File

@ -5,17 +5,9 @@
#include <3ds.h> #include <3ds.h>
#include "action.h" #include "action.h"
#include "../resources.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../info.h"
#include "../../list.h"
#include "../../prompt.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
#include "../../../core/spi.h"
#include "../../../core/stringutil.h"
typedef struct { typedef struct {
title_info* title; title_info* title;
@ -24,7 +16,7 @@ typedef struct {
} erase_twl_save_data; } erase_twl_save_data;
static void action_erase_twl_save_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { static void action_erase_twl_save_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
ui_draw_title_info(view, ((erase_twl_save_data*) data)->title, x1, y1, x2, y2); task_draw_title_info(view, ((erase_twl_save_data*) data)->title, x1, y1, x2, y2);
} }
static Result action_erase_twl_save_is_src_directory(void* data, u32 index, bool* isDirectory) { static Result action_erase_twl_save_is_src_directory(void* data, u32 index, bool* isDirectory) {
@ -91,7 +83,7 @@ static Result action_erase_twl_save_restore(void* data, u32 index) {
} }
static bool action_erase_twl_save_error(void* data, u32 index, Result res, ui_view** errorView) { static bool action_erase_twl_save_error(void* data, u32 index, Result res, ui_view** errorView) {
*errorView = error_display_res(((erase_twl_save_data*) data)->title, ui_draw_title_info, res, "Failed to erase save."); *errorView = error_display_res(((erase_twl_save_data*) data)->title, task_draw_title_info, res, "Failed to erase save.");
return true; return true;
} }
@ -103,7 +95,7 @@ static void action_erase_twl_save_update(ui_view* view, void* data, float* progr
info_destroy(view); info_destroy(view);
if(R_SUCCEEDED(eraseData->eraseInfo.result)) { if(R_SUCCEEDED(eraseData->eraseInfo.result)) {
prompt_display_notify("Success", "Save erased.", COLOR_TEXT, eraseData->title, ui_draw_title_info, NULL); prompt_display_notify("Success", "Save erased.", COLOR_TEXT, eraseData->title, task_draw_title_info, NULL);
} }
free(data); free(data);
@ -134,7 +126,7 @@ static void action_erase_twl_save_onresponse(ui_view* view, void* data, u32 resp
if(R_SUCCEEDED(res)) { if(R_SUCCEEDED(res)) {
info_display("Erasing Save", "Press B to cancel.", true, data, action_erase_twl_save_update, action_erase_twl_save_draw_top); info_display("Erasing Save", "Press B to cancel.", true, data, action_erase_twl_save_update, action_erase_twl_save_draw_top);
} else { } else {
error_display_res(eraseData->title, ui_draw_title_info, res, "Failed to initiate save erase."); error_display_res(eraseData->title, task_draw_title_info, res, "Failed to initiate save erase.");
free(data); free(data);
} }
} else { } else {

View File

@ -3,17 +3,9 @@
#include <3ds.h> #include <3ds.h>
#include "action.h" #include "action.h"
#include "../resources.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../info.h"
#include "../../list.h"
#include "../../prompt.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/error.h"
#include "../../../core/fs.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
static void action_export_secure_value_update(ui_view* view, void* data, float* progress, char* text) { static void action_export_secure_value_update(ui_view* view, void* data, float* progress, char* text) {
title_info* info = (title_info*) data; title_info* info = (title_info*) data;
@ -27,7 +19,7 @@ static void action_export_secure_value_update(ui_view* view, void* data, float*
ui_pop(); ui_pop();
info_destroy(view); info_destroy(view);
prompt_display_notify("Failure", "Secure value not set.", COLOR_TEXT, info, ui_draw_title_info, NULL); prompt_display_notify("Failure", "Secure value not set.", COLOR_TEXT, info, task_draw_title_info, NULL);
return; return;
} }
@ -61,18 +53,18 @@ static void action_export_secure_value_update(ui_view* view, void* data, float*
info_destroy(view); info_destroy(view);
if(R_SUCCEEDED(res)) { if(R_SUCCEEDED(res)) {
prompt_display_notify("Success", "Secure value exported.", COLOR_TEXT, info, ui_draw_title_info, NULL); prompt_display_notify("Success", "Secure value exported.", COLOR_TEXT, info, task_draw_title_info, NULL);
} else { } else {
error_display_res(info, ui_draw_title_info, res, "Failed to export secure value."); error_display_res(info, task_draw_title_info, res, "Failed to export secure value.");
} }
} }
static void action_export_secure_value_onresponse(ui_view* view, void* data, u32 response) { static void action_export_secure_value_onresponse(ui_view* view, void* data, u32 response) {
if(response == PROMPT_YES) { if(response == PROMPT_YES) {
info_display("Exporting Secure Value", "", false, data, action_export_secure_value_update, ui_draw_title_info); info_display("Exporting Secure Value", "", false, data, action_export_secure_value_update, task_draw_title_info);
} }
} }
void action_export_secure_value(linked_list* items, list_item* selected) { void action_export_secure_value(linked_list* items, list_item* selected) {
prompt_display_yes_no("Confirmation", "Export the secure value of the selected title?", COLOR_TEXT, selected->data, ui_draw_title_info, action_export_secure_value_onresponse); prompt_display_yes_no("Confirmation", "Export the secure value of the selected title?", COLOR_TEXT, selected->data, task_draw_title_info, action_export_secure_value_onresponse);
} }

View File

@ -4,19 +4,9 @@
#include <3ds.h> #include <3ds.h>
#include "action.h" #include "action.h"
#include "../resources.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../info.h"
#include "../../list.h"
#include "../../prompt.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/error.h"
#include "../../../core/fs.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
#include "../../../core/spi.h"
#include "../../../core/stringutil.h"
typedef struct { typedef struct {
title_info* title; title_info* title;
@ -25,7 +15,7 @@ typedef struct {
} export_twl_save_data; } export_twl_save_data;
static void action_export_twl_save_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { static void action_export_twl_save_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
ui_draw_title_info(view, ((export_twl_save_data*) data)->title, x1, y1, x2, y2); task_draw_title_info(view, ((export_twl_save_data*) data)->title, x1, y1, x2, y2);
} }
static Result action_export_twl_save_is_src_directory(void* data, u32 index, bool* isDirectory) { static Result action_export_twl_save_is_src_directory(void* data, u32 index, bool* isDirectory) {
@ -115,7 +105,7 @@ static Result action_export_twl_save_restore(void* data, u32 index) {
} }
static bool action_export_twl_save_error(void* data, u32 index, Result res, ui_view** errorView) { static bool action_export_twl_save_error(void* data, u32 index, Result res, ui_view** errorView) {
*errorView = error_display_res(((export_twl_save_data*) data)->title, ui_draw_title_info, res, "Failed to export save."); *errorView = error_display_res(((export_twl_save_data*) data)->title, task_draw_title_info, res, "Failed to export save.");
return true; return true;
} }
@ -127,7 +117,7 @@ static void action_export_twl_save_update(ui_view* view, void* data, float* prog
info_destroy(view); info_destroy(view);
if(R_SUCCEEDED(exportData->exportInfo.result)) { if(R_SUCCEEDED(exportData->exportInfo.result)) {
prompt_display_notify("Success", "Save exported.", COLOR_TEXT, exportData->title, ui_draw_title_info, NULL); prompt_display_notify("Success", "Save exported.", COLOR_TEXT, exportData->title, task_draw_title_info, NULL);
} }
free(data); free(data);
@ -158,7 +148,7 @@ static void action_export_twl_save_onresponse(ui_view* view, void* data, u32 res
if(R_SUCCEEDED(res)) { if(R_SUCCEEDED(res)) {
info_display("Exporting Save", "Press B to cancel.", true, data, action_export_twl_save_update, action_export_twl_save_draw_top); info_display("Exporting Save", "Press B to cancel.", true, data, action_export_twl_save_update, action_export_twl_save_draw_top);
} else { } else {
error_display_res(exportData->title, ui_draw_title_info, res, "Failed to initiate save export."); error_display_res(exportData->title, task_draw_title_info, res, "Failed to initiate save export.");
free(data); free(data);
} }
} else { } else {

View File

@ -4,18 +4,9 @@
#include <3ds.h> #include <3ds.h>
#include "action.h" #include "action.h"
#include "../resources.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../info.h"
#include "../../list.h"
#include "../../prompt.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/error.h"
#include "../../../core/fs.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
#include "../../../core/data/smdh.h"
static void action_extract_smdh_update(ui_view* view, void* data, float* progress, char* text) { static void action_extract_smdh_update(ui_view* view, void* data, float* progress, char* text) {
title_info* info = (title_info*) data; title_info* info = (title_info*) data;
@ -70,18 +61,18 @@ static void action_extract_smdh_update(ui_view* view, void* data, float* progres
info_destroy(view); info_destroy(view);
if(R_SUCCEEDED(res)) { if(R_SUCCEEDED(res)) {
prompt_display_notify("Success", "SMDH extracted.", COLOR_TEXT, info, ui_draw_title_info, NULL); prompt_display_notify("Success", "SMDH extracted.", COLOR_TEXT, info, task_draw_title_info, NULL);
} else { } else {
error_display_res(info, ui_draw_title_info, res, "Failed to extract SMDH."); error_display_res(info, task_draw_title_info, res, "Failed to extract SMDH.");
} }
} }
static void action_extract_smdh_onresponse(ui_view* view, void* data, u32 response) { static void action_extract_smdh_onresponse(ui_view* view, void* data, u32 response) {
if(response == PROMPT_YES) { if(response == PROMPT_YES) {
info_display("Extracting SMDH", "", false, data, action_extract_smdh_update, ui_draw_title_info); info_display("Extracting SMDH", "", false, data, action_extract_smdh_update, task_draw_title_info);
} }
} }
void action_extract_smdh(linked_list* items, list_item* selected) { void action_extract_smdh(linked_list* items, list_item* selected) {
prompt_display_yes_no("Confirmation", "Extract the SMDH of the selected title?", COLOR_TEXT, selected->data, ui_draw_title_info, action_extract_smdh_onresponse); prompt_display_yes_no("Confirmation", "Extract the SMDH of the selected title?", COLOR_TEXT, selected->data, task_draw_title_info, action_extract_smdh_onresponse);
} }

View File

@ -3,17 +3,9 @@
#include <3ds.h> #include <3ds.h>
#include "action.h" #include "action.h"
#include "../resources.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../info.h"
#include "../../list.h"
#include "../../prompt.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/error.h"
#include "../../../core/fs.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
static void action_import_secure_value_update(ui_view* view, void* data, float* progress, char* text) { static void action_import_secure_value_update(ui_view* view, void* data, float* progress, char* text) {
title_info* info = (title_info*) data; title_info* info = (title_info*) data;
@ -45,18 +37,18 @@ static void action_import_secure_value_update(ui_view* view, void* data, float*
info_destroy(view); info_destroy(view);
if(R_SUCCEEDED(res)) { if(R_SUCCEEDED(res)) {
prompt_display_notify("Success", "Secure value imported.", COLOR_TEXT, info, ui_draw_title_info, NULL); prompt_display_notify("Success", "Secure value imported.", COLOR_TEXT, info, task_draw_title_info, NULL);
} else { } else {
error_display_res(info, ui_draw_title_info, res, "Failed to import secure value."); error_display_res(info, task_draw_title_info, res, "Failed to import secure value.");
} }
} }
static void action_import_secure_value_onresponse(ui_view* view, void* data, u32 response) { static void action_import_secure_value_onresponse(ui_view* view, void* data, u32 response) {
if(response == PROMPT_YES) { if(response == PROMPT_YES) {
info_display("Importing Secure Value", "", false, data, action_import_secure_value_update, ui_draw_title_info); info_display("Importing Secure Value", "", false, data, action_import_secure_value_update, task_draw_title_info);
} }
} }
void action_import_secure_value(linked_list* items, list_item* selected) { void action_import_secure_value(linked_list* items, list_item* selected) {
prompt_display_yes_no("Confirmation", "Import the secure value of the selected title?", COLOR_TEXT, selected->data, ui_draw_title_info, action_import_secure_value_onresponse); prompt_display_yes_no("Confirmation", "Import the secure value of the selected title?", COLOR_TEXT, selected->data, task_draw_title_info, action_import_secure_value_onresponse);
} }

View File

@ -3,15 +3,9 @@
#include <3ds.h> #include <3ds.h>
#include "action.h" #include "action.h"
#include "../resources.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../info.h"
#include "../../list.h"
#include "../../prompt.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
static void action_import_seed_update(ui_view* view, void* data, float* progress, char* text) { static void action_import_seed_update(ui_view* view, void* data, float* progress, char* text) {
title_info* info = (title_info*) data; title_info* info = (title_info*) data;
@ -22,18 +16,18 @@ static void action_import_seed_update(ui_view* view, void* data, float* progress
info_destroy(view); info_destroy(view);
if(R_SUCCEEDED(res)) { if(R_SUCCEEDED(res)) {
prompt_display_notify("Success", "Seed imported.", COLOR_TEXT, info, ui_draw_title_info, NULL); prompt_display_notify("Success", "Seed imported.", COLOR_TEXT, info, task_draw_title_info, NULL);
} else { } else {
error_display_res(info, ui_draw_title_info, res, "Failed to import seed."); error_display_res(info, task_draw_title_info, res, "Failed to import seed.");
} }
} }
static void action_import_seed_onresponse(ui_view* view, void* data, u32 response) { static void action_import_seed_onresponse(ui_view* view, void* data, u32 response) {
if(response == PROMPT_YES) { if(response == PROMPT_YES) {
info_display("Importing Seed", "", false, data, action_import_seed_update, ui_draw_title_info); info_display("Importing Seed", "", false, data, action_import_seed_update, task_draw_title_info);
} }
} }
void action_import_seed(linked_list* items, list_item* selected) { void action_import_seed(linked_list* items, list_item* selected) {
prompt_display_yes_no("Confirmation", "Import the seed of the selected title?", COLOR_TEXT, selected->data, ui_draw_title_info, action_import_seed_onresponse); prompt_display_yes_no("Confirmation", "Import the seed of the selected title?", COLOR_TEXT, selected->data, task_draw_title_info, action_import_seed_onresponse);
} }

View File

@ -4,19 +4,9 @@
#include <3ds.h> #include <3ds.h>
#include "action.h" #include "action.h"
#include "../resources.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../info.h"
#include "../../list.h"
#include "../../prompt.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/error.h"
#include "../../../core/fs.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
#include "../../../core/spi.h"
#include "../../../core/stringutil.h"
typedef struct { typedef struct {
title_info* title; title_info* title;
@ -25,7 +15,7 @@ typedef struct {
} import_twl_save_data; } import_twl_save_data;
static void action_import_twl_save_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { static void action_import_twl_save_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
ui_draw_title_info(view, ((import_twl_save_data*) data)->title, x1, y1, x2, y2); task_draw_title_info(view, ((import_twl_save_data*) data)->title, x1, y1, x2, y2);
} }
static Result action_import_twl_save_is_src_directory(void* data, u32 index, bool* isDirectory) { static Result action_import_twl_save_is_src_directory(void* data, u32 index, bool* isDirectory) {
@ -101,7 +91,7 @@ static Result action_import_twl_save_restore(void* data, u32 index) {
} }
static bool action_import_twl_save_error(void* data, u32 index, Result res, ui_view** errorView) { static bool action_import_twl_save_error(void* data, u32 index, Result res, ui_view** errorView) {
*errorView = error_display_res(((import_twl_save_data*) data)->title, ui_draw_title_info, res, "Failed to import save."); *errorView = error_display_res(((import_twl_save_data*) data)->title, task_draw_title_info, res, "Failed to import save.");
return true; return true;
} }
@ -113,7 +103,7 @@ static void action_import_twl_save_update(ui_view* view, void* data, float* prog
info_destroy(view); info_destroy(view);
if(R_SUCCEEDED(importData->importInfo.result)) { if(R_SUCCEEDED(importData->importInfo.result)) {
prompt_display_notify("Success", "Save imported.", COLOR_TEXT, importData->title, ui_draw_title_info, NULL); prompt_display_notify("Success", "Save imported.", COLOR_TEXT, importData->title, task_draw_title_info, NULL);
} }
free(data); free(data);
@ -144,7 +134,7 @@ static void action_import_twl_save_onresponse(ui_view* view, void* data, u32 res
if(R_SUCCEEDED(res)) { if(R_SUCCEEDED(res)) {
info_display("Importing Save", "Press B to cancel.", true, data, action_import_twl_save_update, action_import_twl_save_draw_top); info_display("Importing Save", "Press B to cancel.", true, data, action_import_twl_save_update, action_import_twl_save_draw_top);
} else { } else {
error_display_res(importData->title, ui_draw_title_info, res, "Failed to initiate save import."); error_display_res(importData->title, task_draw_title_info, res, "Failed to initiate save import.");
free(data); free(data);
} }
} else { } else {

View File

@ -5,20 +5,9 @@
#include <3ds.h> #include <3ds.h>
#include "action.h" #include "action.h"
#include "../resources.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../info.h"
#include "../../kbd.h"
#include "../../list.h"
#include "../../prompt.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/error.h"
#include "../../../core/fs.h"
#include "../../../core/http.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
#include "../../../core/data/tmd.h"
#define CONTENTS_MAX 256 #define CONTENTS_MAX 256
@ -178,13 +167,13 @@ static Result action_install_cdn_restore(void* data, u32 index) {
bool action_install_cdn_error(void* data, u32 index, Result res, ui_view** errorView) { bool action_install_cdn_error(void* data, u32 index, Result res, ui_view** errorView) {
install_cdn_data* installData = (install_cdn_data*) data; install_cdn_data* installData = (install_cdn_data*) data;
*errorView = error_display_res(installData->ticket, ui_draw_ticket_info, res, "Failed to install %s from CDN.", index == 0 ? "TMD" : "content"); *errorView = error_display_res(installData->ticket, task_draw_ticket_info, res, "Failed to install %s from CDN.", index == 0 ? "TMD" : "content");
return false; return false;
} }
static void action_install_cdn_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { static void action_install_cdn_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
ui_draw_ticket_info(view, ((install_cdn_data*) data)->ticket, x1, y1, x2, y2); task_draw_ticket_info(view, ((install_cdn_data*) data)->ticket, x1, y1, x2, y2);
} }
static void action_install_cdn_free_data(install_cdn_data* data) { static void action_install_cdn_free_data(install_cdn_data* data) {
@ -221,13 +210,13 @@ static void action_install_cdn_update(ui_view* view, void* data, float* progress
task_populate_tickets_update_use(installData->item); task_populate_tickets_update_use(installData->item);
} }
prompt_display_notify("Success", "Install finished.", COLOR_TEXT, installData->ticket, ui_draw_ticket_info, NULL); prompt_display_notify("Success", "Install finished.", COLOR_TEXT, installData->ticket, task_draw_ticket_info, NULL);
} }
} else { } else {
AM_InstallTitleAbort(); AM_InstallTitleAbort();
if(R_FAILED(res)) { if(R_FAILED(res)) {
error_display_res(installData->ticket, ui_draw_ticket_info, res, "Failed to install CDN title."); error_display_res(installData->ticket, task_draw_ticket_info, res, "Failed to install CDN title.");
} }
} }
@ -273,7 +262,7 @@ static void action_install_cdn_n3ds_onresponse(ui_view* view, void* data, u32 re
} }
if(R_FAILED(res)) { if(R_FAILED(res)) {
error_display_res(installData->ticket, ui_draw_ticket_info, res, "Failed to initiate CDN title installation."); error_display_res(installData->ticket, task_draw_ticket_info, res, "Failed to initiate CDN title installation.");
action_install_cdn_free_data(data); action_install_cdn_free_data(data);
} }
@ -375,5 +364,5 @@ static void action_install_cdn_onresponse(ui_view* view, void* data, u32 respons
void action_install_cdn(linked_list* items, list_item* selected) { void action_install_cdn(linked_list* items, list_item* selected) {
static const char* options[3] = {"Default\nVersion", "Select\nVersion", "No"}; static const char* options[3] = {"Default\nVersion", "Select\nVersion", "No"};
static u32 optionButtons[3] = {KEY_A, KEY_X, KEY_B}; static u32 optionButtons[3] = {KEY_A, KEY_X, KEY_B};
prompt_display_multi_choice("Confirmation", "Install the selected title from the CDN?", COLOR_TEXT, options, optionButtons, 3, selected, ui_draw_ticket_info, action_install_cdn_onresponse); prompt_display_multi_choice("Confirmation", "Install the selected title from the CDN?", COLOR_TEXT, options, optionButtons, 3, selected, task_draw_ticket_info, action_install_cdn_onresponse);
} }

View File

@ -5,17 +5,9 @@
#include <3ds.h> #include <3ds.h>
#include "action.h" #include "action.h"
#include "../resources.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../info.h"
#include "../../list.h"
#include "../../prompt.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/error.h"
#include "../../../core/fs.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
typedef struct { typedef struct {
linked_list* items; linked_list* items;
@ -41,9 +33,9 @@ static void action_install_cias_draw_top(ui_view* view, void* data, float x1, fl
u32 curr = installData->installInfo.processed; u32 curr = installData->installInfo.processed;
if(curr < installData->installInfo.total) { if(curr < installData->installInfo.total) {
ui_draw_file_info(view, ((list_item*) linked_list_get(&installData->contents, curr))->data, x1, y1, x2, y2); task_draw_file_info(view, ((list_item*) linked_list_get(&installData->contents, curr))->data, x1, y1, x2, y2);
} else { } else {
ui_draw_file_info(view, installData->target, x1, y1, x2, y2); task_draw_file_info(view, installData->target, x1, y1, x2, y2);
} }
} }

View File

@ -5,17 +5,9 @@
#include <3ds.h> #include <3ds.h>
#include "action.h" #include "action.h"
#include "../resources.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../info.h"
#include "../../list.h"
#include "../../prompt.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/error.h"
#include "../../../core/fs.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
typedef struct { typedef struct {
linked_list* items; linked_list* items;
@ -37,9 +29,9 @@ static void action_install_tickets_draw_top(ui_view* view, void* data, float x1,
u32 curr = installData->installInfo.processed; u32 curr = installData->installInfo.processed;
if(curr < installData->installInfo.total) { if(curr < installData->installInfo.total) {
ui_draw_file_info(view, ((list_item*) linked_list_get(&installData->contents, curr))->data, x1, y1, x2, y2); task_draw_file_info(view, ((list_item*) linked_list_get(&installData->contents, curr))->data, x1, y1, x2, y2);
} else { } else {
ui_draw_file_info(view, installData->target, x1, y1, x2, y2); task_draw_file_info(view, installData->target, x1, y1, x2, y2);
} }
} }

View File

@ -1,61 +1,57 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <3ds.h> #include <3ds.h>
#include "action.h" #include "action.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../list.h"
#include "../../ui.h" typedef struct {
#include "../../../core/linkedlist.h" list_item* selected;
#include "../../../core/stringutil.h" bool cia;
} install_titledb_data;
typedef struct {
list_item* selected; static void action_install_titledb_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, u32 index) {
bool cia; install_titledb_data* installData = (install_titledb_data*) data;
} install_titledb_data;
if(installData->cia) {
static void action_install_titledb_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, u32 index) { task_draw_titledb_info_cia(view, installData->selected->data, x1, y1, x2, y2);
install_titledb_data* installData = (install_titledb_data*) data; } else {
task_draw_titledb_info_tdsx(view, installData->selected->data, x1, y1, x2, y2);
if(installData->cia) { }
ui_draw_titledb_info_cia(view, installData->selected->data, x1, y1, x2, y2); }
} else {
ui_draw_titledb_info_tdsx(view, installData->selected->data, x1, y1, x2, y2); static void action_update_titledb_finished(void* data) {
} task_populate_titledb_update_status(((install_titledb_data*) data)->selected);
}
free(data);
static void action_update_titledb_finished(void* data) { }
task_populate_titledb_update_status(((install_titledb_data*) data)->selected);
void action_install_titledb(linked_list* items, list_item* selected, bool cia) {
free(data); install_titledb_data* data = (install_titledb_data*) calloc(1, sizeof(install_titledb_data));
} if(data == NULL) {
error_display(NULL, NULL, "Failed to allocate install TitleDB data.");
void action_install_titledb(linked_list* items, list_item* selected, bool cia) {
install_titledb_data* data = (install_titledb_data*) calloc(1, sizeof(install_titledb_data)); return;
if(data == NULL) { }
error_display(NULL, NULL, "Failed to allocate install TitleDB data.");
data->selected = selected;
return; data->cia = cia;
}
titledb_info* info = (titledb_info*) selected->data;
data->selected = selected;
data->cia = cia; char url[64];
char path3dsx[FILE_PATH_MAX];
titledb_info* info = (titledb_info*) selected->data; if(data->cia) {
snprintf(url, DOWNLOAD_URL_MAX, "https://3ds.titledb.com/v1/cia/%lu/download", info->cia.id);
char url[64]; } else {
char path3dsx[FILE_PATH_MAX]; snprintf(url, DOWNLOAD_URL_MAX, "https://3ds.titledb.com/v1/tdsx/%lu/download", info->tdsx.id);
if(data->cia) {
snprintf(url, DOWNLOAD_URL_MAX, "https://3ds.titledb.com/v1/cia/%lu/download", info->cia.id); char name[FILE_NAME_MAX];
} else { string_escape_file_name(name, info->meta.shortDescription, sizeof(name));
snprintf(url, DOWNLOAD_URL_MAX, "https://3ds.titledb.com/v1/tdsx/%lu/download", info->tdsx.id); snprintf(path3dsx, sizeof(path3dsx), "/3ds/%s/%s.3dsx", name, name);
}
char name[FILE_NAME_MAX];
string_escape_file_name(name, info->meta.shortDescription, sizeof(name)); action_install_url("Install the selected title from TitleDB?", url, path3dsx, data, action_update_titledb_finished, action_install_titledb_draw_top);
snprintf(path3dsx, sizeof(path3dsx), "/3ds/%s/%s.3dsx", name, name);
}
action_install_url("Install the selected title from TitleDB?", url, path3dsx, data, action_update_titledb_finished, action_install_titledb_draw_top);
} }

View File

@ -4,20 +4,10 @@
#include <3ds.h> #include <3ds.h>
#include "../action/action.h" #include "action.h"
#include "../resources.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../info.h"
#include "../../prompt.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/error.h"
#include "../../../core/fs.h"
#include "../../../core/http.h"
#include "../../../core/screen.h"
#include "../../../core/stringutil.h"
#include "../../../core/data/cia.h"
#include "../../../core/data/ticket.h"
typedef enum content_type_e { typedef enum content_type_e {
CONTENT_CIA, CONTENT_CIA,

View File

@ -1,14 +1,9 @@
#include <3ds.h> #include <3ds.h>
#include "action.h" #include "action.h"
#include "../resources.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../info.h"
#include "../../list.h"
#include "../../prompt.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/screen.h"
static void action_launch_title_update(ui_view* view, void* data, float* progress, char* text) { static void action_launch_title_update(ui_view* view, void* data, float* progress, char* text) {
title_info* info = (title_info*) data; title_info* info = (title_info*) data;
@ -26,16 +21,16 @@ static void action_launch_title_update(ui_view* view, void* data, float* progres
ui_pop(); ui_pop();
info_destroy(view); info_destroy(view);
error_display_res(info, ui_draw_title_info, res, "Failed to launch title."); error_display_res(info, task_draw_title_info, res, "Failed to launch title.");
} }
} }
static void action_launch_title_onresponse(ui_view* view, void* data, u32 response) { static void action_launch_title_onresponse(ui_view* view, void* data, u32 response) {
if(response == PROMPT_YES) { if(response == PROMPT_YES) {
info_display("Launching Title", "", false, data, action_launch_title_update, ui_draw_title_info); info_display("Launching Title", "", false, data, action_launch_title_update, task_draw_title_info);
} }
} }
void action_launch_title(linked_list* items, list_item* selected) { void action_launch_title(linked_list* items, list_item* selected) {
prompt_display_yes_no("Confirmation", "Launch the selected title?", COLOR_TEXT, selected->data, ui_draw_title_info, action_launch_title_onresponse); prompt_display_yes_no("Confirmation", "Launch the selected title?", COLOR_TEXT, selected->data, task_draw_title_info, action_launch_title_onresponse);
} }

View File

@ -4,19 +4,9 @@
#include <3ds.h> #include <3ds.h>
#include "action.h" #include "action.h"
#include "../resources.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../info.h"
#include "../../kbd.h"
#include "../../list.h"
#include "../../prompt.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/error.h"
#include "../../../core/fs.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
#include "../../../core/stringutil.h"
typedef struct { typedef struct {
linked_list* items; linked_list* items;

View File

@ -5,19 +5,9 @@
#include <3ds.h> #include <3ds.h>
#include "action.h" #include "action.h"
#include "../resources.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../info.h"
#include "../../list.h"
#include "../../prompt.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/error.h"
#include "../../../core/fs.h"
#include "../../../core/clipboard.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
#include "../../../core/stringutil.h"
typedef struct { typedef struct {
linked_list* items; linked_list* items;
@ -35,9 +25,9 @@ static void action_paste_contents_draw_top(ui_view* view, void* data, float x1,
u32 curr = pasteData->pasteInfo.processed; u32 curr = pasteData->pasteInfo.processed;
if(curr < pasteData->pasteInfo.total) { if(curr < pasteData->pasteInfo.total) {
ui_draw_file_info(view, ((list_item*) linked_list_get(&pasteData->contents, curr))->data, x1, y1, x2, y2); task_draw_file_info(view, ((list_item*) linked_list_get(&pasteData->contents, curr))->data, x1, y1, x2, y2);
} else { } else {
ui_draw_file_info(view, pasteData->target, x1, y1, x2, y2); task_draw_file_info(view, pasteData->target, x1, y1, x2, y2);
} }
} }

View File

@ -5,19 +5,9 @@
#include <3ds.h> #include <3ds.h>
#include "action.h" #include "action.h"
#include "../resources.h"
#include "../task/uitask.h" #include "../task/uitask.h"
#include "../../error.h" #include "../../core/core.h"
#include "../../info.h"
#include "../../kbd.h"
#include "../../list.h"
#include "../../prompt.h"
#include "../../resources.h"
#include "../../ui.h"
#include "../../../core/error.h"
#include "../../../core/fs.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
#include "../../../core/stringutil.h"
typedef struct { typedef struct {
linked_list* items; linked_list* items;

View File

@ -5,16 +5,10 @@
#include <3ds.h> #include <3ds.h>
#include "resources.h"
#include "section.h" #include "section.h"
#include "task/uitask.h" #include "task/uitask.h"
#include "../error.h" #include "../core/core.h"
#include "../info.h"
#include "../prompt.h"
#include "../resources.h"
#include "../ui.h"
#include "../../core/error.h"
#include "../../core/fs.h"
#include "../../core/screen.h"
static Result dumpnand_is_src_directory(void* data, u32 index, bool* isDirectory) { static Result dumpnand_is_src_directory(void* data, u32 index, bool* isDirectory) {
*isDirectory = false; *isDirectory = false;

View File

@ -4,16 +4,11 @@
#include <3ds.h> #include <3ds.h>
#include "resources.h"
#include "section.h" #include "section.h"
#include "action/action.h" #include "action/action.h"
#include "task/uitask.h" #include "task/uitask.h"
#include "../error.h" #include "../core/core.h"
#include "../list.h"
#include "../resources.h"
#include "../ui.h"
#include "../../core/linkedlist.h"
#include "../../core/screen.h"
#include "../../core/stringutil.h"
static list_item browse_user_save_data = {"Browse User Save Data", COLOR_TEXT, action_browse_user_ext_save_data}; static list_item browse_user_save_data = {"Browse User Save Data", COLOR_TEXT, action_browse_user_ext_save_data};
static list_item browse_spotpass_save_data = {"Browse SpotPass Save Data", COLOR_TEXT, action_browse_boss_ext_save_data}; static list_item browse_spotpass_save_data = {"Browse SpotPass Save Data", COLOR_TEXT, action_browse_boss_ext_save_data};
@ -36,7 +31,7 @@ typedef struct {
} extsavedata_action_data; } extsavedata_action_data;
static void extsavedata_action_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { static void extsavedata_action_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) {
ui_draw_ext_save_data_info(view, ((extsavedata_action_data*) data)->selected->data, x1, y1, x2, y2); task_draw_ext_save_data_info(view, ((extsavedata_action_data*) data)->selected->data, x1, y1, x2, y2);
} }
static void extsavedata_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { static void extsavedata_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
@ -153,7 +148,7 @@ static void extsavedata_options_open(extsavedata_data* data) {
static void extsavedata_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { static void extsavedata_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) {
if(selected != NULL && selected->data != NULL) { if(selected != NULL && selected->data != NULL) {
ui_draw_ext_save_data_info(view, selected->data, x1, y1, x2, y2); task_draw_ext_save_data_info(view, selected->data, x1, y1, x2, y2);
} }
} }

View File

@ -4,19 +4,11 @@
#include <3ds.h> #include <3ds.h>
#include "resources.h"
#include "section.h" #include "section.h"
#include "action/action.h" #include "action/action.h"
#include "task/uitask.h" #include "task/uitask.h"
#include "../error.h" #include "../core/core.h"
#include "../list.h"
#include "../prompt.h"
#include "../resources.h"
#include "../ui.h"
#include "../../core/clipboard.h"
#include "../../core/fs.h"
#include "../../core/linkedlist.h"
#include "../../core/screen.h"
#include "../../core/stringutil.h"
static list_item rename_opt = {"Rename", COLOR_TEXT, action_rename}; static list_item rename_opt = {"Rename", COLOR_TEXT, action_rename};
static list_item copy = {"Copy", COLOR_TEXT, NULL}; static list_item copy = {"Copy", COLOR_TEXT, NULL};
@ -71,7 +63,7 @@ typedef struct {
} files_action_data; } 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) { 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)->selected->data, x1, y1, x2, y2); task_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) { static void files_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
@ -97,9 +89,9 @@ static void files_action_update(ui_view* view, void* data, linked_list* items, l
Result res = 0; Result res = 0;
if(R_SUCCEEDED(res = clipboard_set_contents(actionData->parent->archive, info->path, selected == &copy_all_contents))) { if(R_SUCCEEDED(res = clipboard_set_contents(actionData->parent->archive, info->path, selected == &copy_all_contents))) {
prompt_display_notify("Success", selected == &copy_all_contents ? "Current directory contents copied to clipboard." : (info->attributes & FS_ATTRIBUTE_DIRECTORY) ? "Current directory copied to clipboard." : "File copied to clipboard.", COLOR_TEXT, info, ui_draw_file_info, NULL); prompt_display_notify("Success", selected == &copy_all_contents ? "Current directory contents copied to clipboard." : (info->attributes & FS_ATTRIBUTE_DIRECTORY) ? "Current directory copied to clipboard." : "File copied to clipboard.", COLOR_TEXT, info, task_draw_file_info, NULL);
} else { } else {
error_display_res(info, ui_draw_file_info, res, "Failed to copy to clipboard."); error_display_res(info, task_draw_file_info, res, "Failed to copy to clipboard.");
} }
} else { } else {
action(actionData->items, actionData->selected); action(actionData->items, actionData->selected);
@ -236,7 +228,7 @@ static void files_options_open(files_data* data) {
static void files_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { static void files_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) {
if(selected != NULL && selected->data != NULL) { if(selected != NULL && selected->data != NULL) {
ui_draw_file_info(view, selected->data, x1, y1, x2, y2); task_draw_file_info(view, selected->data, x1, y1, x2, y2);
} }
} }

View File

@ -1,191 +1,191 @@
#include <sys/iosupport.h> #include <sys/iosupport.h>
#include <malloc.h> #include <malloc.h>
#include <3ds.h> #include <3ds.h>
#include <curl/curl.h> #include <curl/curl.h>
#include "core/clipboard.h" #include "../core/clipboard.h"
#include "core/error.h" #include "../core/error.h"
#include "core/fs.h" #include "../core/fs.h"
#include "core/screen.h" #include "../core/screen.h"
#include "core/task/task.h" #include "../core/task/task.h"
#include "ui/mainmenu.h" #include "../core/ui/ui.h"
#include "ui/ui.h" #include "section.h"
#define CURRENT_KPROCESS (*(void**) 0xFFFF9004) #define CURRENT_KPROCESS (*(void**) 0xFFFF9004)
#define KPROCESS_PID_OFFSET_OLD (0xB4) #define KPROCESS_PID_OFFSET_OLD (0xB4)
#define KPROCESS_PID_OFFSET_NEW (0xBC) #define KPROCESS_PID_OFFSET_NEW (0xBC)
static bool backdoor_ran = false; static bool backdoor_ran = false;
static bool n3ds = false; static bool n3ds = false;
static u32 old_pid = 0; static u32 old_pid = 0;
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wreturn-type" #pragma GCC diagnostic ignored "-Wreturn-type"
static __attribute__((naked)) Result svcGlobalBackdoor(s32 (*callback)()) { static __attribute__((naked)) Result svcGlobalBackdoor(s32 (*callback)()) {
asm volatile( asm volatile(
"svc 0x30\n" "svc 0x30\n"
"bx lr" "bx lr"
); );
} }
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
static s32 patch_pid_kernel() { static s32 patch_pid_kernel() {
u32 *pidPtr = (u32*) (CURRENT_KPROCESS + (n3ds ? KPROCESS_PID_OFFSET_NEW : KPROCESS_PID_OFFSET_OLD)); u32 *pidPtr = (u32*) (CURRENT_KPROCESS + (n3ds ? KPROCESS_PID_OFFSET_NEW : KPROCESS_PID_OFFSET_OLD));
old_pid = *pidPtr; old_pid = *pidPtr;
*pidPtr = 0; *pidPtr = 0;
backdoor_ran = true; backdoor_ran = true;
return 0; return 0;
} }
static s32 restore_pid_kernel() { static s32 restore_pid_kernel() {
u32 *pidPtr = (u32*) (CURRENT_KPROCESS + (n3ds ? KPROCESS_PID_OFFSET_NEW : KPROCESS_PID_OFFSET_OLD)); u32 *pidPtr = (u32*) (CURRENT_KPROCESS + (n3ds ? KPROCESS_PID_OFFSET_NEW : KPROCESS_PID_OFFSET_OLD));
*pidPtr = old_pid; *pidPtr = old_pid;
backdoor_ran = true; backdoor_ran = true;
return 0; return 0;
} }
static bool attempt_patch_pid() { static bool attempt_patch_pid() {
backdoor_ran = false; backdoor_ran = false;
APT_CheckNew3DS(&n3ds); APT_CheckNew3DS(&n3ds);
svcGlobalBackdoor(patch_pid_kernel); svcGlobalBackdoor(patch_pid_kernel);
srvExit(); srvExit();
srvInit(); srvInit();
svcGlobalBackdoor(restore_pid_kernel); svcGlobalBackdoor(restore_pid_kernel);
return backdoor_ran; return backdoor_ran;
} }
static void (*exit_funcs[16])()= {NULL}; static void (*exit_funcs[16])()= {NULL};
static u32 exit_func_count = 0; static u32 exit_func_count = 0;
static void* soc_buffer = NULL; static void* soc_buffer = NULL;
void cleanup_services() { void cleanup_services() {
for(u32 i = 0; i < exit_func_count; i++) { for(u32 i = 0; i < exit_func_count; i++) {
if(exit_funcs[i] != NULL) { if(exit_funcs[i] != NULL) {
exit_funcs[i](); exit_funcs[i]();
exit_funcs[i] = NULL; exit_funcs[i] = NULL;
} }
} }
exit_func_count = 0; exit_func_count = 0;
if(soc_buffer != NULL) { if(soc_buffer != NULL) {
free(soc_buffer); free(soc_buffer);
soc_buffer = NULL; soc_buffer = NULL;
} }
} }
#define INIT_SERVICE(initStatement, exitFunc) (R_SUCCEEDED(res = (initStatement)) && (exit_funcs[exit_func_count++] = (exitFunc))) #define INIT_SERVICE(initStatement, exitFunc) (R_SUCCEEDED(res = (initStatement)) && (exit_funcs[exit_func_count++] = (exitFunc)))
Result init_services() { Result init_services() {
Result res = 0; Result res = 0;
soc_buffer = memalign(0x1000, 0x100000); soc_buffer = memalign(0x1000, 0x100000);
if(soc_buffer != NULL) { if(soc_buffer != NULL) {
Handle tempAM = 0; Handle tempAM = 0;
if(R_SUCCEEDED(res = srvGetServiceHandle(&tempAM, "am:net"))) { if(R_SUCCEEDED(res = srvGetServiceHandle(&tempAM, "am:net"))) {
svcCloseHandle(tempAM); svcCloseHandle(tempAM);
if(INIT_SERVICE(amInit(), amExit) if(INIT_SERVICE(amInit(), amExit)
&& INIT_SERVICE(cfguInit(), cfguExit) && INIT_SERVICE(cfguInit(), cfguExit)
&& INIT_SERVICE(acInit(), acExit) && INIT_SERVICE(acInit(), acExit)
&& INIT_SERVICE(ptmuInit(), ptmuExit) && INIT_SERVICE(ptmuInit(), ptmuExit)
&& INIT_SERVICE(pxiDevInit(), pxiDevExit) && INIT_SERVICE(pxiDevInit(), pxiDevExit)
&& INIT_SERVICE(httpcInit(0), httpcExit) && INIT_SERVICE(httpcInit(0), httpcExit)
&& INIT_SERVICE(socInit(soc_buffer, 0x100000), (void (*)()) socExit)); && INIT_SERVICE(socInit(soc_buffer, 0x100000), (void (*)()) socExit));
} }
} else { } else {
res = R_APP_OUT_OF_MEMORY; res = R_APP_OUT_OF_MEMORY;
} }
if(R_FAILED(res)) { if(R_FAILED(res)) {
cleanup_services(); cleanup_services();
} }
return res; return res;
} }
static u32 old_time_limit = UINT32_MAX; static u32 old_time_limit = UINT32_MAX;
void init() { void init() {
gfxInitDefault(); gfxInitDefault();
Result romfsRes = romfsInit(); Result romfsRes = romfsInit();
if(R_FAILED(romfsRes)) { if(R_FAILED(romfsRes)) {
error_panic("Failed to mount RomFS: %08lX", romfsRes); error_panic("Failed to mount RomFS: %08lX", romfsRes);
return; return;
} }
if(R_FAILED(init_services())) { if(R_FAILED(init_services())) {
if(!attempt_patch_pid()) { if(!attempt_patch_pid()) {
error_panic("Kernel backdoor not installed.\nPlease run a kernel exploit and try again."); error_panic("Kernel backdoor not installed.\nPlease run a kernel exploit and try again.");
return; return;
} }
Result initRes = init_services(); Result initRes = init_services();
if(R_FAILED(initRes)) { if(R_FAILED(initRes)) {
error_panic("Failed to initialize services: %08lX", initRes); error_panic("Failed to initialize services: %08lX", initRes);
return; return;
} }
} }
osSetSpeedupEnable(true); osSetSpeedupEnable(true);
APT_GetAppCpuTimeLimit(&old_time_limit); APT_GetAppCpuTimeLimit(&old_time_limit);
Result cpuRes = APT_SetAppCpuTimeLimit(30); Result cpuRes = APT_SetAppCpuTimeLimit(30);
if(R_FAILED(cpuRes)) { if(R_FAILED(cpuRes)) {
error_panic("Failed to set syscore CPU time limit: %08lX", cpuRes); error_panic("Failed to set syscore CPU time limit: %08lX", cpuRes);
return; return;
} }
AM_InitializeExternalTitleDatabase(false); AM_InitializeExternalTitleDatabase(false);
curl_global_init(CURL_GLOBAL_ALL); curl_global_init(CURL_GLOBAL_ALL);
screen_init(); screen_init();
ui_init(); ui_init();
task_init(); task_init();
} }
void cleanup() { void cleanup() {
clipboard_clear(); clipboard_clear();
task_exit(); task_exit();
ui_exit(); ui_exit();
screen_exit(); screen_exit();
if(old_time_limit != UINT32_MAX) { if(old_time_limit != UINT32_MAX) {
APT_SetAppCpuTimeLimit(old_time_limit); APT_SetAppCpuTimeLimit(old_time_limit);
} }
osSetSpeedupEnable(false); osSetSpeedupEnable(false);
cleanup_services(); cleanup_services();
romfsExit(); romfsExit();
gfxExit(); gfxExit();
} }
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
if(argc > 0 && envIsHomebrew()) { if(argc > 0 && envIsHomebrew()) {
fs_set_3dsx_path(argv[0]); fs_set_3dsx_path(argv[0]);
} }
init(); init();
mainmenu_open(); mainmenu_open();
while(aptMainLoop() && ui_update()); while(aptMainLoop() && ui_update());
cleanup(); cleanup();
return 0; return 0;
} }

View File

@ -3,13 +3,9 @@
#include <3ds.h> #include <3ds.h>
#include "list.h"
#include "mainmenu.h"
#include "resources.h" #include "resources.h"
#include "ui.h" #include "section.h"
#include "section/section.h" #include "../core/core.h"
#include "../core/linkedlist.h"
#include "../core/screen.h"
static list_item sd = {"SD", COLOR_TEXT, files_open_sd}; static list_item sd = {"SD", COLOR_TEXT, files_open_sd};
static list_item ctr_nand = {"CTR NAND", COLOR_TEXT, files_open_ctr_nand}; static list_item ctr_nand = {"CTR NAND", COLOR_TEXT, files_open_ctr_nand};
@ -68,5 +64,7 @@ static void mainmenu_update(ui_view* view, void* data, linked_list* items, list_
} }
void mainmenu_open() { void mainmenu_open() {
resources_load();
list_display("Main Menu", "A: Select, START: Exit", NULL, mainmenu_update, mainmenu_draw_top); list_display("Main Menu", "A: Select, START: Exit", NULL, mainmenu_update, mainmenu_draw_top);
} }

View File

@ -3,15 +3,11 @@
#include <3ds.h> #include <3ds.h>
#include "resources.h"
#include "section.h" #include "section.h"
#include "action/action.h" #include "action/action.h"
#include "task/uitask.h" #include "task/uitask.h"
#include "../error.h" #include "../core/core.h"
#include "../list.h"
#include "../resources.h"
#include "../ui.h"
#include "../../core/linkedlist.h"
#include "../../core/screen.h"
static list_item delete_pending_title = {"Delete Pending Title", COLOR_TEXT, action_delete_pending_title}; static list_item delete_pending_title = {"Delete Pending Title", COLOR_TEXT, action_delete_pending_title};
static list_item delete_all_pending_titles = {"Delete All Pending Titles", COLOR_TEXT, action_delete_all_pending_titles}; static list_item delete_all_pending_titles = {"Delete All Pending Titles", COLOR_TEXT, action_delete_all_pending_titles};
@ -28,7 +24,7 @@ typedef struct {
} pendingtitles_action_data; } pendingtitles_action_data;
static void pendingtitles_action_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { static void pendingtitles_action_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) {
ui_draw_pending_title_info(view, ((pendingtitles_action_data*) data)->selected->data, x1, y1, x2, y2); task_draw_pending_title_info(view, ((pendingtitles_action_data*) data)->selected->data, x1, y1, x2, y2);
} }
static void pendingtitles_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { static void pendingtitles_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
@ -78,7 +74,7 @@ static void pendingtitles_action_open(linked_list* items, list_item* selected) {
static void pendingtitles_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { static void pendingtitles_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) {
if(selected != NULL && selected->data != NULL) { if(selected != NULL && selected->data != NULL) {
ui_draw_pending_title_info(view, selected->data, x1, y1, x2, y2); task_draw_pending_title_info(view, selected->data, x1, y1, x2, y2);
} }
} }

View File

@ -8,22 +8,12 @@
#include <3ds.h> #include <3ds.h>
#include "resources.h"
#include "section.h" #include "section.h"
#include "action/action.h" #include "action/action.h"
#include "task/uitask.h" #include "task/uitask.h"
#include "../error.h" #include "../core/core.h"
#include "../info.h" #include "../libs/quirc/quirc_internal.h"
#include "../kbd.h"
#include "../list.h"
#include "../prompt.h"
#include "../resources.h"
#include "../ui.h"
#include "../../core/error.h"
#include "../../core/fs.h"
#include "../../core/linkedlist.h"
#include "../../core/screen.h"
#include "../../core/task/capturecam.h"
#include "../../libs/quirc/quirc_internal.h"
static bool remoteinstall_get_last_urls(char* out, size_t size) { static bool remoteinstall_get_last_urls(char* out, size_t size) {
if(out == NULL || size == 0) { if(out == NULL || size == 0) {

View File

@ -5,10 +5,7 @@
#include <3ds.h> #include <3ds.h>
#include "resources.h" #include "resources.h"
#include "../core/error.h" #include "../core/core.h"
#include "../core/fs.h"
#include "../core/screen.h"
#include "../core/task/task.h"
static FILE* resources_open_file(const char* path) { static FILE* resources_open_file(const char* path) {
char realPath[FILE_PATH_MAX]; char realPath[FILE_PATH_MAX];

View File

@ -31,7 +31,6 @@
#define TEXTURE_WIFI_2 29 #define TEXTURE_WIFI_2 29
#define TEXTURE_WIFI_3 30 #define TEXTURE_WIFI_3 30
#define COLOR_TEXT 0
#define COLOR_NAND 1 #define COLOR_NAND 1
#define COLOR_SD 2 #define COLOR_SD 2
#define COLOR_GAME_CARD 3 #define COLOR_GAME_CARD 3

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
void mainmenu_open();
void dumpnand_open(); void dumpnand_open();
void extsavedata_open(); void extsavedata_open();
void files_open(FS_ArchiveID archiveId, FS_Path archivePath); void files_open(FS_ArchiveID archiveId, FS_Path archivePath);

View File

@ -3,15 +3,11 @@
#include <3ds.h> #include <3ds.h>
#include "resources.h"
#include "section.h" #include "section.h"
#include "action/action.h" #include "action/action.h"
#include "task/uitask.h" #include "task/uitask.h"
#include "../error.h" #include "../core/core.h"
#include "../list.h"
#include "../resources.h"
#include "../ui.h"
#include "../../core/linkedlist.h"
#include "../../core/screen.h"
static list_item browse_save_data = {"Browse Save Data", COLOR_TEXT, action_browse_system_save_data}; static list_item browse_save_data = {"Browse Save Data", COLOR_TEXT, action_browse_system_save_data};
static list_item delete_save_data = {"Delete Save Data", COLOR_TEXT, action_delete_system_save_data}; static list_item delete_save_data = {"Delete Save Data", COLOR_TEXT, action_delete_system_save_data};
@ -28,7 +24,7 @@ typedef struct {
} systemsavedata_action_data; } systemsavedata_action_data;
static void systemsavedata_action_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { static void systemsavedata_action_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) {
ui_draw_system_save_data_info(view, ((systemsavedata_action_data*) data)->selected->data, x1, y1, x2, y2); task_draw_system_save_data_info(view, ((systemsavedata_action_data*) data)->selected->data, x1, y1, x2, y2);
} }
static void systemsavedata_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { static void systemsavedata_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
@ -78,7 +74,7 @@ static void systemsavedata_action_open(linked_list* items, list_item* selected)
static void systemsavedata_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { static void systemsavedata_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) {
if(selected != NULL && selected->data != NULL) { if(selected != NULL && selected->data != NULL) {
ui_draw_system_save_data_info(view, selected->data, x1, y1, x2, y2); task_draw_system_save_data_info(view, selected->data, x1, y1, x2, y2);
} }
} }

View File

@ -6,14 +6,9 @@
#include <3ds.h> #include <3ds.h>
#include "uitask.h" #include "uitask.h"
#include "../../list.h" #include "listextsavedata.h"
#include "../../resources.h" #include "../resources.h"
#include "../../../core/error.h" #include "../../core/core.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
#include "../../../core/stringutil.h"
#include "../../../core/data/smdh.h"
#include "../../../core/task/task.h"
#define MAX_EXT_SAVE_DATA 512 #define MAX_EXT_SAVE_DATA 512

View File

@ -0,0 +1,28 @@
#pragma once
typedef struct linked_list_s linked_list;
typedef struct list_item_s list_item;
typedef struct ext_save_data_info_s {
FS_MediaType mediaType;
u64 extSaveDataId;
bool shared;
bool hasMeta;
meta_info meta;
} ext_save_data_info;
typedef struct populate_ext_save_data_data_s {
linked_list* items;
void* userData;
bool (*filter)(void* data, u64 extSaveDataId, FS_MediaType mediaType);
int (*compare)(void* data, const void* p1, const void* p2);
volatile bool finished;
Result result;
Handle cancelEvent;
} populate_ext_save_data_data;
void task_free_ext_save_data(list_item* item);
void task_clear_ext_save_data(linked_list* items);
Result task_populate_ext_save_data(populate_ext_save_data_data* data);

View File

@ -6,16 +6,9 @@
#include <3ds.h> #include <3ds.h>
#include "uitask.h" #include "uitask.h"
#include "../../list.h" #include "listfiles.h"
#include "../../resources.h" #include "../resources.h"
#include "../../../core/error.h" #include "../../core/core.h"
#include "../../../core/fs.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
#include "../../../core/stringutil.h"
#include "../../../core/data/cia.h"
#include "../../../core/data/smdh.h"
#include "../../../core/task/task.h"
#define MAX_FILES 1024 #define MAX_FILES 1024

View File

@ -0,0 +1,54 @@
#pragma once
#ifndef FILE_NAME_MAX
#define FILE_NAME_MAX 512
#define FILE_PATH_MAX 512
#endif
typedef struct linked_list_s linked_list;
typedef struct list_item_s list_item;
typedef struct cia_info_s {
u64 titleId;
u16 version;
u64 installedSize;
bool hasMeta;
meta_info meta;
} cia_info;
typedef struct file_info_s {
FS_Archive archive;
char name[FILE_NAME_MAX];
char path[FILE_PATH_MAX];
u32 attributes;
// Files only
u64 size;
bool isCia;
cia_info ciaInfo;
bool isTicket;
ticket_info ticketInfo;
} file_info;
typedef struct populate_files_data_s {
linked_list* items;
FS_Archive archive;
char path[FILE_PATH_MAX];
bool recursive;
bool includeBase;
bool (*filter)(void* data, const char* name, u32 attributes);
void* filterData;
volatile bool finished;
Result result;
Handle cancelEvent;
} populate_files_data;
int task_compare_files(void* userData, const void* p1, const void* p2);
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, u32 attributes);
Result task_populate_files(populate_files_data* data);

View File

@ -4,13 +4,9 @@
#include <3ds.h> #include <3ds.h>
#include "uitask.h" #include "listpendingtitles.h"
#include "../../list.h" #include "../resources.h"
#include "../../resources.h" #include "../../core/core.h"
#include "../../../core/error.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
#include "../../../core/task/task.h"
static int task_populate_pending_titles_compare_ids(const void* e1, const void* e2) { static int task_populate_pending_titles_compare_ids(const void* e1, const void* e2) {
u64 id1 = *(u64*) e1; u64 id1 = *(u64*) e1;

View File

@ -0,0 +1,22 @@
#pragma once
typedef struct linked_list_s linked_list;
typedef struct list_item_s list_item;
typedef struct pending_title_info_s {
FS_MediaType mediaType;
u64 titleId;
u16 version;
} pending_title_info;
typedef struct populate_pending_titles_data_s {
linked_list* items;
volatile bool finished;
Result result;
Handle cancelEvent;
} populate_pending_titles_data;
void task_free_pending_title(list_item* item);
void task_clear_pending_titles(linked_list* items);
Result task_populate_pending_titles(populate_pending_titles_data* data);

View File

@ -4,13 +4,9 @@
#include <3ds.h> #include <3ds.h>
#include "uitask.h" #include "listsystemsavedata.h"
#include "../../list.h" #include "../resources.h"
#include "../../resources.h" #include "../../core/core.h"
#include "../../../core/error.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
#include "../../../core/task/task.h"
#define MAX_SYSTEM_SAVE_DATA 512 #define MAX_SYSTEM_SAVE_DATA 512

View File

@ -0,0 +1,20 @@
#pragma once
typedef struct linked_list_s linked_list;
typedef struct list_item_s list_item;
typedef struct system_save_data_info_s {
u32 systemSaveDataId;
} system_save_data_info;
typedef struct populate_system_save_data_data_s {
linked_list* items;
volatile bool finished;
Result result;
Handle cancelEvent;
} populate_system_save_data_data;
void task_free_system_save_data(list_item* item);
void task_clear_system_save_data(linked_list* items);
Result task_populate_system_save_data(populate_system_save_data_data* data);

View File

@ -4,13 +4,9 @@
#include <3ds.h> #include <3ds.h>
#include "uitask.h" #include "listtickets.h"
#include "../../list.h" #include "../resources.h"
#include "../../resources.h" #include "../../core/core.h"
#include "../../../core/error.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
#include "../../../core/task/task.h"
static int task_populate_tickets_compare_ids(const void* e1, const void* e2) { static int task_populate_tickets_compare_ids(const void* e1, const void* e2) {
u64 id1 = *(u64*) e1; u64 id1 = *(u64*) e1;

View File

@ -0,0 +1,22 @@
#pragma once
typedef struct linked_list_s linked_list;
typedef struct list_item_s list_item;
typedef struct ticket_info_s {
u64 titleId;
bool inUse;
} ticket_info;
typedef struct populate_tickets_data_s {
linked_list* items;
volatile bool finished;
Result result;
Handle cancelEvent;
} populate_tickets_data;
void task_populate_tickets_update_use(list_item* item);
void task_free_ticket(list_item* item);
void task_clear_tickets(linked_list* items);
Result task_populate_tickets(populate_tickets_data* data);

View File

@ -1,302 +1,297 @@
#include <malloc.h> #include <malloc.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <3ds.h> #include <3ds.h>
#include <jansson.h> #include <jansson.h>
#include "uitask.h" #include "uitask.h"
#include "../../list.h" #include "listtitledb.h"
#include "../../resources.h" #include "../resources.h"
#include "../../../core/error.h" #include "../../core/core.h"
#include "../../../core/fs.h" #include "../../core/task/dataop.h"
#include "../../../core/linkedlist.h" #include "../../libs/stb_image/stb_image.h"
#include "../../../core/screen.h"
#include "../../../core/stringutil.h" #define json_object_get_string(obj, name, def) (json_is_string(json_object_get(obj, name)) ? json_string_value(json_object_get(obj, name)) : def)
#include "../../../core/task/task.h" #define json_object_get_integer(obj, name, def) (json_is_integer(json_object_get(obj, name)) ? json_integer_value(json_object_get(obj, name)) : def)
#include "../../../libs/stb_image/stb_image.h"
void task_populate_titledb_update_status(list_item* item) {
#define json_object_get_string(obj, name, def) (json_is_string(json_object_get(obj, name)) ? json_string_value(json_object_get(obj, name)) : def) titledb_info* info = (titledb_info*) item->data;
#define json_object_get_integer(obj, name, def) (json_is_integer(json_object_get(obj, name)) ? json_integer_value(json_object_get(obj, name)) : def)
if(info->cia.exists) {
void task_populate_titledb_update_status(list_item* item) { AM_TitleEntry entry;
titledb_info* info = (titledb_info*) item->data; info->cia.installed = R_SUCCEEDED(AM_GetTitleInfo(fs_get_title_destination(info->cia.titleId), 1, &info->cia.titleId, &entry));
info->cia.installedVersion = info->cia.installed ? entry.version : (u16) 0;
if(info->cia.exists) { }
AM_TitleEntry entry;
info->cia.installed = R_SUCCEEDED(AM_GetTitleInfo(fs_get_title_destination(info->cia.titleId), 1, &info->cia.titleId, &entry)); if(info->tdsx.exists) {
info->cia.installedVersion = info->cia.installed ? entry.version : (u16) 0; info->tdsx.installed = false;
}
char name[FILE_NAME_MAX];
if(info->tdsx.exists) { string_escape_file_name(name, info->meta.shortDescription, sizeof(name));
info->tdsx.installed = false;
char path3dsx[FILE_PATH_MAX];
char name[FILE_NAME_MAX]; snprintf(path3dsx, sizeof(path3dsx), "/3ds/%s/%s.3dsx", name, name);
string_escape_file_name(name, info->meta.shortDescription, sizeof(name));
FS_Path* fsPath = fs_make_path_utf8(path3dsx);
char path3dsx[FILE_PATH_MAX]; if(fsPath != NULL) {
snprintf(path3dsx, sizeof(path3dsx), "/3ds/%s/%s.3dsx", name, name); Handle handle = 0;
if(R_SUCCEEDED(FSUSER_OpenFileDirectly(&handle, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""), *fsPath, FS_OPEN_READ, 0))) {
FS_Path* fsPath = fs_make_path_utf8(path3dsx); FSFILE_Close(handle);
if(fsPath != NULL) {
Handle handle = 0; info->tdsx.installed = true;
if(R_SUCCEEDED(FSUSER_OpenFileDirectly(&handle, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""), *fsPath, FS_OPEN_READ, 0))) { }
FSFILE_Close(handle);
fs_free_path_utf8(fsPath);
info->tdsx.installed = true; }
} }
fs_free_path_utf8(fsPath); if((info->cia.exists && info->cia.installed) || (info->tdsx.exists && info->tdsx.installed)) {
} item->color = COLOR_TITLEDB_INSTALLED;
} } else {
item->color = COLOR_TITLEDB_NOT_INSTALLED;
// TODO: Outdated color(?) }
if((info->cia.exists && info->cia.installed) || (info->tdsx.exists && info->tdsx.installed)) { }
item->color = COLOR_TITLEDB_INSTALLED;
} else { static int task_populate_titledb_compare(void* userData, const void* p1, const void* p2) {
item->color = COLOR_TITLEDB_NOT_INSTALLED; list_item* info1 = (list_item*) p1;
} list_item* info2 = (list_item*) p2;
}
return strncasecmp(info1->name, info2->name, LIST_ITEM_NAME_MAX);
static int task_populate_titledb_compare(void* userData, const void* p1, const void* p2) { }
list_item* info1 = (list_item*) p1;
list_item* info2 = (list_item*) p2; static void task_populate_titledb_thread(void* arg) {
populate_titledb_data* data = (populate_titledb_data*) arg;
return strncasecmp(info1->name, info2->name, LIST_ITEM_NAME_MAX);
} Result res = 0;
static void task_populate_titledb_thread(void* arg) { json_t* root = NULL;
populate_titledb_data* data = (populate_titledb_data*) arg; if(R_SUCCEEDED(res = task_download_json_sync("https://api.titledb.com/v1/entry?nested=true"
"&only=id&only=name&only=author&only=headline&only=category"
Result res = 0; "&only=cia.id&only=cia.updated_at&only=cia.version&only=cia.size&only=cia.titleid"
"&only=tdsx.id&only=tdsx.updated_at&only=tdsx.version&only=tdsx.size&only=tdsx.smdh.id",
json_t* root = NULL; &root, 1024 * 1024))) {
if(R_SUCCEEDED(res = task_download_json_sync("https://api.titledb.com/v1/entry?nested=true" if(json_is_array(root)) {
"&only=id&only=name&only=author&only=headline&only=category" linked_list titles;
"&only=cia.id&only=cia.updated_at&only=cia.version&only=cia.size&only=cia.titleid" linked_list_init(&titles);
"&only=tdsx.id&only=tdsx.updated_at&only=tdsx.version&only=tdsx.size&only=tdsx.smdh.id",
&root, 1024 * 1024))) { for(u32 i = 0; i < json_array_size(root) && R_SUCCEEDED(res); i++) {
if(json_is_array(root)) { svcWaitSynchronization(task_get_pause_event(), U64_MAX);
linked_list titles; if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) {
linked_list_init(&titles); break;
}
for(u32 i = 0; i < json_array_size(root) && R_SUCCEEDED(res); i++) {
svcWaitSynchronization(task_get_pause_event(), U64_MAX); json_t* entry = json_array_get(root, i);
if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) { if(json_is_object(entry)) {
break; list_item* item = (list_item*) calloc(1, sizeof(list_item));
} if(item != NULL) {
titledb_info* titledbInfo = (titledb_info*) calloc(1, sizeof(titledb_info));
json_t* entry = json_array_get(root, i); if(titledbInfo != NULL) {
if(json_is_object(entry)) { titledbInfo->id = (u32) json_object_get_integer(entry, "id", 0);
list_item* item = (list_item*) calloc(1, sizeof(list_item)); strncpy(titledbInfo->category, json_object_get_string(entry, "category", "Unknown"), sizeof(titledbInfo->category));
if(item != NULL) { strncpy(titledbInfo->headline, json_object_get_string(entry, "headline", ""), sizeof(titledbInfo->headline));
titledb_info* titledbInfo = (titledb_info*) calloc(1, sizeof(titledb_info)); strncpy(titledbInfo->meta.shortDescription, json_object_get_string(entry, "name", ""), sizeof(titledbInfo->meta.shortDescription));
if(titledbInfo != NULL) { strncpy(titledbInfo->meta.publisher, json_object_get_string(entry, "author", ""), sizeof(titledbInfo->meta.publisher));
titledbInfo->id = (u32) json_object_get_integer(entry, "id", 0);
strncpy(titledbInfo->category, json_object_get_string(entry, "category", "Unknown"), sizeof(titledbInfo->category)); json_t* cias = json_object_get(entry, "cia");
strncpy(titledbInfo->headline, json_object_get_string(entry, "headline", ""), sizeof(titledbInfo->headline)); if(json_is_array(cias)) {
strncpy(titledbInfo->meta.shortDescription, json_object_get_string(entry, "name", ""), sizeof(titledbInfo->meta.shortDescription)); for(u32 j = 0; j < json_array_size(cias); j++) {
strncpy(titledbInfo->meta.publisher, json_object_get_string(entry, "author", ""), sizeof(titledbInfo->meta.publisher)); json_t* cia = json_array_get(cias, j);
if(json_is_object(cia)) {
json_t* cias = json_object_get(entry, "cia"); const char* updatedAt = json_object_get_string(cia, "updated_at", "");
if(json_is_array(cias)) { if(!titledbInfo->cia.exists || strncmp(updatedAt, titledbInfo->cia.updatedAt, sizeof(titledbInfo->cia.updatedAt)) >= 0) {
for(u32 j = 0; j < json_array_size(cias); j++) { titledbInfo->cia.exists = true;
json_t* cia = json_array_get(cias, j);
if(json_is_object(cia)) { titledbInfo->cia.id = (u32) json_object_get_integer(cia, "id", 0);
const char* updatedAt = json_object_get_string(cia, "updated_at", ""); strncpy(titledbInfo->cia.updatedAt, updatedAt, sizeof(titledbInfo->cia.updatedAt));
if(!titledbInfo->cia.exists || strncmp(updatedAt, titledbInfo->cia.updatedAt, sizeof(titledbInfo->cia.updatedAt)) >= 0) { strncpy(titledbInfo->cia.version, json_object_get_string(cia, "version", "Unknown"), sizeof(titledbInfo->cia.version));
titledbInfo->cia.exists = true; titledbInfo->cia.size = (u32) json_object_get_integer(cia, "size", 0);
titledbInfo->cia.titleId = strtoull(json_object_get_string(cia, "titleid", "0"), NULL, 16);
titledbInfo->cia.id = (u32) json_object_get_integer(cia, "id", 0); }
strncpy(titledbInfo->cia.updatedAt, updatedAt, sizeof(titledbInfo->cia.updatedAt)); }
strncpy(titledbInfo->cia.version, json_object_get_string(cia, "version", "Unknown"), sizeof(titledbInfo->cia.version)); }
titledbInfo->cia.size = (u32) json_object_get_integer(cia, "size", 0); }
titledbInfo->cia.titleId = strtoull(json_object_get_string(cia, "titleid", "0"), NULL, 16);
} json_t* tdsxs = json_object_get(entry, "tdsx");
} if(json_is_array(tdsxs)) {
} for(u32 j = 0; j < json_array_size(tdsxs); j++) {
} json_t* tdsx = json_array_get(tdsxs, j);
if(json_is_object(tdsx)) {
json_t* tdsxs = json_object_get(entry, "tdsx"); const char* updatedAt = json_object_get_string(tdsx, "updated_at", "");
if(json_is_array(tdsxs)) { if(!titledbInfo->tdsx.exists || strncmp(updatedAt, titledbInfo->tdsx.updatedAt, sizeof(titledbInfo->tdsx.updatedAt)) >= 0) {
for(u32 j = 0; j < json_array_size(tdsxs); j++) { titledbInfo->tdsx.exists = true;
json_t* tdsx = json_array_get(tdsxs, j);
if(json_is_object(tdsx)) { titledbInfo->tdsx.id = (u32) json_object_get_integer(tdsx, "id", 0);
const char* updatedAt = json_object_get_string(tdsx, "updated_at", ""); strncpy(titledbInfo->tdsx.updatedAt, updatedAt, sizeof(titledbInfo->tdsx.updatedAt));
if(!titledbInfo->tdsx.exists || strncmp(updatedAt, titledbInfo->tdsx.updatedAt, sizeof(titledbInfo->tdsx.updatedAt)) >= 0) { strncpy(titledbInfo->tdsx.version, json_object_get_string(tdsx, "version", "Unknown"), sizeof(titledbInfo->tdsx.version));
titledbInfo->tdsx.exists = true; titledbInfo->tdsx.size = (u32) json_object_get_integer(tdsx, "size", 0);
titledbInfo->tdsx.id = (u32) json_object_get_integer(tdsx, "id", 0); json_t* smdh = json_object_get(tdsx, "smdh");
strncpy(titledbInfo->tdsx.updatedAt, updatedAt, sizeof(titledbInfo->tdsx.updatedAt)); if(json_is_object(smdh)) {
strncpy(titledbInfo->tdsx.version, json_object_get_string(tdsx, "version", "Unknown"), sizeof(titledbInfo->tdsx.version)); titledbInfo->tdsx.smdh.exists = true;
titledbInfo->tdsx.size = (u32) json_object_get_integer(tdsx, "size", 0);
titledbInfo->tdsx.smdh.id = (u32) json_object_get_integer(smdh, "id", 0);
json_t* smdh = json_object_get(tdsx, "smdh"); }
if(json_is_object(smdh)) { }
titledbInfo->tdsx.smdh.exists = true; }
}
titledbInfo->tdsx.smdh.id = (u32) json_object_get_integer(smdh, "id", 0); }
}
} strncpy(item->name, titledbInfo->meta.shortDescription, LIST_ITEM_NAME_MAX);
} item->data = titledbInfo;
}
} task_populate_titledb_update_status(item);
strncpy(item->name, titledbInfo->meta.shortDescription, LIST_ITEM_NAME_MAX); linked_list_add_sorted(&titles, item, NULL, task_populate_titledb_compare);
item->data = titledbInfo; } else {
free(item);
task_populate_titledb_update_status(item);
res = R_APP_OUT_OF_MEMORY;
linked_list_add_sorted(&titles, item, NULL, task_populate_titledb_compare); }
} else { } else {
free(item); res = R_APP_OUT_OF_MEMORY;
}
res = R_APP_OUT_OF_MEMORY; }
} }
} else {
res = R_APP_OUT_OF_MEMORY; linked_list_iter iter;
} linked_list_iterate(&titles, &iter);
}
} while(linked_list_iter_has_next(&iter)) {
list_item* item = linked_list_iter_next(&iter);
linked_list_iter iter;
linked_list_iterate(&titles, &iter); if(R_SUCCEEDED(res)) {
linked_list_add(data->items, item);
while(linked_list_iter_has_next(&iter)) { } else {
list_item* item = linked_list_iter_next(&iter); task_free_titledb(item);
}
if(R_SUCCEEDED(res)) { }
linked_list_add(data->items, item);
} else { linked_list_destroy(&titles);
task_free_titledb(item); } else {
} res = R_APP_BAD_DATA;
} }
linked_list_destroy(&titles); json_decref(root);
} else { }
res = R_APP_BAD_DATA;
} data->itemsListed = true;
json_decref(root); if(R_SUCCEEDED(res)) {
} linked_list_iter iter;
linked_list_iterate(data->items, &iter);
data->itemsListed = true;
while(linked_list_iter_has_next(&iter)) {
if(R_SUCCEEDED(res)) { svcWaitSynchronization(task_get_pause_event(), U64_MAX);
linked_list_iter iter;
linked_list_iterate(data->items, &iter); Handle events[2] = {data->resumeEvent, data->cancelEvent};
s32 index = 0;
while(linked_list_iter_has_next(&iter)) { svcWaitSynchronizationN(&index, events, 2, false, U64_MAX);
svcWaitSynchronization(task_get_pause_event(), U64_MAX);
if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) {
Handle events[2] = {data->resumeEvent, data->cancelEvent}; break;
s32 index = 0; }
svcWaitSynchronizationN(&index, events, 2, false, U64_MAX);
list_item* item = (list_item*) linked_list_iter_next(&iter);
if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) { titledb_info* titledbInfo = (titledb_info*) item->data;
break;
} char url[128];
if(titledbInfo->cia.exists) {
list_item* item = (list_item*) linked_list_iter_next(&iter); snprintf(url, sizeof(url), "https://3ds.titledb.com/v1/cia/%lu/icon_l.bin", titledbInfo->cia.id);
titledb_info* titledbInfo = (titledb_info*) item->data; } else if(titledbInfo->tdsx.exists && titledbInfo->tdsx.smdh.exists) {
snprintf(url, sizeof(url), "https://3ds.titledb.com/v1/smdh/%lu/icon_l.bin", titledbInfo->tdsx.smdh.id);
char url[128]; } else {
if(titledbInfo->cia.exists) { continue;
snprintf(url, sizeof(url), "https://3ds.titledb.com/v1/cia/%lu/icon_l.bin", titledbInfo->cia.id); }
} else if(titledbInfo->tdsx.exists && titledbInfo->tdsx.smdh.exists) {
snprintf(url, sizeof(url), "https://3ds.titledb.com/v1/smdh/%lu/icon_l.bin", titledbInfo->tdsx.smdh.id); u8 icon[0x1200];
} else { u32 iconSize = 0;
continue; if(R_SUCCEEDED(task_download_sync(url, &iconSize, &icon, sizeof(icon))) && iconSize == sizeof(icon)) {
} titledbInfo->meta.texture = screen_allocate_free_texture();
screen_load_texture_tiled(titledbInfo->meta.texture, icon, sizeof(icon), 48, 48, GPU_RGB565, false);
u8 icon[0x1200]; }
u32 iconSize = 0; }
if(R_SUCCEEDED(task_download_sync(url, &iconSize, &icon, sizeof(icon))) && iconSize == sizeof(icon)) { }
titledbInfo->meta.texture = screen_allocate_free_texture();
screen_load_texture_tiled(titledbInfo->meta.texture, icon, sizeof(icon), 48, 48, GPU_RGB565, false); svcCloseHandle(data->resumeEvent);
} svcCloseHandle(data->cancelEvent);
}
} data->result = res;
data->finished = true;
svcCloseHandle(data->resumeEvent); }
svcCloseHandle(data->cancelEvent);
void task_free_titledb(list_item* item) {
data->result = res; if(item == NULL) {
data->finished = true; return;
} }
void task_free_titledb(list_item* item) { if(item->data != NULL) {
if(item == NULL) { titledb_info* titledbInfo = (titledb_info*) item->data;
return; if(titledbInfo->meta.texture != 0) {
} screen_unload_texture(titledbInfo->meta.texture);
titledbInfo->meta.texture = 0;
if(item->data != NULL) { }
titledb_info* titledbInfo = (titledb_info*) item->data;
if(titledbInfo->meta.texture != 0) { free(item->data);
screen_unload_texture(titledbInfo->meta.texture); }
titledbInfo->meta.texture = 0;
} free(item);
}
free(item->data);
} void task_clear_titledb(linked_list* items) {
if(items == NULL) {
free(item); return;
} }
void task_clear_titledb(linked_list* items) { linked_list_iter iter;
if(items == NULL) { linked_list_iterate(items, &iter);
return;
} while(linked_list_iter_has_next(&iter)) {
list_item* item = (list_item*) linked_list_iter_next(&iter);
linked_list_iter iter;
linked_list_iterate(items, &iter); linked_list_iter_remove(&iter);
task_free_titledb(item);
while(linked_list_iter_has_next(&iter)) { }
list_item* item = (list_item*) linked_list_iter_next(&iter); }
linked_list_iter_remove(&iter); Result task_populate_titledb(populate_titledb_data* data) {
task_free_titledb(item); if(data == NULL || data->items == NULL) {
} return R_APP_INVALID_ARGUMENT;
} }
Result task_populate_titledb(populate_titledb_data* data) { task_clear_titledb(data->items);
if(data == NULL || data->items == NULL) {
return R_APP_INVALID_ARGUMENT; data->itemsListed = false;
} data->finished = false;
data->result = 0;
task_clear_titledb(data->items); data->cancelEvent = 0;
data->itemsListed = false; Result res = 0;
data->finished = false; if(R_SUCCEEDED(res = svcCreateEvent(&data->cancelEvent, RESET_STICKY))) {
data->result = 0; if(R_SUCCEEDED(res = svcCreateEvent(&data->resumeEvent, RESET_STICKY))) {
data->cancelEvent = 0; svcSignalEvent(data->resumeEvent);
Result res = 0; if(threadCreate(task_populate_titledb_thread, data, 0x10000, 0x19, 1, true) == NULL) {
if(R_SUCCEEDED(res = svcCreateEvent(&data->cancelEvent, RESET_STICKY))) { res = R_APP_THREAD_CREATE_FAILED;
if(R_SUCCEEDED(res = svcCreateEvent(&data->resumeEvent, RESET_STICKY))) { }
svcSignalEvent(data->resumeEvent); }
}
if(threadCreate(task_populate_titledb_thread, data, 0x10000, 0x19, 1, true) == NULL) {
res = R_APP_THREAD_CREATE_FAILED; if(R_FAILED(res)) {
} data->itemsListed = true;
} data->finished = true;
}
if(data->resumeEvent != 0) {
if(R_FAILED(res)) { svcCloseHandle(data->resumeEvent);
data->itemsListed = true; data->resumeEvent = 0;
data->finished = true; }
if(data->resumeEvent != 0) { if(data->cancelEvent != 0) {
svcCloseHandle(data->resumeEvent); svcCloseHandle(data->cancelEvent);
data->resumeEvent = 0; data->cancelEvent = 0;
} }
}
if(data->cancelEvent != 0) {
svcCloseHandle(data->cancelEvent); return res;
data->cancelEvent = 0;
}
}
return res;
} }

View File

@ -0,0 +1,60 @@
#pragma once
typedef struct linked_list_s linked_list;
typedef struct list_item_s list_item;
typedef struct titledb_cia_info_s {
bool exists;
u32 id;
char updatedAt[32];
char version[32];
u64 size;
u64 titleId;
bool installed;
u16 installedVersion;
} titledb_cia_info;
typedef struct titledb_smdh_info_s {
bool exists;
u32 id;
} titledb_smdh_info;
typedef struct titledb_tdsx_info_s {
bool exists;
u32 id;
char updatedAt[32];
char version[32];
u64 size;
titledb_smdh_info smdh;
bool installed;
} titledb_tdsx_info;
typedef struct titledb_info_s {
u32 id;
char category[64];
char headline[512];
titledb_cia_info cia;
titledb_tdsx_info tdsx;
meta_info meta;
} titledb_info;
typedef struct populate_titledb_data_s {
linked_list* items;
volatile bool itemsListed;
volatile bool finished;
Result result;
Handle cancelEvent;
Handle resumeEvent;
} populate_titledb_data;
void task_populate_titledb_update_status(list_item* item);
void task_free_titledb(list_item* item);
void task_clear_titledb(linked_list* items);
Result task_populate_titledb(populate_titledb_data* data);

View File

@ -6,16 +6,9 @@
#include <3ds.h> #include <3ds.h>
#include "uitask.h" #include "uitask.h"
#include "../../list.h" #include "listtitles.h"
#include "../../resources.h" #include "../resources.h"
#include "../../../core/error.h" #include "../../core/core.h"
#include "../../../core/fs.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
#include "../../../core/stringutil.h"
#include "../../../core/data/bnr.h"
#include "../../../core/data/smdh.h"
#include "../../../core/task/task.h"
static Result task_populate_titles_add_ctr(populate_titles_data* data, FS_MediaType mediaType, u64 titleId) { static Result task_populate_titles_add_ctr(populate_titles_data* data, FS_MediaType mediaType, u64 titleId) {
Result res = 0; Result res = 0;

View File

@ -0,0 +1,31 @@
#pragma once
typedef struct linked_list_s linked_list;
typedef struct list_item_s list_item;
typedef struct title_info_s {
FS_MediaType mediaType;
u64 titleId;
char productCode[0x10];
u16 version;
u64 installedSize;
bool twl;
bool hasMeta;
meta_info meta;
} title_info;
typedef struct populate_titles_data_s {
linked_list* items;
void* userData;
bool (*filter)(void* data, u64 titleId, FS_MediaType mediaType);
int (*compare)(void* data, const void* p1, const void* p2);
volatile bool finished;
Result result;
Handle cancelEvent;
} populate_titles_data;
void task_free_title(list_item* item);
void task_clear_titles(linked_list* items);
Result task_populate_titles(populate_titles_data* data);

344
source/fbi/task/uitask.c Normal file
View File

@ -0,0 +1,344 @@
#include <stdio.h>
#include <string.h>
#include <3ds.h>
#include "uitask.h"
#include "../resources.h"
#include "../../core/core.h"
void task_draw_meta_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
meta_info* info = (meta_info*) data;
u32 metaInfoBoxShadowWidth;
u32 metaInfoBoxShadowHeight;
screen_get_texture_size(&metaInfoBoxShadowWidth, &metaInfoBoxShadowHeight, TEXTURE_META_INFO_BOX_SHADOW);
float metaInfoBoxShadowX = x1 + (x2 - x1 - metaInfoBoxShadowWidth) / 2;
float metaInfoBoxShadowY = y1 + (y2 - y1) / 4 - metaInfoBoxShadowHeight / 2;
screen_draw_texture(TEXTURE_META_INFO_BOX_SHADOW, metaInfoBoxShadowX, metaInfoBoxShadowY, metaInfoBoxShadowWidth, metaInfoBoxShadowHeight);
u32 metaInfoBoxWidth;
u32 metaInfoBoxHeight;
screen_get_texture_size(&metaInfoBoxWidth, &metaInfoBoxHeight, TEXTURE_META_INFO_BOX);
float metaInfoBoxX = x1 + (x2 - x1 - metaInfoBoxWidth) / 2;
float metaInfoBoxY = y1 + (y2 - y1) / 4 - metaInfoBoxHeight / 2;
screen_draw_texture(TEXTURE_META_INFO_BOX, metaInfoBoxX, metaInfoBoxY, metaInfoBoxWidth, metaInfoBoxHeight);
if(info->texture != 0) {
u32 iconWidth;
u32 iconHeight;
screen_get_texture_size(&iconWidth, &iconHeight, info->texture);
float iconX = metaInfoBoxX + (64 - iconWidth) / 2;
float iconY = metaInfoBoxY + (metaInfoBoxHeight - iconHeight) / 2;
screen_draw_texture(info->texture, iconX, iconY, iconWidth, iconHeight);
}
float metaTextX = metaInfoBoxX + 64;
float shortDescriptionHeight;
screen_get_string_size_wrap(NULL, &shortDescriptionHeight, info->shortDescription, 0.5f, 0.5f, metaInfoBoxX + metaInfoBoxWidth - 8 - metaTextX);
float longDescriptionHeight;
screen_get_string_size_wrap(NULL, &longDescriptionHeight, info->longDescription, 0.5f, 0.5f, metaInfoBoxX + metaInfoBoxWidth - 8 - metaTextX);
float publisherHeight;
screen_get_string_size_wrap(NULL, &publisherHeight, info->publisher, 0.5f, 0.5f, metaInfoBoxX + metaInfoBoxWidth - 8 - metaTextX);
float shortDescriptionY = metaInfoBoxY + (64 - shortDescriptionHeight - 2 - longDescriptionHeight - 2 - publisherHeight) / 2;
screen_draw_string_wrap(info->shortDescription, metaTextX, shortDescriptionY, 0.5f, 0.5f, COLOR_TEXT, false, metaInfoBoxX + metaInfoBoxWidth - 8);
float longDescriptionY = shortDescriptionY + shortDescriptionHeight + 2;
screen_draw_string_wrap(info->longDescription, metaTextX, longDescriptionY, 0.5f, 0.5f, COLOR_TEXT, false, metaInfoBoxX + metaInfoBoxWidth - 8);
float publisherY = longDescriptionY + longDescriptionHeight + 2;
screen_draw_string_wrap(info->publisher, metaTextX, publisherY, 0.5f, 0.5f, COLOR_TEXT, false, metaInfoBoxX + metaInfoBoxWidth - 8);
}
void task_draw_ext_save_data_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
ext_save_data_info* info = (ext_save_data_info*) data;
if(info->hasMeta) {
task_draw_meta_info(view, &info->meta, x1, y1, x2, y2);
}
char infoText[512];
snprintf(infoText, sizeof(infoText),
"Ext Save Data ID: %016llX\n"
"Shared: %s",
info->extSaveDataId,
info->shared ? "Yes" : "No");
float infoWidth;
screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f);
float infoX = x1 + (x2 - x1 - infoWidth) / 2;
float infoY = y1 + (y2 - y1) / 2 - 8;
screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true);
}
void task_draw_file_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
file_info* info = (file_info*) data;
char infoText[512];
size_t infoTextPos = 0;
if(strlen(info->name) > 48) {
infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Name: %.45s...\n", info->name);
} else {
infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Name: %.48s\n", info->name);
}
infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Attributes: ");
if(info->attributes & (FS_ATTRIBUTE_DIRECTORY | FS_ATTRIBUTE_HIDDEN | FS_ATTRIBUTE_ARCHIVE | FS_ATTRIBUTE_READ_ONLY)) {
bool needsSeparator = false;
if(info->attributes & FS_ATTRIBUTE_DIRECTORY) {
infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Directory");
needsSeparator = true;
}
if(info->attributes & FS_ATTRIBUTE_HIDDEN) {
if(needsSeparator) {
infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, ", ");
}
infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Hidden");
needsSeparator = true;
}
if(info->attributes & FS_ATTRIBUTE_ARCHIVE) {
if(needsSeparator) {
infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, ", ");
}
infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Archive");
needsSeparator = true;
}
if(info->attributes & FS_ATTRIBUTE_READ_ONLY) {
if(needsSeparator) {
infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, ", ");
}
infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Read Only");
needsSeparator = true;
}
} else {
infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "None");
}
infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "\n");
if(!(info->attributes & FS_ATTRIBUTE_DIRECTORY)) {
infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Size: %.2f %s\n",
ui_get_display_size(info->size), ui_get_display_size_units(info->size));
if(info->isCia) {
char regionString[64];
if(info->ciaInfo.hasMeta) {
task_draw_meta_info(view, &info->ciaInfo.meta, x1, y1, x2, y2);
smdh_region_to_string(regionString, info->ciaInfo.meta.region, sizeof(regionString));
} else {
snprintf(regionString, sizeof(regionString), "Unknown");
}
infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos,
"Title ID: %016llX\n"
"Version: %hu (%d.%d.%d)\n"
"Region: %s\n"
"Installed Size: %.2f %s",
info->ciaInfo.titleId,
info->ciaInfo.version, (info->ciaInfo.version >> 10) & 0x3F, (info->ciaInfo.version >> 4) & 0x3F, info->ciaInfo.version & 0xF,
regionString,
ui_get_display_size(info->ciaInfo.installedSize),
ui_get_display_size_units(info->ciaInfo.installedSize));
} else if(info->isTicket) {
infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Ticket ID: %016llX", info->ticketInfo.titleId);
}
}
float infoWidth;
screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f);
float infoX = x1 + (x2 - x1 - infoWidth) / 2;
float infoY = y1 + (y2 - y1) / 2 - 8;
screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true);
}
void task_draw_pending_title_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
pending_title_info* info = (pending_title_info*) data;
char infoText[512];
snprintf(infoText, sizeof(infoText),
"Pending Title ID: %016llX\n"
"Media Type: %s\n"
"Version: %hu (%d.%d.%d)",
info->titleId,
info->mediaType == MEDIATYPE_NAND ? "NAND" : info->mediaType == MEDIATYPE_SD ? "SD" : "Game Card",
info->version, (info->version >> 10) & 0x3F, (info->version >> 4) & 0x3F, info->version & 0xF);
float infoWidth;
screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f);
float infoX = x1 + (x2 - x1 - infoWidth) / 2;
float infoY = y1 + (y2 - y1) / 2 - 8;
screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true);
}
void task_draw_system_save_data_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
system_save_data_info* info = (system_save_data_info*) data;
char infoText[512];
snprintf(infoText, sizeof(infoText), "System Save Data ID: %08lX", info->systemSaveDataId);
float infoWidth;
screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f);
float infoX = x1 + (x2 - x1 - infoWidth) / 2;
float infoY = y1 + (y2 - y1) / 2 - 8;
screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true);
}
void task_draw_ticket_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
ticket_info* info = (ticket_info*) data;
char infoText[512];
snprintf(infoText, sizeof(infoText), "Title ID: %016llX", info->titleId);
float infoWidth;
screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f);
float infoX = x1 + (x2 - x1 - infoWidth) / 2;
float infoY = y1 + (y2 - y1) / 2 - 8;
screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true);
}
void task_draw_title_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
title_info* info = (title_info*) data;
char regionString[64];
if(info->hasMeta) {
task_draw_meta_info(view, &info->meta, x1, y1, x2, y2);
smdh_region_to_string(regionString, info->meta.region, sizeof(regionString));
} else {
snprintf(regionString, sizeof(regionString), "Unknown");
}
char infoText[512];
snprintf(infoText, sizeof(infoText),
"Title ID: %016llX\n"
"Media Type: %s\n"
"Version: %hu (%d.%d.%d)\n"
"Product Code: %s\n"
"Region: %s\n"
"Size: %.2f %s",
info->titleId,
info->mediaType == MEDIATYPE_NAND ? "NAND" : info->mediaType == MEDIATYPE_SD ? "SD" : "Game Card",
info->version, (info->version >> 10) & 0x3F, (info->version >> 4) & 0x3F, info->version & 0xF,
info->productCode,
regionString,
ui_get_display_size(info->installedSize), ui_get_display_size_units(info->installedSize));
float infoWidth;
screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f);
float infoX = x1 + (x2 - x1 - infoWidth) / 2;
float infoY = y1 + (y2 - y1) / 2 - 8;
screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true);
}
void task_draw_titledb_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
titledb_info* info = (titledb_info*) data;
task_draw_meta_info(view, &info->meta, x1, y1, x2, y2);
char infoText[1024];
snprintf(infoText, sizeof(infoText),
"%s\n"
"\n"
"Category: %s\n",
info->headline,
info->category);
float infoWidth;
screen_get_string_size_wrap(&infoWidth, NULL, infoText, 0.5f, 0.5f, x2 - x1 - 10);
// TODO: Wrap by word, not character?
float infoX = x1 + (x2 - x1 - infoWidth) / 2;
float infoY = y1 + (y2 - y1) / 2 - 8;
screen_draw_string_wrap(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true, infoX + infoWidth + 1);
}
void task_draw_titledb_info_cia(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
titledb_info* info = (titledb_info*) data;
task_draw_meta_info(view, &info->meta, x1, y1, x2, y2);
char updatedDate[32] = "";
char updatedTime[32] = "";
sscanf(info->cia.updatedAt, "%31[^T]T%31[^Z]Z", updatedDate, updatedTime);
char infoText[512];
snprintf(infoText, sizeof(infoText),
"Title ID: %016llX\n"
"TitleDB Version: %s\n"
"Installed Version: %hu (%d.%d.%d)\n"
"Size: %.2f %s\n"
"Updated At: %s %s",
info->cia.titleId,
info->cia.version,
info->cia.installedVersion, (info->cia.installedVersion >> 10) & 0x3F, (info->cia.installedVersion >> 4) & 0x3F, info->cia.installedVersion & 0xF,
ui_get_display_size(info->cia.size), ui_get_display_size_units(info->cia.size),
updatedDate, updatedTime);
float infoWidth;
screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f);
float infoX = x1 + (x2 - x1 - infoWidth) / 2;
float infoY = y1 + (y2 - y1) / 2 - 8;
screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true);
}
void task_draw_titledb_info_tdsx(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
titledb_info* info = (titledb_info*) data;
task_draw_meta_info(view, &info->meta, x1, y1, x2, y2);
char updatedDate[32] = "";
char updatedTime[32] = "";
sscanf(info->tdsx.updatedAt, "%31[^T]T%31[^Z]Z", updatedDate, updatedTime);
char infoText[512];
snprintf(infoText, sizeof(infoText),
"TitleDB Version: %s\n"
"Size: %.2f %s\n"
"Updated At: %s %s",
info->tdsx.version,
ui_get_display_size(info->tdsx.size), ui_get_display_size_units(info->tdsx.size),
updatedDate, updatedTime);
float infoWidth;
screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f);
float infoX = x1 + (x2 - x1 - infoWidth) / 2;
float infoY = y1 + (y2 - y1) / 2 - 8;
screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true);
}

30
source/fbi/task/uitask.h Normal file
View File

@ -0,0 +1,30 @@
#pragma once
typedef struct ui_view_s ui_view;
typedef struct meta_info_s {
char shortDescription[0x100];
char longDescription[0x200];
char publisher[0x100];
u32 region;
u32 texture;
} meta_info;
void task_draw_meta_info(ui_view* view, void* data, float x1, float y1, float x2, float y2);
void task_draw_ext_save_data_info(ui_view* view, void* data, float x1, float y1, float x2, float y2);
void task_draw_file_info(ui_view* view, void* data, float x1, float y1, float x2, float y2);
void task_draw_pending_title_info(ui_view* view, void* data, float x1, float y1, float x2, float y2);
void task_draw_system_save_data_info(ui_view* view, void* data, float x1, float y1, float x2, float y2);
void task_draw_ticket_info(ui_view* view, void* data, float x1, float y1, float x2, float y2);
void task_draw_title_info(ui_view* view, void* data, float x1, float y1, float x2, float y2);
void task_draw_titledb_info(ui_view* view, void* data, float x1, float y1, float x2, float y2);
void task_draw_titledb_info_cia(ui_view* view, void* data, float x1, float y1, float x2, float y2);
void task_draw_titledb_info_tdsx(ui_view* view, void* data, float x1, float y1, float x2, float y2);
#include "listextsavedata.h"
#include "listpendingtitles.h"
#include "listsystemsavedata.h"
#include "listtickets.h"
#include "listtitledb.h"
#include "listtitles.h"
#include "listfiles.h"

View File

@ -3,15 +3,11 @@
#include <3ds.h> #include <3ds.h>
#include "resources.h"
#include "section.h" #include "section.h"
#include "action/action.h" #include "action/action.h"
#include "task/uitask.h" #include "task/uitask.h"
#include "../error.h" #include "../core/core.h"
#include "../list.h"
#include "../resources.h"
#include "../ui.h"
#include "../../core/linkedlist.h"
#include "../../core/screen.h"
static list_item install_from_cdn = {"Install from CDN", COLOR_TEXT, action_install_cdn}; static list_item install_from_cdn = {"Install from CDN", COLOR_TEXT, action_install_cdn};
static list_item delete_ticket = {"Delete Ticket", COLOR_TEXT, action_delete_ticket}; static list_item delete_ticket = {"Delete Ticket", COLOR_TEXT, action_delete_ticket};
@ -29,7 +25,7 @@ typedef struct {
} tickets_action_data; } tickets_action_data;
static void tickets_action_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { static void tickets_action_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) {
ui_draw_ticket_info(view, ((tickets_action_data*) data)->selected->data, x1, y1, x2, y2); task_draw_ticket_info(view, ((tickets_action_data*) data)->selected->data, x1, y1, x2, y2);
} }
static void tickets_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { static void tickets_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
@ -80,7 +76,7 @@ static void tickets_action_open(linked_list* items, list_item* selected) {
static void tickets_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { static void tickets_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) {
if(selected != NULL && selected->data != NULL) { if(selected != NULL && selected->data != NULL) {
ui_draw_ticket_info(view, selected->data, x1, y1, x2, y2); task_draw_ticket_info(view, selected->data, x1, y1, x2, y2);
} }
} }

View File

@ -1,248 +1,244 @@
#include <malloc.h> #include <malloc.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <3ds.h> #include <3ds.h>
#include "section.h" #include "resources.h"
#include "action/action.h" #include "section.h"
#include "task/uitask.h" #include "action/action.h"
#include "../error.h" #include "task/uitask.h"
#include "../list.h" #include "../core/core.h"
#include "../resources.h"
#include "../ui.h" static list_item install = {"Install", COLOR_TEXT, action_install_titledb};
#include "../../core/linkedlist.h"
#include "../../core/screen.h" typedef struct {
populate_titledb_data populateData;
static list_item install = {"Install", COLOR_TEXT, action_install_titledb};
bool populated;
typedef struct { } titledb_data;
populate_titledb_data populateData;
typedef struct {
bool populated; linked_list* items;
} titledb_data; list_item* selected;
} titledb_entry_data;
typedef struct {
linked_list* items; typedef struct {
list_item* selected; linked_list* items;
} titledb_entry_data; list_item* selected;
bool cia;
typedef struct { } titledb_action_data;
linked_list* items;
list_item* selected; static void titledb_action_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) {
bool cia; titledb_action_data* actionData = (titledb_action_data*) data;
} titledb_action_data;
if(actionData->cia) {
static void titledb_action_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { task_draw_titledb_info_cia(view, actionData->selected->data, x1, y1, x2, y2);
titledb_action_data* actionData = (titledb_action_data*) data; } else {
task_draw_titledb_info_tdsx(view, actionData->selected->data, x1, y1, x2, y2);
if(actionData->cia) { }
ui_draw_titledb_info_cia(view, actionData->selected->data, x1, y1, x2, y2); }
} else {
ui_draw_titledb_info_tdsx(view, actionData->selected->data, x1, y1, x2, y2); static void titledb_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
} titledb_action_data* actionData = (titledb_action_data*) data;
}
if(hidKeysDown() & KEY_B) {
static void titledb_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { ui_pop();
titledb_action_data* actionData = (titledb_action_data*) data; list_destroy(view);
if(hidKeysDown() & KEY_B) { free(data);
ui_pop();
list_destroy(view); return;
}
free(data);
if(selected != NULL && selected->data != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) {
return; void(*action)(linked_list*, list_item*, bool) = (void(*)(linked_list*, list_item*, bool)) selected->data;
}
ui_pop();
if(selected != NULL && selected->data != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) { list_destroy(view);
void(*action)(linked_list*, list_item*, bool) = (void(*)(linked_list*, list_item*, bool)) selected->data;
action(actionData->items, actionData->selected, actionData->cia);
ui_pop();
list_destroy(view); free(data);
action(actionData->items, actionData->selected, actionData->cia); return;
}
free(data);
if(linked_list_size(items) == 0) {
return; linked_list_add(items, &install);
} }
}
if(linked_list_size(items) == 0) {
linked_list_add(items, &install); static void titledb_action_open(linked_list* items, list_item* selected, bool cia) {
} titledb_action_data* data = (titledb_action_data*) calloc(1, sizeof(titledb_action_data));
} if(data == NULL) {
error_display(NULL, NULL, "Failed to allocate TitleDB action data.");
static void titledb_action_open(linked_list* items, list_item* selected, bool cia) {
titledb_action_data* data = (titledb_action_data*) calloc(1, sizeof(titledb_action_data)); return;
if(data == NULL) { }
error_display(NULL, NULL, "Failed to allocate TitleDB action data.");
data->items = items;
return; data->selected = selected;
} data->cia = cia;
data->items = items; list_display("TitleDB Action", "A: Select, B: Return", data, titledb_action_update, titledb_action_draw_top);
data->selected = selected; }
data->cia = cia;
static void titledb_entry_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) {
list_display("TitleDB Action", "A: Select, B: Return", data, titledb_action_update, titledb_action_draw_top); titledb_entry_data* entryData = (titledb_entry_data*) data;
}
if(selected != NULL) {
static void titledb_entry_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { if(strncmp(selected->name, "CIA", sizeof(selected->name)) == 0) {
titledb_entry_data* entryData = (titledb_entry_data*) data; task_draw_titledb_info_cia(view, entryData->selected->data, x1, y1, x2, y2);
} else if(strncmp(selected->name, "3DSX", sizeof(selected->name)) == 0) {
if(selected != NULL) { task_draw_titledb_info_tdsx(view, entryData->selected->data, x1, y1, x2, y2);
if(strncmp(selected->name, "CIA", sizeof(selected->name)) == 0) { }
ui_draw_titledb_info_cia(view, entryData->selected->data, x1, y1, x2, y2); }
} else if(strncmp(selected->name, "3DSX", sizeof(selected->name)) == 0) { }
ui_draw_titledb_info_tdsx(view, entryData->selected->data, x1, y1, x2, y2);
} static void titledb_entry_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
} titledb_entry_data* entryData = (titledb_entry_data*) data;
}
if(hidKeysDown() & KEY_B) {
static void titledb_entry_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { ui_pop();
titledb_entry_data* entryData = (titledb_entry_data*) data;
linked_list_iter iter;
if(hidKeysDown() & KEY_B) { linked_list_iterate(items, &iter);
ui_pop();
while(linked_list_iter_has_next(&iter)) {
linked_list_iter iter; free(linked_list_iter_next(&iter));
linked_list_iterate(items, &iter); linked_list_iter_remove(&iter);
}
while(linked_list_iter_has_next(&iter)) {
free(linked_list_iter_next(&iter)); list_destroy(view);
linked_list_iter_remove(&iter); free(data);
}
return;
list_destroy(view); }
free(data);
if(selected != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) {
return; titledb_action_open(entryData->items, entryData->selected, (bool) selected->data);
} return;
}
if(selected != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) {
titledb_action_open(entryData->items, entryData->selected, (bool) selected->data); if(linked_list_size(items) == 0) {
return; titledb_info* info = (titledb_info*) entryData->selected->data;
}
if(info->cia.exists) {
if(linked_list_size(items) == 0) { list_item* item = (list_item*) calloc(1, sizeof(list_item));
titledb_info* info = (titledb_info*) entryData->selected->data; if(item != NULL) {
strncpy(item->name, "CIA", sizeof(item->name));
if(info->cia.exists) { item->data = (void*) true;
list_item* item = (list_item*) calloc(1, sizeof(list_item)); item->color = info->cia.installed ? COLOR_TITLEDB_INSTALLED : COLOR_TITLEDB_NOT_INSTALLED;
if(item != NULL) {
strncpy(item->name, "CIA", sizeof(item->name)); linked_list_add(items, item);
item->data = (void*) true; }
item->color = info->cia.installed ? COLOR_TITLEDB_INSTALLED : COLOR_TITLEDB_NOT_INSTALLED; }
linked_list_add(items, item); if(info->tdsx.exists) {
} list_item* item = (list_item*) calloc(1, sizeof(list_item));
} if(item != NULL) {
strncpy(item->name, "3DSX", sizeof(item->name));
if(info->tdsx.exists) { item->data = (void*) false;
list_item* item = (list_item*) calloc(1, sizeof(list_item)); item->color = info->tdsx.installed ? COLOR_TITLEDB_INSTALLED : COLOR_TITLEDB_NOT_INSTALLED;
if(item != NULL) {
strncpy(item->name, "3DSX", sizeof(item->name)); linked_list_add(items, item);
item->data = (void*) false; }
item->color = info->tdsx.installed ? COLOR_TITLEDB_INSTALLED : COLOR_TITLEDB_NOT_INSTALLED; }
}
linked_list_add(items, item); }
}
} static void titledb_entry_open(linked_list* items, list_item* selected) {
} titledb_entry_data* data = (titledb_entry_data*) calloc(1, sizeof(titledb_entry_data));
} if(data == NULL) {
error_display(NULL, NULL, "Failed to allocate TitleDB entry data.");
static void titledb_entry_open(linked_list* items, list_item* selected) {
titledb_entry_data* data = (titledb_entry_data*) calloc(1, sizeof(titledb_entry_data)); return;
if(data == NULL) { }
error_display(NULL, NULL, "Failed to allocate TitleDB entry data.");
data->items = items;
return; data->selected = selected;
}
list_display("TitleDB Entry", "A: Select, B: Return", data, titledb_entry_update, titledb_entry_draw_top);
data->items = items; }
data->selected = selected;
static void titledb_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) {
list_display("TitleDB Entry", "A: Select, B: Return", data, titledb_entry_update, titledb_entry_draw_top); titledb_data* listData = (titledb_data*) data;
}
if(!listData->populateData.itemsListed) {
static void titledb_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { static const char* text = "Loading title list, please wait...\nNOTE: Cancelling may take up to 15 seconds.";
titledb_data* listData = (titledb_data*) data;
float textWidth;
if(!listData->populateData.itemsListed) { float textHeight;
static const char* text = "Loading title list, please wait...\nNOTE: Cancelling may take up to 15 seconds."; screen_get_string_size(&textWidth, &textHeight, text, 0.5f, 0.5f);
screen_draw_string(text, x1 + (x2 - x1 - textWidth) / 2, y1 + (y2 - y1 - textHeight) / 2, 0.5f, 0.5f, COLOR_TEXT, true);
float textWidth; } else if(selected != NULL && selected->data != NULL) {
float textHeight; task_draw_titledb_info(view, selected->data, x1, y1, x2, y2);
screen_get_string_size(&textWidth, &textHeight, text, 0.5f, 0.5f); }
screen_draw_string(text, x1 + (x2 - x1 - textWidth) / 2, y1 + (y2 - y1 - textHeight) / 2, 0.5f, 0.5f, COLOR_TEXT, true); }
} else if(selected != NULL && selected->data != NULL) {
ui_draw_titledb_info(view, selected->data, x1, y1, x2, y2); static void titledb_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
} titledb_data* listData = (titledb_data*) data;
}
svcSignalEvent(listData->populateData.resumeEvent);
static void titledb_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
titledb_data* listData = (titledb_data*) data; if(hidKeysDown() & KEY_B) {
if(!listData->populateData.finished) {
svcSignalEvent(listData->populateData.resumeEvent); svcSignalEvent(listData->populateData.cancelEvent);
while(!listData->populateData.finished) {
if(hidKeysDown() & KEY_B) { svcSleepThread(1000000);
if(!listData->populateData.finished) { }
svcSignalEvent(listData->populateData.cancelEvent); }
while(!listData->populateData.finished) {
svcSleepThread(1000000); ui_pop();
}
} task_clear_titledb(items);
list_destroy(view);
ui_pop();
free(listData);
task_clear_titledb(items); return;
list_destroy(view); }
free(listData); if(!listData->populated || (hidKeysDown() & KEY_X)) {
return; if(!listData->populateData.finished) {
} svcSignalEvent(listData->populateData.cancelEvent);
while(!listData->populateData.finished) {
if(!listData->populated || (hidKeysDown() & KEY_X)) { svcSleepThread(1000000);
if(!listData->populateData.finished) { }
svcSignalEvent(listData->populateData.cancelEvent); }
while(!listData->populateData.finished) {
svcSleepThread(1000000); listData->populateData.items = items;
} Result res = task_populate_titledb(&listData->populateData);
} if(R_FAILED(res)) {
error_display_res(NULL, NULL, res, "Failed to initiate TitleDB list population.");
listData->populateData.items = items; }
Result res = task_populate_titledb(&listData->populateData);
if(R_FAILED(res)) { listData->populated = true;
error_display_res(NULL, NULL, res, "Failed to initiate TitleDB list population."); }
}
if(listData->populateData.finished && R_FAILED(listData->populateData.result)) {
listData->populated = true; error_display_res(NULL, NULL, listData->populateData.result, "Failed to populate TitleDB list.");
}
listData->populateData.result = 0;
if(listData->populateData.finished && R_FAILED(listData->populateData.result)) { }
error_display_res(NULL, NULL, listData->populateData.result, "Failed to populate TitleDB list.");
if(selected != NULL && selected->data != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) {
listData->populateData.result = 0; svcClearEvent(listData->populateData.resumeEvent);
}
titledb_entry_open(items, selected);
if(selected != NULL && selected->data != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) { return;
svcClearEvent(listData->populateData.resumeEvent); }
}
titledb_entry_open(items, selected);
return; void titledb_open() {
} titledb_data* data = (titledb_data*) calloc(1, sizeof(titledb_data));
} if(data == NULL) {
error_display(NULL, NULL, "Failed to allocate TitleDB data.");
void titledb_open() {
titledb_data* data = (titledb_data*) calloc(1, sizeof(titledb_data)); return;
if(data == NULL) { }
error_display(NULL, NULL, "Failed to allocate TitleDB data.");
data->populateData.finished = true;
return;
} list_display("TitleDB.com", "A: Select, B: Return, X: Refresh", data, titledb_update, titledb_draw_top);
data->populateData.finished = true;
list_display("TitleDB.com", "A: Select, B: Return, X: Refresh", data, titledb_update, titledb_draw_top);
} }

View File

@ -4,16 +4,11 @@
#include <3ds.h> #include <3ds.h>
#include "resources.h"
#include "section.h" #include "section.h"
#include "action/action.h" #include "action/action.h"
#include "task/uitask.h" #include "task/uitask.h"
#include "../error.h" #include "../core/core.h"
#include "../list.h"
#include "../resources.h"
#include "../ui.h"
#include "../../core/linkedlist.h"
#include "../../core/screen.h"
#include "../../core/stringutil.h"
static list_item launch_title = {"Launch Title", COLOR_TEXT, action_launch_title}; static list_item launch_title = {"Launch Title", COLOR_TEXT, action_launch_title};
static list_item delete_title = {"Delete Title", COLOR_TEXT, action_delete_title}; static list_item delete_title = {"Delete Title", COLOR_TEXT, action_delete_title};
@ -47,7 +42,7 @@ typedef struct {
} titles_action_data; } titles_action_data;
static void titles_action_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { static void titles_action_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) {
ui_draw_title_info(view, ((titles_action_data*) data)->selected->data, x1, y1, x2, y2); task_draw_title_info(view, ((titles_action_data*) data)->selected->data, x1, y1, x2, y2);
} }
static void titles_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { static void titles_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
@ -196,7 +191,7 @@ static void titles_options_open(titles_data* data) {
static void titles_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { static void titles_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) {
if(selected != NULL && selected->data != NULL) { if(selected != NULL && selected->data != NULL) {
ui_draw_title_info(view, selected->data, x1, y1, x2, y2); task_draw_title_info(view, selected->data, x1, y1, x2, y2);
} }
} }

View File

@ -5,17 +5,11 @@
#include <3ds.h> #include <3ds.h>
#include <jansson.h> #include <jansson.h>
#include "resources.h"
#include "section.h" #include "section.h"
#include "action/action.h" #include "action/action.h"
#include "task/uitask.h" #include "task/uitask.h"
#include "../error.h" #include "../core/core.h"
#include "../info.h"
#include "../prompt.h"
#include "../resources.h"
#include "../ui.h"
#include "../../core/error.h"
#include "../../core/fs.h"
#include "../../core/screen.h"
static void update_check_update(ui_view* view, void* data, float* progress, char* text) { static void update_check_update(ui_view* view, void* data, float* progress, char* text) {
bool hasUpdate = false; bool hasUpdate = false;

View File

@ -1,3 +0,0 @@
#pragma once
void mainmenu_open();

View File

@ -1,297 +0,0 @@
#pragma once
// TODO: Find a way to get rid of this?
#ifndef FILE_NAME_MAX
#define FILE_NAME_MAX 512
#define FILE_PATH_MAX 512
#endif
#define DOWNLOAD_URL_MAX 1024
typedef struct json_t json_t;
typedef struct linked_list_s linked_list;
typedef struct list_item_s list_item;
typedef struct ui_view_s ui_view;
typedef struct meta_info_s {
char shortDescription[0x100];
char longDescription[0x200];
char publisher[0x100];
u32 region;
u32 texture;
} meta_info;
typedef struct title_info_s {
FS_MediaType mediaType;
u64 titleId;
char productCode[0x10];
u16 version;
u64 installedSize;
bool twl;
bool hasMeta;
meta_info meta;
} title_info;
typedef struct pending_title_info_s {
FS_MediaType mediaType;
u64 titleId;
u16 version;
} pending_title_info;
typedef struct ticket_info_s {
u64 titleId;
bool inUse;
} ticket_info;
typedef struct ext_save_data_info_s {
FS_MediaType mediaType;
u64 extSaveDataId;
bool shared;
bool hasMeta;
meta_info meta;
} ext_save_data_info;
typedef struct system_save_data_info_s {
u32 systemSaveDataId;
} system_save_data_info;
typedef struct cia_info_s {
u64 titleId;
u16 version;
u64 installedSize;
bool hasMeta;
meta_info meta;
} cia_info;
typedef struct file_info_s {
FS_Archive archive;
char name[FILE_NAME_MAX];
char path[FILE_PATH_MAX];
u32 attributes;
// Files only
u64 size;
bool isCia;
cia_info ciaInfo;
bool isTicket;
ticket_info ticketInfo;
} file_info;
typedef struct titledb_cia_info_s {
bool exists;
u32 id;
char updatedAt[32];
char version[32];
u64 size;
u64 titleId;
bool installed;
u16 installedVersion;
} titledb_cia_info;
typedef struct titledb_smdh_info_s {
bool exists;
u32 id;
} titledb_smdh_info;
typedef struct titledb_tdsx_info_s {
bool exists;
u32 id;
char updatedAt[32];
char version[32];
u64 size;
titledb_smdh_info smdh;
bool installed;
} titledb_tdsx_info;
typedef struct titledb_info_s {
u32 id;
char category[64];
char headline[512];
titledb_cia_info cia;
titledb_tdsx_info tdsx;
meta_info meta;
} titledb_info;
typedef enum data_op_e {
DATAOP_COPY,
DATAOP_DOWNLOAD,
DATAOP_DELETE
} data_op;
typedef struct data_op_data_s {
void* data;
data_op op;
u32 processed;
u32 total;
// Copy
bool copyEmpty;
Result (*isSrcDirectory)(void* data, u32 index, bool* isDirectory);
Result (*makeDstDirectory)(void* data, u32 index);
Result (*openSrc)(void* data, u32 index, u32* handle);
Result (*closeSrc)(void* data, u32 index, bool succeeded, u32 handle);
Result (*getSrcSize)(void* data, u32 handle, u64* size);
Result (*readSrc)(void* data, u32 handle, u32* bytesRead, void* buffer, u64 offset, u32 size);
// Download
char (*downloadUrls)[DOWNLOAD_URL_MAX];
// Copy/Download
u64 currProcessed;
u64 currTotal;
u32 bytesPerSecond;
u32 estimatedRemainingSeconds;
u32 bufferSize;
Result (*openDst)(void* data, u32 index, void* initialReadBlock, u64 size, u32* handle);
Result (*closeDst)(void* data, u32 index, bool succeeded, u32 handle);
Result (*writeDst)(void* data, u32 handle, u32* bytesWritten, void* buffer, u64 offset, u32 size);
Result (*suspendTransfer)(void* data, u32 index, u32* srcHandle, u32* dstHandle);
Result (*restoreTransfer)(void* data, u32 index, u32* srcHandle, u32* dstHandle);
// Delete
Result (*delete)(void* data, u32 index);
// Suspend
Result (*suspend)(void* data, u32 index);
Result (*restore)(void* data, u32 index);
// Errors
bool (*error)(void* data, u32 index, Result res, ui_view** errorView);
// General
volatile bool finished;
Result result;
Handle cancelEvent;
// Internal
volatile bool retryResponse;
} data_op_data;
typedef struct populate_ext_save_data_data_s {
linked_list* items;
void* userData;
bool (*filter)(void* data, u64 extSaveDataId, FS_MediaType mediaType);
int (*compare)(void* data, const void* p1, const void* p2);
volatile bool finished;
Result result;
Handle cancelEvent;
} populate_ext_save_data_data;
typedef struct populate_files_data_s {
linked_list* items;
FS_Archive archive;
char path[FILE_PATH_MAX];
bool recursive;
bool includeBase;
bool (*filter)(void* data, const char* name, u32 attributes);
void* filterData;
volatile bool finished;
Result result;
Handle cancelEvent;
} populate_files_data;
typedef struct populate_pending_titles_data_s {
linked_list* items;
volatile bool finished;
Result result;
Handle cancelEvent;
} populate_pending_titles_data;
typedef struct populate_system_save_data_data_s {
linked_list* items;
volatile bool finished;
Result result;
Handle cancelEvent;
} populate_system_save_data_data;
typedef struct populate_tickets_data_s {
linked_list* items;
volatile bool finished;
Result result;
Handle cancelEvent;
} populate_tickets_data;
typedef struct populate_titles_data_s {
linked_list* items;
void* userData;
bool (*filter)(void* data, u64 titleId, FS_MediaType mediaType);
int (*compare)(void* data, const void* p1, const void* p2);
volatile bool finished;
Result result;
Handle cancelEvent;
} populate_titles_data;
typedef struct populate_titledb_data_s {
linked_list* items;
volatile bool itemsListed;
volatile bool finished;
Result result;
Handle cancelEvent;
Handle resumeEvent;
} populate_titledb_data;
Result task_download_sync(const char* url, u32* downloadedSize, void* buf, size_t size);
Result task_download_json_sync(const char* url, json_t** json, size_t maxSize);
Result task_download_seed_sync(u64 titleId);
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);
Result task_populate_ext_save_data(populate_ext_save_data_data* data);
int task_compare_files(void* userData, const void* p1, const void* p2);
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, u32 attributes);
Result task_populate_files(populate_files_data* data);
void task_free_pending_title(list_item* item);
void task_clear_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);
Result task_populate_system_save_data(populate_system_save_data_data* data);
void task_populate_tickets_update_use(list_item* item);
void task_free_ticket(list_item* item);
void task_clear_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);
Result task_populate_titles(populate_titles_data* data);
void task_populate_titledb_update_status(list_item* item);
void task_free_titledb(list_item* item);
void task_clear_titledb(linked_list* items);
Result task_populate_titledb(populate_titledb_data* data);

View File

@ -1,40 +0,0 @@
#pragma once
#include <stdbool.h>
typedef struct ui_view_s {
const char* name;
const char* info;
void* data;
void (*update)(struct ui_view_s* view, void* data, float bx1, float by1, float bx2, float by2);
void (*drawTop)(struct ui_view_s* view, void* data, float x1, float y1, float x2, float y2);
void (*drawBottom)(struct ui_view_s* view, void* data, float x1, float y1, float x2, float y2);
Handle active;
} ui_view;
void ui_init();
void ui_exit();
ui_view* ui_create();
void ui_destroy(ui_view* view);
ui_view* ui_top();
bool ui_push(ui_view* view);
void ui_pop();
bool ui_update();
const char* ui_get_display_eta(u32 seconds);
double ui_get_display_size(u64 size);
const char* ui_get_display_size_units(u64 size);
void ui_draw_meta_info(ui_view* view, void* data, float x1, float y1, float x2, float y2);
void ui_draw_ext_save_data_info(ui_view* view, void* data, float x1, float y1, float x2, float y2);
void ui_draw_file_info(ui_view* view, void* data, float x1, float y1, float x2, float y2);
void ui_draw_pending_title_info(ui_view* view, void* data, float x1, float y1, float x2, float y2);
void ui_draw_system_save_data_info(ui_view* view, void* data, float x1, float y1, float x2, float y2);
void ui_draw_ticket_info(ui_view* view, void* data, float x1, float y1, float x2, float y2);
void ui_draw_title_info(ui_view* view, void* data, float x1, float y1, float x2, float y2);
void ui_draw_titledb_info(ui_view* view, void* data, float x1, float y1, float x2, float y2);
void ui_draw_titledb_info_cia(ui_view* view, void* data, float x1, float y1, float x2, float y2);
void ui_draw_titledb_info_tdsx(ui_view* view, void* data, float x1, float y1, float x2, float y2);