Use linked lists to store UI list contents.

This commit is contained in:
Steven Smith 2016-04-25 18:51:17 -07:00
parent 9c1a7c33fb
commit d9b1527f2e
22 changed files with 981 additions and 801 deletions

222
source/core/linkedlist.c Normal file
View File

@ -0,0 +1,222 @@
#include <malloc.h>
#include "linkedlist.h"
void linked_list_init(linked_list* list) {
list->first = NULL;
list->last = NULL;
list->size = 0;
}
void linked_list_destroy(linked_list* list) {
linked_list_clear(list);
}
unsigned int linked_list_size(linked_list* list) {
return list->size;
}
void linked_list_clear(linked_list* list) {
linked_list_node* node = list->first;
while(node != NULL) {
linked_list_node* next = node->next;
free(node);
node = next;
}
list->first = NULL;
list->last = NULL;
list->size = 0;
}
bool linked_list_contains(linked_list* list, void* value) {
linked_list_node* node = list->first;
while(node != NULL) {
if(node->value == value) {
return true;
}
node = node->next;
}
return false;
}
static linked_list_node* linked_list_get_node(linked_list* list, unsigned int index) {
if(index < 0 || index >= list->size) {
return NULL;
}
linked_list_node* node = NULL;
if(index > (list->size - 1) / 2) {
node = list->last;
unsigned int pos = list->size - 1;
while(node != NULL && pos != index) {
node = node->prev;
pos--;
}
} else {
node = list->first;
unsigned int pos = 0;
while(node != NULL && pos != index) {
node = node->next;
pos++;
}
}
return node;
}
void* linked_list_get(linked_list* list, unsigned int index) {
linked_list_node* node = linked_list_get_node(list, index);
return node != NULL ? node->value : NULL;
}
bool linked_list_add(linked_list* list, void* value) {
linked_list_node* node = (linked_list_node*) calloc(1, sizeof(linked_list_node));
if(node == NULL) {
return false;
}
node->value = value;
node->next = NULL;
if(list->first == NULL || list->last == NULL) {
node->prev = NULL;
list->first = node;
list->last = node;
} else {
node->prev = list->last;
list->last->next = node;
list->last = node;
}
list->size++;
return true;
}
bool linked_list_add_at(linked_list* list, unsigned int index, void* value) {
linked_list_node* node = (linked_list_node*) calloc(1, sizeof(linked_list_node));
if(node == NULL) {
return false;
}
node->value = value;
if(index == 0) {
node->prev = NULL;
node->next = list->first;
list->first = node;
} else {
linked_list_node* prev = linked_list_get_node(list, index - 1);
if(prev == NULL) {
free(node);
return false;
}
node->prev = prev;
node->next = prev->next;
prev->next = node;
}
if(node->next != NULL) {
node->next->prev = node;
} else {
list->last = node;
}
list->size++;
return true;
}
static void linked_list_remove_node(linked_list* list, linked_list_node* node) {
if(node->prev != NULL) {
node->prev->next = node->next;
}
if(node->next != NULL) {
node->next->prev = node->prev;
}
if(list->first == node) {
list->first = node->next;
}
if(list->last == node) {
list->last = node->prev;
}
list->size--;
free(node);
}
bool linked_list_remove(linked_list* list, void* value) {
bool found = false;
linked_list_node* node = list->first;
while(node != NULL) {
linked_list_node* next = node->next;
if(node->value == value) {
found = true;
linked_list_remove_node(list, node);
}
node = next;
}
return found;
}
bool linked_list_remove_at(linked_list* list, unsigned int index) {
linked_list_node* node = linked_list_get_node(list, index);
if(node == NULL) {
return false;
}
linked_list_remove_node(list, node);
return true;
}
void linked_list_iterate(linked_list* list, linked_list_iter* iter) {
iter->list = list;
linked_list_iter_restart(iter);
}
void linked_list_iter_restart(linked_list_iter* iter) {
if(iter->list == NULL) {
return;
}
iter->curr = NULL;
iter->next = iter->list->first;
}
bool linked_list_iter_has_next(linked_list_iter* iter) {
return iter->next != NULL;
}
void* linked_list_iter_next(linked_list_iter* iter) {
if(iter->next == NULL) {
return NULL;
}
iter->curr = iter->next;
iter->next = iter->next->next;
return iter->curr->value;
}
void linked_list_iter_remove(linked_list_iter* iter) {
if(iter->curr == NULL) {
return;
}
linked_list_remove_node(iter->list, iter->curr);
}

40
source/core/linkedlist.h Normal file
View File

@ -0,0 +1,40 @@
#pragma once
#include <stdbool.h>
typedef struct linked_list_node_s {
struct linked_list_node_s* prev;
struct linked_list_node_s* next;
void* value;
} linked_list_node;
typedef struct linked_list_s {
linked_list_node* first;
linked_list_node* last;
unsigned int size;
} linked_list;
typedef struct linked_list_iter_s {
linked_list* list;
linked_list_node* curr;
linked_list_node* next;
} linked_list_iter;
void linked_list_init(linked_list* list);
void linked_list_destroy(linked_list* list);
unsigned int linked_list_size(linked_list* list);
void linked_list_clear(linked_list* list);
bool linked_list_contains(linked_list* list, void* value);
void* linked_list_get(linked_list* list, unsigned int index);
bool linked_list_add(linked_list* list, void* value);
bool linked_list_add_at(linked_list* list, unsigned int index, void* value);
bool linked_list_remove(linked_list* list, void* value);
bool linked_list_remove_at(linked_list* list, unsigned int index);
void linked_list_iterate(linked_list* list, linked_list_iter* iter);
void linked_list_iter_restart(linked_list_iter* iter);
bool linked_list_iter_has_next(linked_list_iter* iter);
void* linked_list_iter_next(linked_list_iter* iter);
void linked_list_iter_remove(linked_list_iter* iter);

View File

@ -547,31 +547,35 @@ void screen_draw_texture_crop(u32 id, float x, float y, float width, float heigh
static void screen_get_string_size_internal(float* width, float* height, const char* text, float scaleX, float scaleY, bool oneLine) {
float w = 0;
float h = scaleY * fontGetInfo()->lineFeed;
float h = 0;
float lineWidth = 0;
const uint8_t* p = (const uint8_t*) text;
uint32_t code = 0;
ssize_t units = -1;
while(*p && (units = decode_utf8(&code, p)) != -1 && code > 0) {
p += units;
if(text != NULL) {
h = scaleY * fontGetInfo()->lineFeed;
if(code == '\n') {
if(*p) {
if(lineWidth > w) {
w = lineWidth;
const uint8_t* p = (const uint8_t*) text;
uint32_t code = 0;
ssize_t units = -1;
while(*p && (units = decode_utf8(&code, p)) != -1 && code > 0) {
p += units;
if(code == '\n') {
if(*p) {
if(lineWidth > w) {
w = lineWidth;
}
lineWidth = 0;
if(oneLine) {
break;
}
h += scaleY * fontGetInfo()->lineFeed;
}
lineWidth = 0;
if(oneLine) {
break;
}
h += scaleY * fontGetInfo()->lineFeed;
} else {
lineWidth += scaleX * fontGetCharWidthInfo(fontGlyphIndexFromCodePoint(code))->charWidth;
}
} else {
lineWidth += scaleX * fontGetCharWidthInfo(fontGlyphIndexFromCodePoint(code))->charWidth;
}
}
@ -589,6 +593,10 @@ void screen_get_string_size(float* width, float* height, const char* text, float
}
void screen_draw_string(const char* text, float x, float y, float scaleX, float scaleY, u32 colorId, bool baseline) {
if(text == NULL) {
return;
}
C3D_TexEnv* env = C3D_GetTexEnv(0);
if(env == NULL) {
util_panic("Failed to retrieve combiner settings.");

View File

@ -5,27 +5,36 @@
#include "error.h"
#include "list.h"
#include "../screen.h"
#include "../core/linkedlist.h"
typedef struct {
void* data;
list_item* items;
u32* itemCount;
linked_list items;
u32 selectedIndex;
u32 selectionScroll;
u64 nextSelectionScrollResetTime;
float scrollPos;
u32 lastScrollTouchY;
u64 nextActionTime;
void (*update)(ui_view* view, void* data, list_item** items, u32** itemCount, list_item* selected, bool selectedTouched);
void (*update)(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched);
void (*drawTop)(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected);
} list_data;
static float list_get_item_screen_y(list_data* listData, u32 index) {
float y = -listData->scrollPos;
for(u32 i = 0; i < index && i < *listData->itemCount; i++) {
linked_list_iter iter;
linked_list_iterate(&listData->items, &iter);
int i = 0;
while(linked_list_iter_has_next(&iter) && i < index) {
list_item* item = (list_item*) linked_list_iter_next(&iter);
float stringHeight;
screen_get_string_size(NULL, &stringHeight, listData->items[i].name, 0.5f, 0.5f);
screen_get_string_size(NULL, &stringHeight, item->name, 0.5f, 0.5f);
y += stringHeight;
i++;
}
return y;
@ -33,36 +42,47 @@ static float list_get_item_screen_y(list_data* listData, u32 index) {
static int list_get_item_at(list_data* listData, float screenY) {
float y = -listData->scrollPos;
for(u32 i = 0; i < *listData->itemCount; i++) {
linked_list_iter iter;
linked_list_iterate(&listData->items, &iter);
int i = 0;
while(linked_list_iter_has_next(&iter)) {
list_item* item = (list_item*) linked_list_iter_next(&iter);
float stringHeight;
screen_get_string_size(NULL, &stringHeight, listData->items[i].name, 0.5f, 0.5f);
screen_get_string_size(NULL, &stringHeight, item->name, 0.5f, 0.5f);
if(screenY >= y && screenY < y + stringHeight) {
return (int) i;
return i;
}
y += stringHeight;
i++;
}
return -1;
}
static void list_validate_pos(list_data* listData, float by1, float by2) {
if(listData->items == NULL || listData->itemCount == NULL || *listData->itemCount <= 0 || listData->selectedIndex <= 0) {
u32 size = linked_list_size(&listData->items);
if(size == 0 || listData->selectedIndex < 0) {
listData->selectedIndex = 0;
listData->scrollPos = 0;
}
if(listData->items != NULL && listData->itemCount != NULL && *listData->itemCount > 0) {
if(listData->selectedIndex > *listData->itemCount - 1) {
listData->selectedIndex = *listData->itemCount - 1;
if(size > 0) {
if(listData->selectedIndex > size - 1) {
listData->selectedIndex = size - 1;
listData->scrollPos = 0;
}
float lastItemHeight;
screen_get_string_size(NULL, &lastItemHeight, listData->items[*listData->itemCount - 1].name, 0.5f, 0.5f);
screen_get_string_size(NULL, &lastItemHeight, ((list_item*) linked_list_get(&listData->items, size - 1))->name, 0.5f, 0.5f);
float lastPageEnd = list_get_item_screen_y(listData, *listData->itemCount - 1);
float lastPageEnd = list_get_item_screen_y(listData, size - 1);
if(lastPageEnd < by2 - by1 - lastItemHeight) {
listData->scrollPos -= (by2 - by1 - lastItemHeight) - lastPageEnd;
}
@ -76,12 +96,14 @@ static void list_validate_pos(list_data* listData, float by1, float by2) {
static void list_update(ui_view* view, void* data, float bx1, float by1, float bx2, float by2) {
list_data* listData = (list_data*) data;
u32 size = linked_list_size(&listData->items);
bool selectedTouched = false;
if(listData->items != NULL && listData->itemCount != NULL && *listData->itemCount > 0) {
if(size > 0) {
list_validate_pos(listData, by1, by2);
float itemWidth;
screen_get_string_size(&itemWidth, NULL, listData->items[listData->selectedIndex].name, 0.5f, 0.5f);
screen_get_string_size(&itemWidth, NULL, ((list_item*) linked_list_get(&listData->items, listData->selectedIndex))->name, 0.5f, 0.5f);
if(itemWidth > bx2 - bx1) {
if(listData->selectionScroll == 0 || listData->selectionScroll >= itemWidth - (bx2 - bx1)) {
if(listData->nextSelectionScrollResetTime == 0) {
@ -100,7 +122,7 @@ static void list_update(ui_view* view, void* data, float bx1, float by1, float b
u32 lastSelectedIndex = listData->selectedIndex;
if(((hidKeysDown() & KEY_DOWN) || ((hidKeysHeld() & KEY_DOWN) && osGetTime() >= listData->nextActionTime)) && listData->selectedIndex < *listData->itemCount - 1) {
if(((hidKeysDown() & KEY_DOWN) || ((hidKeysHeld() & KEY_DOWN) && osGetTime() >= listData->nextActionTime)) && listData->selectedIndex < size - 1) {
listData->selectedIndex++;
listData->nextActionTime = osGetTime() + ((hidKeysDown() & KEY_DOWN) ? 500 : 100);
}
@ -110,8 +132,8 @@ static void list_update(ui_view* view, void* data, float bx1, float by1, float b
listData->nextActionTime = osGetTime() + ((hidKeysDown() & KEY_UP) ? 500 : 100);
}
if(((hidKeysDown() & KEY_RIGHT) || ((hidKeysHeld() & KEY_RIGHT) && osGetTime() >= listData->nextActionTime)) && listData->selectedIndex < *listData->itemCount - 1) {
u32 remaining = *listData->itemCount - 1 - listData->selectedIndex;
if(((hidKeysDown() & KEY_RIGHT) || ((hidKeysHeld() & KEY_RIGHT) && osGetTime() >= listData->nextActionTime)) && listData->selectedIndex < size - 1) {
u32 remaining = size - 1 - listData->selectedIndex;
listData->selectedIndex += remaining < 13 ? remaining : 13;
listData->nextActionTime = osGetTime() + ((hidKeysDown() & KEY_RIGHT) ? 500 : 100);
@ -129,7 +151,7 @@ static void list_update(ui_view* view, void* data, float bx1, float by1, float b
listData->nextSelectionScrollResetTime = 0;
float itemHeight;
screen_get_string_size(NULL, &itemHeight, listData->items[listData->selectedIndex].name, 0.5f, 0.5f);
screen_get_string_size(NULL, &itemHeight, ((list_item*) linked_list_get(&listData->items, listData->selectedIndex))->name, 0.5f, 0.5f);
float itemY = list_get_item_screen_y(listData, listData->selectedIndex);
if(itemY + itemHeight > by2 - by1) {
@ -167,7 +189,7 @@ static void list_update(ui_view* view, void* data, float bx1, float by1, float b
}
if(listData->update != NULL) {
listData->update(view, listData->data, &listData->items, &listData->itemCount, listData->items != NULL && listData->itemCount != NULL && *listData->itemCount > 0 ? &listData->items[listData->selectedIndex] : NULL, selectedTouched);
listData->update(view, listData->data, &listData->items, linked_list_get(&listData->items, listData->selectedIndex), selectedTouched);
}
}
@ -175,7 +197,7 @@ static void list_draw_top(ui_view* view, void* data, float x1, float y1, float x
list_data* listData = (list_data*) data;
if(listData->drawTop != NULL) {
listData->drawTop(view, listData->data, x1, y1, x2, y2, listData->items != NULL && listData->itemCount != NULL && *listData->itemCount > 0 ? &listData->items[listData->selectedIndex] : NULL);
listData->drawTop(view, listData->data, x1, y1, x2, y2, linked_list_get(&listData->items, listData->selectedIndex));
}
}
@ -184,34 +206,45 @@ static void list_draw_bottom(ui_view* view, void* data, float x1, float y1, floa
list_validate_pos(listData, y1, y2);
if(listData->items != NULL && listData->itemCount != NULL) {
float y = y1 - listData->scrollPos;
for(u32 i = 0; i < *listData->itemCount && y < y2; i++) {
float stringHeight;
screen_get_string_size(NULL, &stringHeight, listData->items[i].name, 0.5f, 0.5f);
float y = y1 - listData->scrollPos;
if(y > y1 - stringHeight) {
float x = x1 + 2;
if(i == listData->selectedIndex) {
x -= listData->selectionScroll;
}
linked_list_iter iter;
linked_list_iterate(&listData->items, &iter);
screen_draw_string(listData->items[i].name, x, y, 0.5f, 0.5f, listData->items[i].rgba, false);
u32 i = 0;
while(linked_list_iter_has_next(&iter)) {
if(y > y2) {
break;
}
if(i == listData->selectedIndex) {
u32 selectionOverlayWidth = 0;
u32 selectionOverlayHeight = 0;
screen_get_texture_size(&selectionOverlayWidth, &selectionOverlayHeight, TEXTURE_SELECTION_OVERLAY);
screen_draw_texture(TEXTURE_SELECTION_OVERLAY, (x1 + x2 - selectionOverlayWidth) / 2, y, selectionOverlayWidth, stringHeight);
}
list_item* item = linked_list_iter_next(&iter);
float stringHeight;
screen_get_string_size(NULL, &stringHeight, item->name, 0.5f, 0.5f);
if(y > y1 - stringHeight) {
float x = x1 + 2;
if(i == listData->selectedIndex) {
x -= listData->selectionScroll;
}
y += stringHeight;
screen_draw_string(item->name, x, y, 0.5f, 0.5f, item->color, false);
if(i == listData->selectedIndex) {
u32 selectionOverlayWidth = 0;
u32 selectionOverlayHeight = 0;
screen_get_texture_size(&selectionOverlayWidth, &selectionOverlayHeight, TEXTURE_SELECTION_OVERLAY);
screen_draw_texture(TEXTURE_SELECTION_OVERLAY, (x1 + x2 - selectionOverlayWidth) / 2, y, selectionOverlayWidth, stringHeight);
}
}
y += stringHeight;
i++;
}
}
void list_display(const char* name, const char* info, void* data, void (*update)(ui_view* view, void* data, list_item** contents, u32** itemCount, list_item* selected, bool selectedTouched),
void list_display(const char* name, const char* info, void* data, void (*update)(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched),
void (*drawTop)(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected)) {
list_data* listData = (list_data*) calloc(1, sizeof(list_data));
if(listData == NULL) {
@ -221,8 +254,7 @@ void list_display(const char* name, const char* info, void* data, void (*update)
}
listData->data = data;
listData->items = NULL;
listData->itemCount = NULL;
linked_list_init(&listData->items);
listData->selectedIndex = 0;
listData->selectionScroll = 0;
listData->nextSelectionScrollResetTime = 0;
@ -249,6 +281,8 @@ void list_display(const char* name, const char* info, void* data, void (*update)
}
void list_destroy(ui_view* view) {
linked_list_destroy(&((list_data*) view->data)->items);
free(view->data);
free(view);
}

View File

@ -3,13 +3,14 @@
#include <sys/syslimits.h>
#include "ui.h"
#include "../core/linkedlist.h"
typedef struct {
char name[NAME_MAX];
u32 rgba;
u32 color;
void* data;
} list_item;
void list_display(const char* name, const char* info, void* data, void (*update)(ui_view* view, void* data, list_item** contents, u32** itemCount, list_item* selected, bool selectedTouched),
void list_display(const char* name, const char* info, void* data, void (*update)(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched),
void (*drawTop)(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected));
void list_destroy(ui_view* view);

View File

@ -8,24 +8,19 @@
#include "section/section.h"
#include "../screen.h"
#define MAINMENU_ITEM_COUNT 13
static u32 mainmenu_item_count = MAINMENU_ITEM_COUNT;
static list_item mainmenu_items[MAINMENU_ITEM_COUNT] = {
{"SD", COLOR_TEXT, files_open_sd},
{"CTR NAND", COLOR_TEXT, files_open_ctr_nand},
{"TWL NAND", COLOR_TEXT, files_open_twl_nand},
{"TWL Photo", COLOR_TEXT, files_open_twl_photo},
{"TWL Sound", COLOR_TEXT, files_open_twl_sound},
{"Dump NAND", COLOR_TEXT, dump_nand},
{"Titles", COLOR_TEXT, titles_open},
{"Pending Titles", COLOR_TEXT, pendingtitles_open},
{"Tickets", COLOR_TEXT, tickets_open},
{"Ext Save Data", COLOR_TEXT, extsavedata_open},
{"System Save Data", COLOR_TEXT, systemsavedata_open},
{"Network Install", COLOR_TEXT, networkinstall_open},
{"QR Code Install", COLOR_TEXT, qrinstall_open},
};
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 twl_nand = {"TWL NAND", COLOR_TEXT, files_open_twl_nand};
static list_item twl_photo = {"TWL Photo", COLOR_TEXT, files_open_twl_photo};
static list_item twl_sound = {"TWL Sound", COLOR_TEXT, files_open_twl_sound};
static list_item dump_nand = {"Dump NAND", COLOR_TEXT, dumpnand_open};
static list_item titles = {"Titles", COLOR_TEXT, titles_open};
static list_item pending_titles = {"Pending Titles", COLOR_TEXT, pendingtitles_open};
static list_item tickets = {"Tickets", COLOR_TEXT, tickets_open};
static list_item ext_save_data = {"Ext Save Data", COLOR_TEXT, extsavedata_open};
static list_item system_save_data = {"System Save Data", COLOR_TEXT, systemsavedata_open};
static list_item network_install = {"Network Install", COLOR_TEXT, networkinstall_open};
static list_item qr_code_install = {"QR Code Install", COLOR_TEXT, qrinstall_open};
static void mainmenu_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) {
u32 logoWidth;
@ -48,7 +43,7 @@ static void mainmenu_draw_top(ui_view* view, void* data, float x1, float y1, flo
screen_draw_string(verString, verX, verY, 0.5f, 0.5f, COLOR_TEXT, false);
}
static void mainmenu_update(ui_view* view, void* data, list_item** items, u32** itemCount, list_item* selected, bool selectedTouched) {
static void mainmenu_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
if(hidKeysDown() & KEY_START) {
ui_pop();
list_destroy(view);
@ -61,9 +56,20 @@ static void mainmenu_update(ui_view* view, void* data, list_item** items, u32**
return;
}
if(*itemCount != &mainmenu_item_count || *items != mainmenu_items) {
*itemCount = &mainmenu_item_count;
*items = mainmenu_items;
if(linked_list_size(items) == 0) {
linked_list_add(items, &sd);
linked_list_add(items, &ctr_nand);
linked_list_add(items, &twl_nand);
linked_list_add(items, &twl_photo);
linked_list_add(items, &twl_sound);
linked_list_add(items, &dump_nand);
linked_list_add(items, &titles);
linked_list_add(items, &pending_titles);
linked_list_add(items, &tickets);
linked_list_add(items, &ext_save_data);
linked_list_add(items, &system_save_data);
linked_list_add(items, &network_install);
linked_list_add(items, &qr_code_install);
}
}

View File

@ -51,6 +51,9 @@ static void action_export_secure_value_update(ui_view* view, void* data, float*
}
}
ui_pop();
info_destroy(view);
if(R_SUCCEEDED(res)) {
prompt_display("Success", "Secure value exported.", COLOR_TEXT, false, info, NULL, ui_draw_title_info, NULL);
} else {

View File

@ -103,7 +103,7 @@ static void dumpnand_onresponse(ui_view* view, void* data, bool response) {
}
}
void dump_nand() {
void dumpnand_open() {
dump_nand_data* data = (dump_nand_data*) calloc(1, sizeof(dump_nand_data));
if(data == NULL) {
error_display(NULL, NULL, NULL, "Failed to allocate dump NAND data.");

View File

@ -6,26 +6,18 @@
#include "action/action.h"
#include "section.h"
#include "../error.h"
#include "../list.h"
#include "../../screen.h"
#define EXTSAVEDATA_MAX 512
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 delete_save_data = {"Delete Save Data", COLOR_TEXT, action_delete_ext_save_data};
typedef struct {
list_item items[EXTSAVEDATA_MAX];
u32 count;
Handle cancelEvent;
bool populated;
} extsavedata_data;
#define EXTSAVEDATA_ACTION_COUNT 3
static u32 extsavedata_action_count = EXTSAVEDATA_ACTION_COUNT;
static list_item extsavedata_action_items[EXTSAVEDATA_ACTION_COUNT] = {
{"Browse User Save Data", COLOR_TEXT, action_browse_user_ext_save_data},
{"Browse SpotPass Save Data", COLOR_TEXT, action_browse_boss_ext_save_data},
{"Delete Save Data", COLOR_TEXT, action_delete_ext_save_data},
};
typedef struct {
ext_save_data_info* info;
bool* populated;
@ -35,7 +27,7 @@ static void extsavedata_action_draw_top(ui_view* view, void* data, float x1, flo
ui_draw_ext_save_data_info(view, ((extsavedata_action_data*) data)->info, x1, y1, x2, y2);
}
static void extsavedata_action_update(ui_view* view, void* data, list_item** items, u32** itemCount, list_item* selected, bool selectedTouched) {
static void extsavedata_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
extsavedata_action_data* actionData = (extsavedata_action_data*) data;
if(hidKeysDown() & KEY_B) {
@ -60,9 +52,10 @@ static void extsavedata_action_update(ui_view* view, void* data, list_item** ite
return;
}
if(*itemCount != &extsavedata_action_count || *items != extsavedata_action_items) {
*itemCount = &extsavedata_action_count;
*items = extsavedata_action_items;
if(linked_list_size(items) == 0) {
linked_list_add(items, &browse_user_save_data);
linked_list_add(items, &browse_spotpass_save_data);
linked_list_add(items, &delete_save_data);
}
}
@ -86,7 +79,7 @@ static void extsavedata_draw_top(ui_view* view, void* data, float x1, float y1,
}
}
static void extsavedata_update(ui_view* view, void* data, list_item** items, u32** itemCount, list_item* selected, bool selectedTouched) {
static void extsavedata_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
extsavedata_data* listData = (extsavedata_data*) data;
if(hidKeysDown() & KEY_B) {
@ -100,9 +93,10 @@ static void extsavedata_update(ui_view* view, void* data, list_item** items, u32
}
ui_pop();
task_clear_ext_save_data(items);
list_destroy(view);
task_clear_ext_save_data(listData->items, &listData->count);
free(listData);
return;
}
@ -117,7 +111,7 @@ static void extsavedata_update(ui_view* view, void* data, list_item** items, u32
listData->cancelEvent = 0;
}
listData->cancelEvent = task_populate_ext_save_data(listData->items, &listData->count, EXTSAVEDATA_MAX);
listData->cancelEvent = task_populate_ext_save_data(items);
listData->populated = true;
}
@ -125,11 +119,6 @@ static void extsavedata_update(ui_view* view, void* data, list_item** items, u32
extsavedata_action_open((ext_save_data_info*) selected->data, &listData->populated);
return;
}
if(*itemCount != &listData->count || *items != listData->items) {
*itemCount = &listData->count;
*items = listData->items;
}
}
void extsavedata_open() {

View File

@ -8,14 +8,29 @@
#include "action/action.h"
#include "section.h"
#include "../error.h"
#include "../list.h"
#include "../../screen.h"
#include "../../util.h"
#include "task/task.h"
#define FILES_MAX 1024
static list_item delete = {"Delete", COLOR_TEXT, action_delete_contents};
static list_item copy = {"Copy", COLOR_TEXT, action_copy_contents};
static list_item paste = {"Paste", COLOR_TEXT, action_paste_contents};
static list_item install_cia = {"Install CIA", COLOR_TEXT, action_install_cias};
static list_item install_and_delete_cia = {"Install and delete CIA", COLOR_TEXT, action_install_cias_delete};
static list_item install_ticket = {"Install ticket", COLOR_TEXT, action_install_tickets};
static list_item delete_all_contents = {"Delete all contents", COLOR_TEXT, action_delete_dir_contents};
static list_item install_all_cias = {"Install all CIAs", COLOR_TEXT, action_install_cias};
static list_item install_and_delete_all_cias = {"Install and delete all CIAs", COLOR_TEXT, action_install_cias_delete};
static list_item delete_all_cias = {"Delete all CIAs", COLOR_TEXT, action_delete_dir_cias};
static list_item install_all_tickets = {"Install all tickets", COLOR_TEXT, action_install_tickets};
typedef struct {
list_item items[FILES_MAX];
u32 count;
Handle cancelEvent;
bool populated;
@ -26,84 +41,6 @@ typedef struct {
file_info parentDir;
} files_data;
#define FILES_ACTION_COUNT 3
static u32 files_action_count = FILES_ACTION_COUNT;
static list_item files_action_items[FILES_ACTION_COUNT] = {
{"Delete", COLOR_TEXT, action_delete_contents},
{"Copy", COLOR_TEXT, action_copy_contents},
{"Paste", COLOR_TEXT, action_paste_contents},
};
#define CIA_FILES_ACTION_COUNT 5
static u32 cia_files_action_count = CIA_FILES_ACTION_COUNT;
static list_item cia_files_action_items[CIA_FILES_ACTION_COUNT] = {
{"Install CIA", COLOR_TEXT, action_install_cias},
{"Install and delete CIA", COLOR_TEXT, action_install_cias_delete},
{"Delete", COLOR_TEXT, action_delete_contents},
{"Copy", COLOR_TEXT, action_copy_contents},
{"Paste", COLOR_TEXT, action_paste_contents},
};
#define TICKET_FILES_ACTION_COUNT 4
static u32 ticket_files_action_count = TICKET_FILES_ACTION_COUNT;
static list_item ticket_files_action_items[TICKET_FILES_ACTION_COUNT] = {
{"Install ticket", COLOR_TEXT, action_install_tickets},
{"Delete", COLOR_TEXT, action_delete_contents},
{"Copy", COLOR_TEXT, action_copy_contents},
{"Paste", COLOR_TEXT, action_paste_contents},
};
#define DIRECTORIES_ACTION_COUNT 4
static u32 directories_action_count = DIRECTORIES_ACTION_COUNT;
static list_item directories_action_items[DIRECTORIES_ACTION_COUNT] = {
{"Delete all contents", COLOR_TEXT, action_delete_dir_contents},
{"Delete", COLOR_TEXT, action_delete_dir},
{"Copy", COLOR_TEXT, action_copy_contents},
{"Paste", COLOR_TEXT, action_paste_contents},
};
#define CIA_DIRECTORIES_ACTION_COUNT 7
static u32 cia_directories_action_count = CIA_DIRECTORIES_ACTION_COUNT;
static list_item cia_directories_action_items[CIA_DIRECTORIES_ACTION_COUNT] = {
{"Install all CIAs", COLOR_TEXT, action_install_cias},
{"Install and delete all CIAs", COLOR_TEXT, action_install_cias_delete},
{"Delete all CIAs", COLOR_TEXT, action_delete_dir_cias},
{"Delete all contents", COLOR_TEXT, action_delete_dir_contents},
{"Delete", COLOR_TEXT, action_delete_dir},
{"Copy", COLOR_TEXT, action_copy_contents},
{"Paste", COLOR_TEXT, action_paste_contents},
};
#define TICKET_DIRECTORIES_ACTION_COUNT 5
static u32 ticket_directories_action_count = TICKET_DIRECTORIES_ACTION_COUNT;
static list_item ticket_directories_action_items[TICKET_DIRECTORIES_ACTION_COUNT] = {
{"Install all tickets", COLOR_TEXT, action_install_tickets},
{"Delete all contents", COLOR_TEXT, action_delete_dir_contents},
{"Delete", COLOR_TEXT, action_delete_dir},
{"Copy", COLOR_TEXT, action_copy_contents},
{"Paste", COLOR_TEXT, action_paste_contents},
};
#define CIA_TICKET_DIRECTORIES_ACTION_COUNT 8
static u32 cia_ticket_directories_action_count = CIA_TICKET_DIRECTORIES_ACTION_COUNT;
static list_item cia_ticket_directories_action_items[CIA_TICKET_DIRECTORIES_ACTION_COUNT] = {
{"Install all CIAs", COLOR_TEXT, action_install_cias},
{"Install and delete all CIAs", COLOR_TEXT, action_install_cias_delete},
{"Install all tickets", COLOR_TEXT, action_install_tickets},
{"Delete all CIAs", COLOR_TEXT, action_delete_dir_cias},
{"Delete all contents", COLOR_TEXT, action_delete_dir_contents},
{"Delete", COLOR_TEXT, action_delete_dir},
{"Copy", COLOR_TEXT, action_copy_contents},
{"Paste", COLOR_TEXT, action_paste_contents},
};
typedef struct {
file_info* info;
bool* populated;
@ -113,7 +50,7 @@ static void files_action_draw_top(ui_view* view, void* data, float x1, float y1,
ui_draw_file_info(view, ((files_action_data*) data)->info, x1, y1, x2, y2);
}
static void files_action_update(ui_view* view, void* data, list_item** items, u32** itemCount, list_item* selected, bool selectedTouched) {
static void files_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
files_action_data* actionData = (files_action_data*) data;
if(hidKeysDown() & KEY_B) {
@ -138,45 +75,33 @@ static void files_action_update(ui_view* view, void* data, list_item** items, u3
return;
}
if(actionData->info->isDirectory) {
if(actionData->info->containsCias && actionData->info->containsTickets) {
if(*itemCount != &cia_ticket_directories_action_count || *items != cia_ticket_directories_action_items) {
*itemCount = &cia_ticket_directories_action_count;
*items = cia_ticket_directories_action_items;
if(linked_list_size(items) == 0) {
if(actionData->info->isDirectory) {
if(actionData->info->containsCias) {
linked_list_add(items, &install_all_cias);
linked_list_add(items, &install_and_delete_all_cias);
linked_list_add(items, &delete_all_cias);
}
} else if(actionData->info->containsCias) {
if(*itemCount != &cia_directories_action_count || *items != cia_directories_action_items) {
*itemCount = &cia_directories_action_count;
*items = cia_directories_action_items;
}
} else if(actionData->info->containsTickets) {
if(*itemCount != &ticket_directories_action_count || *items != ticket_directories_action_items) {
*itemCount = &ticket_directories_action_count;
*items = ticket_directories_action_items;
if(actionData->info->containsTickets) {
linked_list_add(items, &install_all_tickets);
}
linked_list_add(items, &delete_all_contents);
} else {
if(*itemCount != &directories_action_count || *items != directories_action_items) {
*itemCount = &directories_action_count;
*items = directories_action_items;
}
}
} else {
if(actionData->info->isCia) {
if(*itemCount != &cia_files_action_count || *items != cia_files_action_items) {
*itemCount = &cia_files_action_count;
*items = cia_files_action_items;
}
} else if(actionData->info->isTicket) {
if(*itemCount != &ticket_files_action_count || *items != ticket_files_action_items) {
*itemCount = &ticket_files_action_count;
*items = ticket_files_action_items;
}
} else {
if(*itemCount != &files_action_count || *items != files_action_items) {
*itemCount = &files_action_count;
*items = files_action_items;
if(actionData->info->isCia) {
linked_list_add(items, &install_cia);
linked_list_add(items, &install_and_delete_cia);
}
if(actionData->info->isTicket) {
linked_list_add(items, &install_ticket);
}
}
linked_list_add(items, &delete);
linked_list_add(items, &copy);
linked_list_add(items, &paste);
}
}
@ -200,7 +125,7 @@ static void files_draw_top(ui_view* view, void* data, float x1, float y1, float
}
}
static void files_repopulate(files_data* listData) {
static void files_repopulate(files_data* listData, linked_list* items) {
if(listData->cancelEvent != 0) {
svcSignalEvent(listData->cancelEvent);
while(svcWaitSynchronization(listData->cancelEvent, 0) == 0) {
@ -222,11 +147,11 @@ static void files_repopulate(files_data* listData) {
util_get_path_file(listData->parentDir.name, listData->parentDir.path, NAME_MAX);
}
listData->cancelEvent = task_populate_files(listData->items, &listData->count, FILES_MAX, &listData->currDir);
listData->cancelEvent = task_populate_files(items, &listData->currDir);
listData->populated = true;
}
static void files_navigate(files_data* listData, const char* path) {
static void files_navigate(files_data* listData, linked_list* items, const char* path) {
strncpy(listData->currDir.path, path, PATH_MAX);
util_get_path_file(listData->currDir.name, listData->currDir.path, NAME_MAX);
@ -235,10 +160,10 @@ static void files_navigate(files_data* listData, const char* path) {
strncpy(listData->parentDir.path, parentPath, PATH_MAX);
util_get_path_file(listData->parentDir.name, listData->parentDir.path, NAME_MAX);
files_repopulate(listData);
files_repopulate(listData, items);
}
static void files_update(ui_view* view, void* data, list_item** items, u32** itemCount, list_item* selected, bool selectedTouched) {
static void files_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
files_data* listData = (files_data*) data;
if(hidKeysDown() & KEY_B) {
@ -263,13 +188,14 @@ static void files_update(ui_view* view, void* data, list_item** items, u32** ite
}
ui_pop();
task_clear_files(items);
list_destroy(view);
task_clear_files(listData->items, &listData->count);
free(listData);
return;
} else {
files_navigate(listData, listData->parentDir.path);
files_navigate(listData, items, listData->parentDir.path);
}
}
@ -282,7 +208,7 @@ static void files_update(ui_view* view, void* data, list_item** items, u32** ite
file_info* fileInfo = (file_info*) selected->data;
if(util_is_dir(&listData->archive, fileInfo->path)) {
files_navigate(listData, fileInfo->path);
files_navigate(listData, items, fileInfo->path);
} else {
files_action_open(fileInfo, &listData->populated);
return;
@ -290,12 +216,7 @@ static void files_update(ui_view* view, void* data, list_item** items, u32** ite
}
if(!listData->populated || (hidKeysDown() & KEY_X)) {
files_repopulate(listData);
}
if(*itemCount != &listData->count || *items != listData->items) {
*itemCount = &listData->count;
*items = listData->items;
files_repopulate(listData, items);
}
}

View File

@ -6,25 +6,17 @@
#include "action/action.h"
#include "section.h"
#include "../error.h"
#include "../list.h"
#include "../../screen.h"
#define PENDINGTITLES_MAX 1024
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};
typedef struct {
list_item items[PENDINGTITLES_MAX];
u32 count;
Handle cancelEvent;
bool populated;
} pendingtitles_data;
#define PENDINGTITLES_ACTION_COUNT 2
static u32 pending_titles_action_count = PENDINGTITLES_ACTION_COUNT;
static list_item pending_titles_action_items[PENDINGTITLES_ACTION_COUNT] = {
{"Delete Pending Title", COLOR_TEXT, action_delete_pending_title},
{"Delete All Pending Titles", COLOR_TEXT, action_delete_all_pending_titles},
};
typedef struct {
pending_title_info* info;
bool* populated;
@ -34,7 +26,7 @@ static void pendingtitles_action_draw_top(ui_view* view, void* data, float x1, f
ui_draw_pending_title_info(view, ((pendingtitles_action_data*) data)->info, x1, y1, x2, y2);
}
static void pendingtitles_action_update(ui_view* view, void* data, list_item** items, u32** itemCount, list_item* selected, bool selectedTouched) {
static void pendingtitles_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
pendingtitles_action_data* actionData = (pendingtitles_action_data*) data;
if(hidKeysDown() & KEY_B) {
@ -59,9 +51,9 @@ static void pendingtitles_action_update(ui_view* view, void* data, list_item** i
return;
}
if(*itemCount != &pending_titles_action_count || *items != pending_titles_action_items) {
*itemCount = &pending_titles_action_count;
*items = pending_titles_action_items;
if(linked_list_size(items) == 0) {
linked_list_add(items, &delete_pending_title);
linked_list_add(items, &delete_all_pending_titles);
}
}
@ -85,7 +77,7 @@ static void pendingtitles_draw_top(ui_view* view, void* data, float x1, float y1
}
}
static void pendingtitles_update(ui_view* view, void* data, list_item** items, u32** itemCount, list_item* selected, bool selectedTouched) {
static void pendingtitles_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
pendingtitles_data* listData = (pendingtitles_data*) data;
if(hidKeysDown() & KEY_B) {
@ -99,9 +91,10 @@ static void pendingtitles_update(ui_view* view, void* data, list_item** items, u
}
ui_pop();
task_clear_pending_titles(items);
list_destroy(view);
task_clear_pending_titles(listData->items, &listData->count);
free(listData);
return;
}
@ -116,7 +109,7 @@ static void pendingtitles_update(ui_view* view, void* data, list_item** items, u
listData->cancelEvent = 0;
}
listData->cancelEvent = task_populate_pending_titles(listData->items, &listData->count, PENDINGTITLES_MAX);
listData->cancelEvent = task_populate_pending_titles(items);
listData->populated = true;
}
@ -124,11 +117,6 @@ static void pendingtitles_update(ui_view* view, void* data, list_item** items, u
pendingtitles_action_open((pending_title_info*) selected->data, &listData->populated);
return;
}
if(*itemCount != &listData->count || *items != listData->items) {
*itemCount = &listData->count;
*items = listData->items;
}
}
void pendingtitles_open() {

View File

@ -2,7 +2,7 @@
#include "../ui.h"
void dump_nand();
void dumpnand_open();
void extsavedata_open();
void files_open(FS_Archive archive);
void files_open_sd();

View File

@ -6,25 +6,17 @@
#include "action/action.h"
#include "section.h"
#include "../error.h"
#include "../list.h"
#include "../../screen.h"
#define SYSTEMSAVEDATA_MAX 512
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};
typedef struct {
list_item items[SYSTEMSAVEDATA_MAX];
u32 count;
Handle cancelEvent;
bool populated;
} systemsavedata_data;
#define SYSTEMSAVEDATA_ACTION_COUNT 2
static u32 systemsavedata_action_count = SYSTEMSAVEDATA_ACTION_COUNT;
static list_item systemsavedata_action_items[SYSTEMSAVEDATA_ACTION_COUNT] = {
{"Browse Save Data", COLOR_TEXT, action_browse_system_save_data},
{"Delete Save Data", COLOR_TEXT, action_delete_system_save_data},
};
typedef struct {
system_save_data_info* info;
bool* populated;
@ -34,7 +26,7 @@ static void systemsavedata_action_draw_top(ui_view* view, void* data, float x1,
ui_draw_system_save_data_info(view, ((systemsavedata_action_data*) data)->info, x1, y1, x2, y2);
}
static void systemsavedata_action_update(ui_view* view, void* data, list_item** items, u32** itemCount, list_item* selected, bool selectedTouched) {
static void systemsavedata_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
systemsavedata_action_data* actionData = (systemsavedata_action_data*) data;
if(hidKeysDown() & KEY_B) {
@ -59,9 +51,9 @@ static void systemsavedata_action_update(ui_view* view, void* data, list_item**
return;
}
if(*itemCount != &systemsavedata_action_count || *items != systemsavedata_action_items) {
*itemCount = &systemsavedata_action_count;
*items = systemsavedata_action_items;
if(linked_list_size(items) == 0) {
linked_list_add(items, &browse_save_data);
linked_list_add(items, &delete_save_data);
}
}
@ -85,7 +77,7 @@ static void systemsavedata_draw_top(ui_view* view, void* data, float x1, float y
}
}
static void systemsavedata_update(ui_view* view, void* data, list_item** items, u32** itemCount, list_item* selected, bool selectedTouched) {
static void systemsavedata_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
systemsavedata_data* listData = (systemsavedata_data*) data;
if(hidKeysDown() & KEY_B) {
@ -99,9 +91,10 @@ static void systemsavedata_update(ui_view* view, void* data, list_item** items,
}
ui_pop();
task_clear_system_save_data(items);
list_destroy(view);
task_clear_system_save_data(listData->items, &listData->count);
free(listData);
return;
}
@ -116,7 +109,7 @@ static void systemsavedata_update(ui_view* view, void* data, list_item** items,
listData->cancelEvent = 0;
}
listData->cancelEvent = task_populate_system_save_data(listData->items, &listData->count, SYSTEMSAVEDATA_MAX);
listData->cancelEvent = task_populate_system_save_data(items);
listData->populated = true;
}
@ -124,11 +117,6 @@ static void systemsavedata_update(ui_view* view, void* data, list_item** items,
systemsavedata_action_open((system_save_data_info*) selected->data, &listData->populated);
return;
}
if(*itemCount != &listData->count || *items != listData->items) {
*itemCount = &listData->count;
*items = listData->items;
}
}
void systemsavedata_open() {

View File

@ -12,10 +12,10 @@
#include "../../../util.h"
#include "task.h"
#define MAX_EXT_SAVE_DATA 512
typedef struct {
list_item* items;
u32* count;
u32 max;
linked_list* items;
Handle cancelEvent;
} populate_ext_save_data_data;
@ -24,69 +24,74 @@ static Result task_populate_ext_save_data_from(populate_ext_save_data_data* data
Result res = 0;
u32 extSaveDataCount = 0;
u64* extSaveDataIds = (u64*) calloc(data->max, sizeof(u64));
u64* extSaveDataIds = (u64*) calloc(MAX_EXT_SAVE_DATA, sizeof(u64));
if(extSaveDataIds != NULL) {
if(R_SUCCEEDED(res = FSUSER_EnumerateExtSaveData(&extSaveDataCount, data->max, mediaType, 8, mediaType == MEDIATYPE_NAND, (u8*) extSaveDataIds))) {
if(R_SUCCEEDED(res = FSUSER_EnumerateExtSaveData(&extSaveDataCount, MAX_EXT_SAVE_DATA, mediaType, 8, mediaType == MEDIATYPE_NAND, (u8*) extSaveDataIds))) {
qsort(extSaveDataIds, extSaveDataCount, sizeof(u64), util_compare_u64);
SMDH smdh;
for(u32 i = 0; i < extSaveDataCount && *data->count < data->max && R_SUCCEEDED(res); i++) {
for(u32 i = 0; i < extSaveDataCount && R_SUCCEEDED(res); i++) {
if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) {
break;
}
ext_save_data_info* extSaveDataInfo = (ext_save_data_info*) calloc(1, sizeof(ext_save_data_info));
if(extSaveDataInfo != NULL) {
extSaveDataInfo->mediaType = mediaType;
extSaveDataInfo->extSaveDataId = extSaveDataIds[i];
extSaveDataInfo->shared = mediaType == MEDIATYPE_NAND;
extSaveDataInfo->hasMeta = false;
list_item* item = (list_item*) calloc(1, sizeof(list_item));
if(item != NULL) {
ext_save_data_info* extSaveDataInfo = (ext_save_data_info*) calloc(1, sizeof(ext_save_data_info));
if(extSaveDataInfo != NULL) {
extSaveDataInfo->mediaType = mediaType;
extSaveDataInfo->extSaveDataId = extSaveDataIds[i];
extSaveDataInfo->shared = mediaType == MEDIATYPE_NAND;
extSaveDataInfo->hasMeta = false;
list_item* item = &data->items[*data->count];
FS_ExtSaveDataInfo info = {.mediaType = mediaType, .saveId = extSaveDataIds[i]};
u32 smdhBytesRead = 0;
if(R_SUCCEEDED(FSUSER_ReadExtSaveDataIcon(&smdhBytesRead, info, sizeof(SMDH), (u8*) &smdh)) && smdhBytesRead == sizeof(SMDH)) {
u8 systemLanguage = CFG_LANGUAGE_EN;
CFGU_GetSystemLanguage(&systemLanguage);
FS_ExtSaveDataInfo info = {.mediaType = mediaType, .saveId = extSaveDataIds[i]};
u32 smdhBytesRead = 0;
if(R_SUCCEEDED(FSUSER_ReadExtSaveDataIcon(&smdhBytesRead, info, sizeof(SMDH), (u8*) &smdh)) && smdhBytesRead == sizeof(SMDH)) {
u8 systemLanguage = CFG_LANGUAGE_EN;
CFGU_GetSystemLanguage(&systemLanguage);
utf16_to_utf8((uint8_t*) item->name, smdh.titles[systemLanguage].shortDescription, NAME_MAX - 1);
utf16_to_utf8((uint8_t*) item->name, smdh.titles[systemLanguage].shortDescription, NAME_MAX - 1);
extSaveDataInfo->hasMeta = true;
utf16_to_utf8((uint8_t*) extSaveDataInfo->meta.shortDescription, smdh.titles[systemLanguage].shortDescription, sizeof(extSaveDataInfo->meta.shortDescription) - 1);
utf16_to_utf8((uint8_t*) extSaveDataInfo->meta.longDescription, smdh.titles[systemLanguage].longDescription, sizeof(extSaveDataInfo->meta.longDescription) - 1);
utf16_to_utf8((uint8_t*) extSaveDataInfo->meta.publisher, smdh.titles[systemLanguage].publisher, sizeof(extSaveDataInfo->meta.publisher) - 1);
extSaveDataInfo->meta.texture = screen_load_texture_tiled_auto(smdh.largeIcon, sizeof(smdh.largeIcon), 48, 48, GPU_RGB565, false);
}
bool empty = strlen(item->name) == 0;
if(!empty) {
empty = true;
char* curr = item->name;
while(*curr) {
if(*curr != ' ') {
empty = false;
break;
}
curr++;
extSaveDataInfo->hasMeta = true;
utf16_to_utf8((uint8_t*) extSaveDataInfo->meta.shortDescription, smdh.titles[systemLanguage].shortDescription, sizeof(extSaveDataInfo->meta.shortDescription) - 1);
utf16_to_utf8((uint8_t*) extSaveDataInfo->meta.longDescription, smdh.titles[systemLanguage].longDescription, sizeof(extSaveDataInfo->meta.longDescription) - 1);
utf16_to_utf8((uint8_t*) extSaveDataInfo->meta.publisher, smdh.titles[systemLanguage].publisher, sizeof(extSaveDataInfo->meta.publisher) - 1);
extSaveDataInfo->meta.texture = screen_load_texture_tiled_auto(smdh.largeIcon, sizeof(smdh.largeIcon), 48, 48, GPU_RGB565, false);
}
bool empty = strlen(item->name) == 0;
if(!empty) {
empty = true;
char* curr = item->name;
while(*curr) {
if(*curr != ' ') {
empty = false;
break;
}
curr++;
}
}
if(empty) {
snprintf(item->name, NAME_MAX, "%016llX", extSaveDataIds[i]);
}
if(mediaType == MEDIATYPE_NAND) {
item->color = COLOR_NAND;
} else if(mediaType == MEDIATYPE_SD) {
item->color = COLOR_SD;
}
item->data = extSaveDataInfo;
linked_list_add(data->items, item);
} else {
free(item);
res = R_FBI_OUT_OF_MEMORY;
}
if(empty) {
snprintf(item->name, NAME_MAX, "%016llX", extSaveDataIds[i]);
}
if(mediaType == MEDIATYPE_NAND) {
item->rgba = COLOR_NAND;
} else if(mediaType == MEDIATYPE_SD) {
item->rgba = COLOR_SD;
}
item->data = extSaveDataInfo;
(*data->count)++;
} else {
res = R_FBI_OUT_OF_MEMORY;
}
@ -113,36 +118,38 @@ static void task_populate_ext_save_data_thread(void* arg) {
free(data);
}
void task_clear_ext_save_data(list_item* items, u32* count) {
if(items == NULL || count == NULL || *count == 0) {
void task_clear_ext_save_data(linked_list* items) {
if(items == NULL) {
return;
}
u32 prevCount = *count;
*count = 0;
linked_list_iter iter;
linked_list_iterate(items, &iter);
for(u32 i = 0; i < prevCount; i++) {
if(items[i].data != NULL) {
ext_save_data_info* extSaveDataInfo = (ext_save_data_info*) items[i].data;
while(linked_list_iter_has_next(&iter)) {
list_item* item = (list_item*) linked_list_iter_next(&iter);
if(item->data != NULL) {
ext_save_data_info* extSaveDataInfo = (ext_save_data_info*) item->data;
if(extSaveDataInfo->hasMeta) {
screen_unload_texture(extSaveDataInfo->meta.texture);
}
free(items[i].data);
items[i].data = NULL;
free(item->data);
}
memset(items[i].name, '\0', NAME_MAX);
items[i].rgba = 0;
free(item);
linked_list_iter_remove(&iter);
}
}
Handle task_populate_ext_save_data(list_item* items, u32* count, u32 max) {
if(items == NULL || count == NULL || max == 0) {
Handle task_populate_ext_save_data(linked_list* items) {
if(items == NULL) {
return 0;
}
task_clear_ext_save_data(items, count);
task_clear_ext_save_data(items);
populate_ext_save_data_data* data = (populate_ext_save_data_data*) calloc(1, sizeof(populate_ext_save_data_data));
if(data == NULL) {
@ -152,8 +159,6 @@ Handle task_populate_ext_save_data(list_item* items, u32* count, u32 max) {
}
data->items = items;
data->count = count;
data->max = max;
Result eventRes = svcCreateEvent(&data->cancelEvent, 1);
if(R_FAILED(eventRes)) {

View File

@ -12,14 +12,13 @@
#include "../../../screen.h"
#include "task.h"
#define MAX_FILES 1024
typedef struct {
list_item* items;
u32* count;
u32 max;
linked_list* items;
file_info* dir;
Handle cancelEvent;
file_info* dir;
} populate_files_data;
static void task_populate_files_thread(void* arg) {
@ -34,13 +33,13 @@ static void task_populate_files_thread(void* arg) {
Handle dirHandle = 0;
if(R_SUCCEEDED(res = FSUSER_OpenDirectory(&dirHandle, *data->dir->archive, *fsPath))) {
u32 entryCount = 0;
FS_DirectoryEntry* entries = (FS_DirectoryEntry*) calloc(data->max, sizeof(FS_DirectoryEntry));
FS_DirectoryEntry* entries = (FS_DirectoryEntry*) calloc(MAX_FILES, sizeof(FS_DirectoryEntry));
if(entries != NULL) {
if(R_SUCCEEDED(res = FSDIR_Read(dirHandle, &entryCount, data->max, entries)) && entryCount > 0) {
if(R_SUCCEEDED(res = FSDIR_Read(dirHandle, &entryCount, MAX_FILES, entries)) && entryCount > 0) {
qsort(entries, entryCount, sizeof(FS_DirectoryEntry), util_compare_directory_entries);
SMDH smdh;
for(u32 i = 0; i < entryCount && *data->count < data->max && R_SUCCEEDED(res); i++) {
for(u32 i = 0; i < entryCount && R_SUCCEEDED(res); i++) {
if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) {
break;
}
@ -49,91 +48,96 @@ static void task_populate_files_thread(void* arg) {
continue;
}
file_info* fileInfo = (file_info*) calloc(1, sizeof(file_info));
if(fileInfo != NULL) {
fileInfo->archive = data->dir->archive;
utf16_to_utf8((uint8_t*) fileInfo->name, entries[i].name, NAME_MAX - 1);
fileInfo->containsCias = false;
fileInfo->size = 0;
fileInfo->isCia = false;
list_item* item = (list_item*) calloc(1, sizeof(list_item));
if(item != NULL) {
file_info* fileInfo = (file_info*) calloc(1, sizeof(file_info));
if(fileInfo != NULL) {
fileInfo->archive = data->dir->archive;
utf16_to_utf8((uint8_t*) fileInfo->name, entries[i].name, NAME_MAX - 1);
fileInfo->containsCias = false;
fileInfo->size = 0;
fileInfo->isCia = false;
list_item* item = &data->items[*data->count];
if(entries[i].attributes & FS_ATTRIBUTE_DIRECTORY) {
item->color = COLOR_DIRECTORY;
if(entries[i].attributes & FS_ATTRIBUTE_DIRECTORY) {
item->rgba = COLOR_DIRECTORY;
snprintf(fileInfo->path, PATH_MAX, "%s%s/", data->dir->path, fileInfo->name);
fileInfo->isDirectory = true;
} else {
item->color = COLOR_TEXT;
snprintf(fileInfo->path, PATH_MAX, "%s%s/", data->dir->path, fileInfo->name);
fileInfo->isDirectory = true;
} else {
item->rgba = COLOR_TEXT;
snprintf(fileInfo->path, PATH_MAX, "%s%s", data->dir->path, fileInfo->name);
fileInfo->isDirectory = false;
snprintf(fileInfo->path, PATH_MAX, "%s%s", data->dir->path, fileInfo->name);
fileInfo->isDirectory = false;
FS_Path* fileFsPath = util_make_path_utf8(fileInfo->path);
if(fileFsPath != NULL) {
Handle fileHandle;
if(R_SUCCEEDED(FSUSER_OpenFile(&fileHandle, *data->dir->archive, *fileFsPath, FS_OPEN_READ, 0))) {
FSFILE_GetSize(fileHandle, &fileInfo->size);
FS_Path* fileFsPath = util_make_path_utf8(fileInfo->path);
if(fileFsPath != NULL) {
Handle fileHandle;
if(R_SUCCEEDED(FSUSER_OpenFile(&fileHandle, *data->dir->archive, *fileFsPath, FS_OPEN_READ, 0))) {
FSFILE_GetSize(fileHandle, &fileInfo->size);
size_t len = strlen(fileInfo->path);
if(len > 4) {
if(strcasecmp(&fileInfo->path[len - 4], ".cia") == 0) {
AM_TitleEntry titleEntry;
if(R_SUCCEEDED(AM_GetCiaFileInfo(MEDIATYPE_SD, &titleEntry, fileHandle))) {
data->dir->containsCias = true;
size_t len = strlen(fileInfo->path);
if(len > 4) {
if(strcasecmp(&fileInfo->path[len - 4], ".cia") == 0) {
AM_TitleEntry titleEntry;
if(R_SUCCEEDED(AM_GetCiaFileInfo(MEDIATYPE_SD, &titleEntry, fileHandle))) {
data->dir->containsCias = true;
fileInfo->isCia = true;
fileInfo->ciaInfo.titleId = titleEntry.titleID;
fileInfo->ciaInfo.version = titleEntry.version;
fileInfo->ciaInfo.installedSize = titleEntry.size;
fileInfo->ciaInfo.hasMeta = false;
if(((titleEntry.titleID >> 32) & 0x8010) != 0 && R_SUCCEEDED(AM_GetCiaFileInfo(MEDIATYPE_NAND, &titleEntry, fileHandle))) {
fileInfo->isCia = true;
fileInfo->ciaInfo.titleId = titleEntry.titleID;
fileInfo->ciaInfo.version = titleEntry.version;
fileInfo->ciaInfo.installedSize = titleEntry.size;
fileInfo->ciaInfo.hasMeta = false;
if(((titleEntry.titleID >> 32) & 0x8010) != 0 && R_SUCCEEDED(AM_GetCiaFileInfo(MEDIATYPE_NAND, &titleEntry, fileHandle))) {
fileInfo->ciaInfo.installedSize = titleEntry.size;
}
if(R_SUCCEEDED(AM_GetCiaIcon(&smdh, fileHandle))) {
u8 systemLanguage = CFG_LANGUAGE_EN;
CFGU_GetSystemLanguage(&systemLanguage);
fileInfo->ciaInfo.hasMeta = true;
utf16_to_utf8((uint8_t*) fileInfo->ciaInfo.meta.shortDescription, smdh.titles[systemLanguage].shortDescription, sizeof(fileInfo->ciaInfo.meta.shortDescription) - 1);
utf16_to_utf8((uint8_t*) fileInfo->ciaInfo.meta.longDescription, smdh.titles[systemLanguage].longDescription, sizeof(fileInfo->ciaInfo.meta.longDescription) - 1);
utf16_to_utf8((uint8_t*) fileInfo->ciaInfo.meta.publisher, smdh.titles[systemLanguage].publisher, sizeof(fileInfo->ciaInfo.meta.publisher) - 1);
fileInfo->ciaInfo.meta.texture = screen_load_texture_tiled_auto(smdh.largeIcon, sizeof(smdh.largeIcon), 48, 48, GPU_RGB565, false);
}
}
} else if(strcasecmp(&fileInfo->path[len - 4], ".tik") == 0) {
u32 bytesRead = 0;
if(R_SUCCEEDED(AM_GetCiaIcon(&smdh, fileHandle))) {
u8 systemLanguage = CFG_LANGUAGE_EN;
CFGU_GetSystemLanguage(&systemLanguage);
u8 sigType = 0;
if(R_SUCCEEDED(FSFILE_Read(fileHandle, &bytesRead, 3, &sigType, sizeof(sigType))) && bytesRead == sizeof(sigType) && sigType <= 5) {
static u32 dataOffsets[6] = {0x240, 0x140, 0x80, 0x240, 0x140, 0x80};
static u32 titleIdOffset = 0x9C;
fileInfo->ciaInfo.hasMeta = true;
utf16_to_utf8((uint8_t*) fileInfo->ciaInfo.meta.shortDescription, smdh.titles[systemLanguage].shortDescription, sizeof(fileInfo->ciaInfo.meta.shortDescription) - 1);
utf16_to_utf8((uint8_t*) fileInfo->ciaInfo.meta.longDescription, smdh.titles[systemLanguage].longDescription, sizeof(fileInfo->ciaInfo.meta.longDescription) - 1);
utf16_to_utf8((uint8_t*) fileInfo->ciaInfo.meta.publisher, smdh.titles[systemLanguage].publisher, sizeof(fileInfo->ciaInfo.meta.publisher) - 1);
fileInfo->ciaInfo.meta.texture = screen_load_texture_tiled_auto(smdh.largeIcon, sizeof(smdh.largeIcon), 48, 48, GPU_RGB565, false);
}
}
} else if(strcasecmp(&fileInfo->path[len - 4], ".tik") == 0) {
u32 bytesRead = 0;
u64 titleId = 0;
if(R_SUCCEEDED(FSFILE_Read(fileHandle, &bytesRead, dataOffsets[sigType] + titleIdOffset, &titleId, sizeof(titleId))) && bytesRead == sizeof(titleId)) {
data->dir->containsTickets = true;
u8 sigType = 0;
if(R_SUCCEEDED(FSFILE_Read(fileHandle, &bytesRead, 3, &sigType, sizeof(sigType))) && bytesRead == sizeof(sigType) && sigType <= 5) {
static u32 dataOffsets[6] = {0x240, 0x140, 0x80, 0x240, 0x140, 0x80};
static u32 titleIdOffset = 0x9C;
u64 titleId = 0;
if(R_SUCCEEDED(FSFILE_Read(fileHandle, &bytesRead, dataOffsets[sigType] + titleIdOffset, &titleId, sizeof(titleId))) && bytesRead == sizeof(titleId)) {
data->dir->containsTickets = true;
fileInfo->isTicket = true;
fileInfo->ticketInfo.titleId = __builtin_bswap64(titleId);
fileInfo->isTicket = true;
fileInfo->ticketInfo.titleId = __builtin_bswap64(titleId);
}
}
}
}
FSFILE_Close(fileHandle);
}
FSFILE_Close(fileHandle);
util_free_path_utf8(fileFsPath);
}
util_free_path_utf8(fileFsPath);
}
strncpy(item->name, fileInfo->name, NAME_MAX);
item->data = fileInfo;
linked_list_add(data->items, item);
} else {
free(item);
res = R_FBI_OUT_OF_MEMORY;
}
strncpy(item->name, fileInfo->name, NAME_MAX);
item->data = fileInfo;
(*data->count)++;
} else {
res = R_FBI_OUT_OF_MEMORY;
}
@ -161,36 +165,38 @@ static void task_populate_files_thread(void* arg) {
free(data);
}
void task_clear_files(list_item* items, u32* count) {
if(items == NULL || count == NULL) {
void task_clear_files(linked_list* items) {
if(items == NULL) {
return;
}
u32 prevCount = *count;
*count = 0;
linked_list_iter iter;
linked_list_iterate(items, &iter);
for(u32 i = 0; i < prevCount; i++) {
if(items[i].data != NULL) {
file_info* fileInfo = (file_info*) items[i].data;
while(linked_list_iter_has_next(&iter)) {
list_item* item = (list_item*) linked_list_iter_next(&iter);
if(item->data != NULL) {
file_info* fileInfo = (file_info*) item->data;
if(fileInfo->isCia && fileInfo->ciaInfo.hasMeta) {
screen_unload_texture(fileInfo->ciaInfo.meta.texture);
}
free(items[i].data);
items[i].data = NULL;
free(item->data);
}
memset(items[i].name, '\0', NAME_MAX);
items[i].rgba = 0;
free(item);
linked_list_iter_remove(&iter);
}
}
Handle task_populate_files(list_item* items, u32* count, u32 max, file_info* dir) {
if(items == NULL || count == NULL || max == 0 || dir == NULL) {
Handle task_populate_files(linked_list* items, file_info* dir) {
if(items == NULL || dir == NULL) {
return 0;
}
task_clear_files(items, count);
task_clear_files(items);
populate_files_data* data = (populate_files_data*) calloc(1, sizeof(populate_files_data));
if(data == NULL) {
@ -200,8 +206,6 @@ Handle task_populate_files(list_item* items, u32* count, u32 max, file_info* dir
}
data->items = items;
data->count = count;
data->max = max;
data->dir = dir;
Result eventRes = svcCreateEvent(&data->cancelEvent, 1);

View File

@ -2,7 +2,6 @@
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <3ds.h>
@ -13,9 +12,7 @@
#include "task.h"
typedef struct {
list_item* items;
u32* count;
u32 max;
linked_list* items;
Handle cancelEvent;
} populate_pending_titles_data;
@ -33,28 +30,34 @@ static Result task_populate_pending_titles_from(populate_pending_titles_data* da
AM_PendingTitleEntry* pendingTitleInfos = (AM_PendingTitleEntry*) calloc(pendingTitleCount, sizeof(AM_PendingTitleEntry));
if(pendingTitleInfos != NULL) {
if(R_SUCCEEDED(res = AM_GetPendingTitleInfo(pendingTitleCount, mediaType, pendingTitleIds, pendingTitleInfos))) {
for(u32 i = 0; i < pendingTitleCount && *data->count < data->max && R_SUCCEEDED(res); i++) {
for(u32 i = 0; i < pendingTitleCount && R_SUCCEEDED(res); i++) {
if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) {
break;
}
pending_title_info* pendingTitleInfo = (pending_title_info*) calloc(1, sizeof(pending_title_info));
if(pendingTitleInfo != NULL) {
pendingTitleInfo->mediaType = mediaType;
pendingTitleInfo->titleId = pendingTitleIds[i];
pendingTitleInfo->version = pendingTitleInfos[i].version;
list_item* item = (list_item*) calloc(1, sizeof(list_item));
if(item != NULL) {
pending_title_info* pendingTitleInfo = (pending_title_info*) calloc(1, sizeof(pending_title_info));
if(pendingTitleInfo != NULL) {
pendingTitleInfo->mediaType = mediaType;
pendingTitleInfo->titleId = pendingTitleIds[i];
pendingTitleInfo->version = pendingTitleInfos[i].version;
list_item* item = &data->items[*data->count];
snprintf(item->name, NAME_MAX, "%016llX", pendingTitleIds[i]);
if(mediaType == MEDIATYPE_NAND) {
item->rgba = COLOR_NAND;
} else if(mediaType == MEDIATYPE_SD) {
item->rgba = COLOR_SD;
snprintf(item->name, NAME_MAX, "%016llX", pendingTitleIds[i]);
if(mediaType == MEDIATYPE_NAND) {
item->color = COLOR_NAND;
} else if(mediaType == MEDIATYPE_SD) {
item->color = COLOR_SD;
}
item->data = pendingTitleInfo;
linked_list_add(data->items, item);
} else {
free(item);
res = R_FBI_OUT_OF_MEMORY;
}
item->data = pendingTitleInfo;
(*data->count)++;
} else {
res = R_FBI_OUT_OF_MEMORY;
}
@ -88,31 +91,33 @@ static void task_populate_pending_titles_thread(void* arg) {
free(data);
}
void task_clear_pending_titles(list_item* items, u32* count) {
if(items == NULL || count == NULL) {
void task_clear_pending_titles(linked_list* items) {
if(items == NULL) {
return;
}
u32 prevCount = *count;
*count = 0;
linked_list_iter iter;
linked_list_iterate(items, &iter);
for(u32 i = 0; i < prevCount; i++) {
if(items[i].data != NULL) {
free(items[i].data);
items[i].data = NULL;
while(linked_list_iter_has_next(&iter)) {
list_item* item = (list_item*) linked_list_iter_next(&iter);
if(item->data != NULL) {
free(item->data);
}
memset(items[i].name, '\0', NAME_MAX);
items[i].rgba = 0;
free(item);
linked_list_iter_remove(&iter);
}
}
Handle task_populate_pending_titles(list_item* items, u32* count, u32 max) {
if(items == NULL || count == NULL || max == 0) {
Handle task_populate_pending_titles(linked_list* items) {
if(items == NULL) {
return 0;
}
task_clear_pending_titles(items, count);
task_clear_pending_titles(items);
populate_pending_titles_data* data = (populate_pending_titles_data*) calloc(1, sizeof(populate_pending_titles_data));
if(data == NULL) {
@ -122,8 +127,6 @@ Handle task_populate_pending_titles(list_item* items, u32* count, u32 max) {
}
data->items = items;
data->count = count;
data->max = max;
Result eventRes = svcCreateEvent(&data->cancelEvent, 1);
if(R_FAILED(eventRes)) {

View File

@ -12,10 +12,10 @@
#include "../../../util.h"
#include "task.h"
#define MAX_SYSTEM_SAVE_DATA 512
typedef struct {
list_item* items;
u32* count;
u32 max;
linked_list* items;
Handle cancelEvent;
} populate_system_save_data_data;
@ -26,26 +26,32 @@ static void task_populate_system_save_data_thread(void* arg) {
Result res = 0;
u32 systemSaveDataCount = 0;
u32* systemSaveDataIds = (u32*) calloc(data->max, sizeof(u32));
u32* systemSaveDataIds = (u32*) calloc(MAX_SYSTEM_SAVE_DATA, sizeof(u32));
if(systemSaveDataIds != NULL) {
if(R_SUCCEEDED(res = FSUSER_EnumerateSystemSaveData(&systemSaveDataCount, data->max * sizeof(u32), systemSaveDataIds))) {
if(R_SUCCEEDED(res = FSUSER_EnumerateSystemSaveData(&systemSaveDataCount, MAX_SYSTEM_SAVE_DATA * sizeof(u32), systemSaveDataIds))) {
qsort(systemSaveDataIds, systemSaveDataCount, sizeof(u32), util_compare_u32);
for(u32 i = 0; i < systemSaveDataCount && *data->count < data->max && R_SUCCEEDED(res); i++) {
for(u32 i = 0; i < systemSaveDataCount && R_SUCCEEDED(res); i++) {
if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) {
break;
}
system_save_data_info* systemSaveDataInfo = (system_save_data_info*) calloc(1, sizeof(system_save_data_info));
if(systemSaveDataInfo != NULL) {
systemSaveDataInfo->systemSaveDataId = systemSaveDataIds[i];
list_item* item = (list_item*) calloc(1, sizeof(list_item));
if(item != NULL) {
system_save_data_info* systemSaveDataInfo = (system_save_data_info*) calloc(1, sizeof(system_save_data_info));
if(systemSaveDataInfo != NULL) {
systemSaveDataInfo->systemSaveDataId = systemSaveDataIds[i];
list_item* item = &data->items[*data->count];
snprintf(item->name, NAME_MAX, "%08lX", systemSaveDataIds[i]);
item->rgba = COLOR_TEXT;
item->data = systemSaveDataInfo;
snprintf(item->name, NAME_MAX, "%08lX", systemSaveDataIds[i]);
item->color = COLOR_TEXT;
item->data = systemSaveDataInfo;
(*data->count)++;
linked_list_add(data->items, item);
} else {
free(item);
res = R_FBI_OUT_OF_MEMORY;
}
} else {
res = R_FBI_OUT_OF_MEMORY;
}
@ -65,31 +71,33 @@ static void task_populate_system_save_data_thread(void* arg) {
free(data);
}
void task_clear_system_save_data(list_item* items, u32* count) {
if(items == NULL || count == NULL) {
void task_clear_system_save_data(linked_list* items) {
if(items == NULL) {
return;
}
u32 prevCount = *count;
*count = 0;
linked_list_iter iter;
linked_list_iterate(items, &iter);
for(u32 i = 0; i < prevCount; i++) {
if(items[i].data != NULL) {
free(items[i].data);
items[i].data = NULL;
while(linked_list_iter_has_next(&iter)) {
list_item* item = (list_item*) linked_list_iter_next(&iter);
if(item->data != NULL) {
free(item->data);
}
memset(items[i].name, '\0', NAME_MAX);
items[i].rgba = 0;
free(item);
linked_list_iter_remove(&iter);
}
}
Handle task_populate_system_save_data(list_item* items, u32* count, u32 max) {
if(items == NULL || count == NULL || max == 0) {
Handle task_populate_system_save_data(linked_list* items) {
if(items == NULL) {
return 0;
}
task_clear_system_save_data(items, count);
task_clear_system_save_data(items);
populate_system_save_data_data* data = (populate_system_save_data_data*) calloc(1, sizeof(populate_system_save_data_data));
if(data == NULL) {
@ -99,8 +107,6 @@ Handle task_populate_system_save_data(list_item* items, u32* count, u32 max) {
}
data->items = items;
data->count = count;
data->max = max;
Result eventRes = svcCreateEvent(&data->cancelEvent, 1);
if(R_FAILED(eventRes)) {

View File

@ -13,9 +13,7 @@
#include "task.h"
typedef struct {
list_item* items;
u32* count;
u32 max;
linked_list* items;
Handle cancelEvent;
} populate_tickets_data;
@ -32,21 +30,27 @@ static void task_populate_tickets_thread(void* arg) {
if(R_SUCCEEDED(res = AM_GetTicketList(&ticketCount, ticketCount, 0, ticketIds))) {
qsort(ticketIds, ticketCount, sizeof(u64), util_compare_u64);
for(u32 i = 0; i < ticketCount && *data->count < data->max && R_SUCCEEDED(res); i++) {
for(u32 i = 0; i < ticketCount && R_SUCCEEDED(res); i++) {
if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) {
break;
}
ticket_info* ticketInfo = (ticket_info*) calloc(1, sizeof(ticket_info));
if(ticketInfo != NULL) {
ticketInfo->titleId = ticketIds[i];
list_item* item = (list_item*) calloc(1, sizeof(list_item));
if(item != NULL) {
ticket_info* ticketInfo = (ticket_info*) calloc(1, sizeof(ticket_info));
if(ticketInfo != NULL) {
ticketInfo->titleId = ticketIds[i];
list_item* item = &data->items[*data->count];
snprintf(item->name, NAME_MAX, "%016llX", ticketIds[i]);
item->rgba = COLOR_TEXT;
item->data = ticketInfo;
snprintf(item->name, NAME_MAX, "%016llX", ticketIds[i]);
item->color = COLOR_TEXT;
item->data = ticketInfo;
(*data->count)++;
linked_list_add(data->items, item);
} else {
free(item);
res = R_FBI_OUT_OF_MEMORY;
}
} else {
res = R_FBI_OUT_OF_MEMORY;
}
@ -67,31 +71,33 @@ static void task_populate_tickets_thread(void* arg) {
free(data);
}
void task_clear_tickets(list_item* items, u32* count) {
if(items == NULL || count == NULL) {
void task_clear_tickets(linked_list* items) {
if(items == NULL) {
return;
}
u32 prevCount = *count;
*count = 0;
linked_list_iter iter;
linked_list_iterate(items, &iter);
for(u32 i = 0; i < prevCount; i++) {
if(items[i].data != NULL) {
free(items[i].data);
items[i].data = NULL;
while(linked_list_iter_has_next(&iter)) {
list_item* item = (list_item*) linked_list_iter_next(&iter);
if(item->data != NULL) {
free(item->data);
}
memset(items[i].name, '\0', NAME_MAX);
items[i].rgba = 0;
free(item);
linked_list_iter_remove(&iter);
}
}
Handle task_populate_tickets(list_item* items, u32* count, u32 max) {
if(items == NULL || count == NULL || max == 0) {
Handle task_populate_tickets(linked_list* items) {
if(items == NULL) {
return 0;
}
task_clear_tickets(items, count);
task_clear_tickets(items);
populate_tickets_data* data = (populate_tickets_data*) calloc(1, sizeof(populate_tickets_data));
if(data == NULL) {
@ -101,8 +107,6 @@ Handle task_populate_tickets(list_item* items, u32* count, u32 max) {
}
data->items = items;
data->count = count;
data->max = max;
Result eventRes = svcCreateEvent(&data->cancelEvent, 1);
if(R_FAILED(eventRes)) {

View File

@ -14,9 +14,7 @@
#include "task.h"
typedef struct {
list_item* items;
u32* count;
u32 max;
linked_list* items;
Handle cancelEvent;
} populate_titles_data;
@ -26,80 +24,85 @@ static Result task_populate_titles_add_ctr(populate_titles_data* data, FS_MediaT
AM_TitleEntry entry;
if(R_SUCCEEDED(res = AM_GetTitleInfo(mediaType, 1, &titleId, &entry))) {
title_info* titleInfo = (title_info*) calloc(1, sizeof(title_info));
if(titleInfo != NULL) {
titleInfo->mediaType = mediaType;
titleInfo->titleId = titleId;
AM_GetTitleProductCode(mediaType, titleId, titleInfo->productCode);
titleInfo->version = entry.version;
titleInfo->installedSize = entry.size;
titleInfo->twl = false;
titleInfo->hasMeta = false;
list_item* item = (list_item*) calloc(1, sizeof(list_item));
if(item != NULL) {
title_info* titleInfo = (title_info*) calloc(1, sizeof(title_info));
if(titleInfo != NULL) {
titleInfo->mediaType = mediaType;
titleInfo->titleId = titleId;
AM_GetTitleProductCode(mediaType, titleId, titleInfo->productCode);
titleInfo->version = entry.version;
titleInfo->installedSize = entry.size;
titleInfo->twl = false;
titleInfo->hasMeta = false;
list_item* item = &data->items[*data->count];
static const u32 filePathData[] = {0x00000000, 0x00000000, 0x00000002, 0x6E6F6369, 0x00000000};
static const FS_Path filePath = (FS_Path) {PATH_BINARY, 0x14, (u8*) filePathData};
u32 archivePath[] = {(u32) (titleId & 0xFFFFFFFF), (u32) ((titleId >> 32) & 0xFFFFFFFF), mediaType, 0x00000000};
FS_Archive archive = {ARCHIVE_SAVEDATA_AND_CONTENT, (FS_Path) {PATH_BINARY, 0x10, (u8*) archivePath}};
static const u32 filePathData[] = {0x00000000, 0x00000000, 0x00000002, 0x6E6F6369, 0x00000000};
static const FS_Path filePath = (FS_Path) {PATH_BINARY, 0x14, (u8*) filePathData};
u32 archivePath[] = {(u32) (titleId & 0xFFFFFFFF), (u32) ((titleId >> 32) & 0xFFFFFFFF), mediaType, 0x00000000};
FS_Archive archive = {ARCHIVE_SAVEDATA_AND_CONTENT, (FS_Path) {PATH_BINARY, 0x10, (u8*) archivePath}};
Handle fileHandle;
if(R_SUCCEEDED(FSUSER_OpenFileDirectly(&fileHandle, archive, filePath, FS_OPEN_READ, 0))) {
SMDH* smdh = (SMDH*) calloc(1, sizeof(SMDH));
if(smdh != NULL) {
u32 bytesRead;
if(R_SUCCEEDED(FSFILE_Read(fileHandle, &bytesRead, 0, smdh, sizeof(SMDH))) && bytesRead == sizeof(SMDH)) {
if(smdh->magic[0] == 'S' && smdh->magic[1] == 'M' && smdh->magic[2] == 'D' && smdh->magic[3] == 'H') {
titleInfo->hasMeta = true;
Handle fileHandle;
if(R_SUCCEEDED(FSUSER_OpenFileDirectly(&fileHandle, archive, filePath, FS_OPEN_READ, 0))) {
SMDH* smdh = (SMDH*) calloc(1, sizeof(SMDH));
if(smdh != NULL) {
u32 bytesRead;
if(R_SUCCEEDED(FSFILE_Read(fileHandle, &bytesRead, 0, smdh, sizeof(SMDH))) && bytesRead == sizeof(SMDH)) {
if(smdh->magic[0] == 'S' && smdh->magic[1] == 'M' && smdh->magic[2] == 'D' && smdh->magic[3] == 'H') {
titleInfo->hasMeta = true;
u8 systemLanguage = CFG_LANGUAGE_EN;
CFGU_GetSystemLanguage(&systemLanguage);
u8 systemLanguage = CFG_LANGUAGE_EN;
CFGU_GetSystemLanguage(&systemLanguage);
utf16_to_utf8((uint8_t*) item->name, smdh->titles[systemLanguage].shortDescription, NAME_MAX - 1);
utf16_to_utf8((uint8_t*) item->name, smdh->titles[systemLanguage].shortDescription, NAME_MAX - 1);
utf16_to_utf8((uint8_t*) titleInfo->meta.shortDescription, smdh->titles[systemLanguage].shortDescription, sizeof(titleInfo->meta.shortDescription) - 1);
utf16_to_utf8((uint8_t*) titleInfo->meta.longDescription, smdh->titles[systemLanguage].longDescription, sizeof(titleInfo->meta.longDescription) - 1);
utf16_to_utf8((uint8_t*) titleInfo->meta.publisher, smdh->titles[systemLanguage].publisher, sizeof(titleInfo->meta.publisher) - 1);
titleInfo->meta.texture = screen_load_texture_tiled_auto(smdh->largeIcon, sizeof(smdh->largeIcon), 48, 48, GPU_RGB565, false);
utf16_to_utf8((uint8_t*) titleInfo->meta.shortDescription, smdh->titles[systemLanguage].shortDescription, sizeof(titleInfo->meta.shortDescription) - 1);
utf16_to_utf8((uint8_t*) titleInfo->meta.longDescription, smdh->titles[systemLanguage].longDescription, sizeof(titleInfo->meta.longDescription) - 1);
utf16_to_utf8((uint8_t*) titleInfo->meta.publisher, smdh->titles[systemLanguage].publisher, sizeof(titleInfo->meta.publisher) - 1);
titleInfo->meta.texture = screen_load_texture_tiled_auto(smdh->largeIcon, sizeof(smdh->largeIcon), 48, 48, GPU_RGB565, false);
}
}
free(smdh);
}
free(smdh);
FSFILE_Close(fileHandle);
}
FSFILE_Close(fileHandle);
}
bool empty = strlen(item->name) == 0;
if(!empty) {
empty = true;
bool empty = strlen(item->name) == 0;
if(!empty) {
empty = true;
char* curr = item->name;
while(*curr) {
if(*curr != ' ') {
empty = false;
break;
}
char* curr = item->name;
while(*curr) {
if(*curr != ' ') {
empty = false;
break;
curr++;
}
curr++;
}
if(empty) {
snprintf(item->name, NAME_MAX, "%016llX", titleId);
}
if(mediaType == MEDIATYPE_NAND) {
item->color = COLOR_NAND;
} else if(mediaType == MEDIATYPE_SD) {
item->color = COLOR_SD;
} else if(mediaType == MEDIATYPE_GAME_CARD) {
item->color = COLOR_GAME_CARD;
}
item->data = titleInfo;
linked_list_add(data->items, item);
} else {
free(item);
res = R_FBI_OUT_OF_MEMORY;
}
if(empty) {
snprintf(item->name, NAME_MAX, "%016llX", titleId);
}
if(mediaType == MEDIATYPE_NAND) {
item->rgba = COLOR_NAND;
} else if(mediaType == MEDIATYPE_SD) {
item->rgba = COLOR_SD;
} else if(mediaType == MEDIATYPE_GAME_CARD) {
item->rgba = COLOR_GAME_CARD;
}
item->data = titleInfo;
(*data->count)++;
} else {
res = R_FBI_OUT_OF_MEMORY;
}
@ -139,100 +142,105 @@ static Result task_populate_titles_add_twl(populate_titles_data* data, FS_MediaT
}
if(R_SUCCEEDED(res)) {
title_info* titleInfo = (title_info*) calloc(1, sizeof(title_info));
if(titleInfo != NULL) {
titleInfo->mediaType = mediaType;
titleInfo->titleId = realTitleId;
strncpy(titleInfo->productCode, productCode, 12);
titleInfo->version = version;
titleInfo->installedSize = installedSize;
titleInfo->twl = true;
titleInfo->hasMeta = false;
list_item* item = (list_item*) calloc(1, sizeof(list_item));
if(item != NULL) {
title_info* titleInfo = (title_info*) calloc(1, sizeof(title_info));
if(titleInfo != NULL) {
titleInfo->mediaType = mediaType;
titleInfo->titleId = realTitleId;
strncpy(titleInfo->productCode, productCode, 12);
titleInfo->version = version;
titleInfo->installedSize = installedSize;
titleInfo->twl = true;
titleInfo->hasMeta = false;
list_item* item = &data->items[*data->count];
BNR* bnr = (BNR*) calloc(1, sizeof(BNR));
if(bnr != NULL) {
if(R_SUCCEEDED(FSUSER_GetLegacyBannerData(mediaType, titleId, (u8*) bnr))) {
titleInfo->hasMeta = true;
BNR* bnr = (BNR*) calloc(1, sizeof(BNR));
if(bnr != NULL) {
if(R_SUCCEEDED(FSUSER_GetLegacyBannerData(mediaType, titleId, (u8*) bnr))) {
titleInfo->hasMeta = true;
u8 systemLanguage = CFG_LANGUAGE_EN;
CFGU_GetSystemLanguage(&systemLanguage);
u8 systemLanguage = CFG_LANGUAGE_EN;
CFGU_GetSystemLanguage(&systemLanguage);
char title[0x100] = {'\0'};
utf16_to_utf8((uint8_t*) title, bnr->titles[systemLanguage], sizeof(title) - 1);
char title[0x100] = {'\0'};
utf16_to_utf8((uint8_t*) title, bnr->titles[systemLanguage], sizeof(title) - 1);
if(strchr(title, '\n') == NULL) {
size_t len = strlen(title);
strncpy(item->name, title, len);
strncpy(titleInfo->meta.shortDescription, title, len);
} else {
char* destinations[] = {titleInfo->meta.shortDescription, titleInfo->meta.longDescription, titleInfo->meta.publisher};
int currDest = 0;
if(strchr(title, '\n') == NULL) {
size_t len = strlen(title);
strncpy(item->name, title, len);
strncpy(titleInfo->meta.shortDescription, title, len);
} else {
char* destinations[] = {titleInfo->meta.shortDescription, titleInfo->meta.longDescription, titleInfo->meta.publisher};
int currDest = 0;
char* last = title;
char* curr = NULL;
char* last = title;
char* curr = NULL;
while(currDest < 3 && (curr = strchr(last, '\n')) != NULL) {
strncpy(destinations[currDest++], last, curr - last);
last = curr + 1;
*curr = ' ';
}
while(currDest < 3 && (curr = strchr(last, '\n')) != NULL) {
strncpy(destinations[currDest++], last, curr - last);
last = curr + 1;
*curr = ' ';
strncpy(item->name, title, last - title);
if(currDest < 3) {
strncpy(destinations[currDest], last, strlen(title) - (last - title));
}
}
strncpy(item->name, title, last - title);
if(currDest < 3) {
strncpy(destinations[currDest], last, strlen(title) - (last - title));
u8 icon[32 * 32 * 2];
for(u32 x = 0; x < 32; x++) {
for(u32 y = 0; y < 32; y++) {
u32 srcPos = (((y >> 3) * 4 + (x >> 3)) * 8 + (y & 7)) * 4 + ((x & 7) >> 1);
u32 srcShift = (x & 1) * 4;
u16 srcPx = bnr->mainIconPalette[(bnr->mainIconBitmap[srcPos] >> srcShift) & 0xF];
u8 r = (u8) (srcPx & 0x1F);
u8 g = (u8) ((srcPx >> 5) & 0x1F);
u8 b = (u8) ((srcPx >> 10) & 0x1F);
u16 reversedPx = (u16) ((r << 11) | (g << 6) | (b << 1) | 1);
u32 dstPos = (y * 32 + x) * 2;
icon[dstPos + 0] = (u8) (reversedPx & 0xFF);
icon[dstPos + 1] = (u8) ((reversedPx >> 8) & 0xFF);
}
}
titleInfo->meta.texture = screen_load_texture_auto(icon, sizeof(icon), 32, 32, GPU_RGBA5551, false);
}
u8 icon[32 * 32 * 2];
for(u32 x = 0; x < 32; x++) {
for(u32 y = 0; y < 32; y++) {
u32 srcPos = (((y >> 3) * 4 + (x >> 3)) * 8 + (y & 7)) * 4 + ((x & 7) >> 1);
u32 srcShift = (x & 1) * 4;
u16 srcPx = bnr->mainIconPalette[(bnr->mainIconBitmap[srcPos] >> srcShift) & 0xF];
u8 r = (u8) (srcPx & 0x1F);
u8 g = (u8) ((srcPx >> 5) & 0x1F);
u8 b = (u8) ((srcPx >> 10) & 0x1F);
u16 reversedPx = (u16) ((r << 11) | (g << 6) | (b << 1) | 1);
u32 dstPos = (y * 32 + x) * 2;
icon[dstPos + 0] = (u8) (reversedPx & 0xFF);
icon[dstPos + 1] = (u8) ((reversedPx >> 8) & 0xFF);
}
}
titleInfo->meta.texture = screen_load_texture_auto(icon, sizeof(icon), 32, 32, GPU_RGBA5551, false);
free(bnr);
}
free(bnr);
}
bool empty = strlen(item->name) == 0;
if(!empty) {
empty = true;
bool empty = strlen(item->name) == 0;
if(!empty) {
empty = true;
char* curr = item->name;
while(*curr) {
if(*curr != ' ') {
empty = false;
break;
}
char* curr = item->name;
while(*curr) {
if(*curr != ' ') {
empty = false;
break;
curr++;
}
curr++;
}
if(empty) {
snprintf(item->name, NAME_MAX, "%016llX", realTitleId);
}
item->color = COLOR_DS_TITLE;
item->data = titleInfo;
linked_list_add(data->items, item);
} else {
free(item);
res = R_FBI_OUT_OF_MEMORY;
}
if(empty) {
snprintf(item->name, NAME_MAX, "%016llX", realTitleId);
}
item->rgba = COLOR_DS_TITLE;
item->data = titleInfo;
(*data->count)++;
} else {
res = R_FBI_OUT_OF_MEMORY;
}
@ -258,7 +266,7 @@ static Result task_populate_titles_from(populate_titles_data* data, FS_MediaType
if(R_SUCCEEDED(res = AM_GetTitleList(&titleCount, mediaType, titleCount, titleIds))) {
qsort(titleIds, titleCount, sizeof(u64), util_compare_u64);
for(u32 i = 0; i < titleCount && *data->count < data->max && R_SUCCEEDED(res); i++) {
for(u32 i = 0; i < titleCount && R_SUCCEEDED(res); i++) {
if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) {
break;
}
@ -296,36 +304,38 @@ static void task_populate_titles_thread(void* arg) {
free(data);
}
void task_clear_titles(list_item* items, u32* count) {
if(items == NULL || count == NULL) {
void task_clear_titles(linked_list* items) {
if(items == NULL) {
return;
}
u32 prevCount = *count;
*count = 0;
linked_list_iter iter;
linked_list_iterate(items, &iter);
for(u32 i = 0; i < prevCount; i++) {
if(items[i].data != NULL) {
title_info* titleInfo = (title_info*) items[i].data;
while(linked_list_iter_has_next(&iter)) {
list_item* item = (list_item*) linked_list_iter_next(&iter);
if(item->data != NULL) {
title_info* titleInfo = (title_info*) item->data;
if(titleInfo->hasMeta) {
screen_unload_texture(titleInfo->meta.texture);
}
free(items[i].data);
items[i].data = NULL;
free(item->data);
}
memset(items[i].name, '\0', NAME_MAX);
items[i].rgba = 0;
free(item);
linked_list_iter_remove(&iter);
}
}
Handle task_populate_titles(list_item* items, u32* count, u32 max) {
if(items == NULL || count == NULL || max == 0) {
Handle task_populate_titles(linked_list* items) {
if(items == NULL) {
return 0;
}
task_clear_titles(items, count);
task_clear_titles(items);
populate_titles_data* data = (populate_titles_data*) calloc(1, sizeof(populate_titles_data));
if(data == NULL) {
@ -335,8 +345,6 @@ Handle task_populate_titles(list_item* items, u32* count, u32 max) {
}
data->items = items;
data->count = count;
data->max = max;
Result eventRes = svcCreateEvent(&data->cancelEvent, 1);
if(R_FAILED(eventRes)) {

View File

@ -2,7 +2,14 @@
#include <sys/syslimits.h>
#include "../../list.h"
#include "../../../core/linkedlist.h"
#define R_FBI_CANCELLED MAKERESULT(RL_PERMANENT, RS_CANCELED, RM_APPLICATION, 1)
#define R_FBI_ERRNO MAKERESULT(RL_PERMANENT, RS_INTERNAL, RM_APPLICATION, 2)
#define R_FBI_HTTP_RESPONSE_CODE MAKERESULT(RL_PERMANENT, RS_INTERNAL, RM_APPLICATION, 3)
#define R_FBI_WRONG_SYSTEM MAKERESULT(RL_PERMANENT, RS_NOTSUPPORTED, RM_APPLICATION, 4)
#define R_FBI_OUT_OF_MEMORY MAKERESULT(RL_FATAL, RS_OUTOFRESOURCE, RM_APPLICATION, RD_OUT_OF_MEMORY)
typedef struct {
char shortDescription[0x100];
@ -68,13 +75,6 @@ typedef struct {
ticket_info ticketInfo;
} file_info;
#define R_FBI_CANCELLED MAKERESULT(RL_PERMANENT, RS_CANCELED, RM_APPLICATION, 1)
#define R_FBI_ERRNO MAKERESULT(RL_PERMANENT, RS_INTERNAL, RM_APPLICATION, 2)
#define R_FBI_HTTP_RESPONSE_CODE MAKERESULT(RL_PERMANENT, RS_INTERNAL, RM_APPLICATION, 3)
#define R_FBI_WRONG_SYSTEM MAKERESULT(RL_PERMANENT, RS_NOTSUPPORTED, RM_APPLICATION, 4)
#define R_FBI_OUT_OF_MEMORY MAKERESULT(RL_FATAL, RS_OUTOFRESOURCE, RM_APPLICATION, RD_OUT_OF_MEMORY)
typedef enum {
DATAOP_COPY,
DATAOP_DELETE
@ -125,20 +125,20 @@ Handle task_capture_cam(Handle* mutex, u16* buffer, s16 width, s16 height);
Handle task_data_op(data_op_info* info);
void task_clear_ext_save_data(list_item* items, u32* count);
Handle task_populate_ext_save_data(list_item* items, u32* count, u32 max);
void task_clear_ext_save_data(linked_list* items);
Handle task_populate_ext_save_data(linked_list* items);
void task_clear_files(list_item* items, u32* count);
Handle task_populate_files(list_item* items, u32* count, u32 max, file_info* dir);
void task_clear_files(linked_list* items);
Handle task_populate_files(linked_list* items, file_info* dir);
void task_clear_pending_titles(list_item* items, u32* count);
Handle task_populate_pending_titles(list_item* items, u32* count, u32 max);
void task_clear_pending_titles(linked_list* items);
Handle task_populate_pending_titles(linked_list* items);
void task_clear_system_save_data(list_item* items, u32* count);
Handle task_populate_system_save_data(list_item* items, u32* count, u32 max);
void task_clear_system_save_data(linked_list* items);
Handle task_populate_system_save_data(linked_list* items);
void task_clear_tickets(list_item* items, u32* count);
Handle task_populate_tickets(list_item* items, u32* count, u32 max);
void task_clear_tickets(linked_list* items);
Handle task_populate_tickets(linked_list* items);
void task_clear_titles(list_item* items, u32* count);
Handle task_populate_titles(list_item* items, u32* count, u32 max);
void task_clear_titles(linked_list* items);
Handle task_populate_titles(linked_list* items);

View File

@ -6,25 +6,17 @@
#include "action/action.h"
#include "section.h"
#include "../error.h"
#include "../list.h"
#include "../../screen.h"
#define TICKETS_MAX 1024
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};
typedef struct {
list_item items[TICKETS_MAX];
u32 count;
Handle cancelEvent;
bool populated;
} tickets_data;
#define TICKETS_ACTION_COUNT 2
static u32 tickets_action_count = TICKETS_ACTION_COUNT;
static list_item tickets_action_items[TICKETS_ACTION_COUNT] = {
{"Install from CDN", COLOR_TEXT, action_install_cdn},
{"Delete Ticket", COLOR_TEXT, action_delete_ticket},
};
typedef struct {
ticket_info* info;
bool* populated;
@ -34,7 +26,7 @@ static void tickets_action_draw_top(ui_view* view, void* data, float x1, float y
ui_draw_ticket_info(view, ((tickets_action_data*) data)->info, x1, y1, x2, y2);
}
static void tickets_action_update(ui_view* view, void* data, list_item** items, u32** itemCount, list_item* selected, bool selectedTouched) {
static void tickets_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
tickets_action_data* actionData = (tickets_action_data*) data;
if(hidKeysDown() & KEY_B) {
@ -59,9 +51,9 @@ static void tickets_action_update(ui_view* view, void* data, list_item** items,
return;
}
if(*itemCount != &tickets_action_count || *items != tickets_action_items) {
*itemCount = &tickets_action_count;
*items = tickets_action_items;
if(linked_list_size(items) == 0) {
linked_list_add(items, &install_from_cdn);
linked_list_add(items, &delete_ticket);
}
}
@ -85,7 +77,7 @@ static void tickets_draw_top(ui_view* view, void* data, float x1, float y1, floa
}
}
static void tickets_update(ui_view* view, void* data, list_item** items, u32** itemCount, list_item* selected, bool selectedTouched) {
static void tickets_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
tickets_data* listData = (tickets_data*) data;
if(hidKeysDown() & KEY_B) {
@ -99,9 +91,10 @@ static void tickets_update(ui_view* view, void* data, list_item** items, u32** i
}
ui_pop();
task_clear_tickets(items);
list_destroy(view);
task_clear_tickets(listData->items, &listData->count);
free(listData);
return;
}
@ -116,7 +109,7 @@ static void tickets_update(ui_view* view, void* data, list_item** items, u32** i
listData->cancelEvent = 0;
}
listData->cancelEvent = task_populate_tickets(listData->items, &listData->count, TICKETS_MAX);
listData->cancelEvent = task_populate_tickets(items);
listData->populated = true;
}
@ -124,11 +117,6 @@ static void tickets_update(ui_view* view, void* data, list_item** items, u32** i
tickets_action_open((ticket_info*) selected->data, &listData->populated);
return;
}
if(*itemCount != &listData->count || *items != listData->items) {
*itemCount = &listData->count;
*items = listData->items;
}
}
void tickets_open() {

View File

@ -6,52 +6,22 @@
#include "action/action.h"
#include "section.h"
#include "../error.h"
#include "../list.h"
#include "../../screen.h"
#include "task/task.h"
#define TITLES_MAX 1024
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 browse_save_data = {"Browse Save Data", COLOR_TEXT, action_browse_title_save_data};
static list_item import_secure_value = {"Import Secure Value", COLOR_TEXT, action_import_secure_value};
static list_item export_secure_value = {"Export Secure Value", COLOR_TEXT, action_export_secure_value};
static list_item delete_secure_value = {"Delete Secure Value", COLOR_TEXT, action_delete_secure_value};
typedef struct {
list_item items[TITLES_MAX];
u32 count;
Handle cancelEvent;
bool populated;
} titles_data;
#define TITLES_ACTION_COUNT 6
static u32 titles_action_count = TITLES_ACTION_COUNT;
static list_item titles_action_items[TITLES_ACTION_COUNT] = {
{"Launch Title", COLOR_TEXT, action_launch_title},
{"Delete Title", COLOR_TEXT, action_delete_title},
{"Browse Save Data", COLOR_TEXT, action_browse_title_save_data},
{"Import Secure Value", COLOR_TEXT, action_import_secure_value},
{"Export Secure Value", COLOR_TEXT, action_export_secure_value},
{"Delete Secure Value", COLOR_TEXT, action_delete_secure_value},
};
#define CARD_TITLES_ACTION_COUNT 2
static u32 card_titles_action_count = CARD_TITLES_ACTION_COUNT;
static list_item card_titles_action_items[CARD_TITLES_ACTION_COUNT] = {
{"Launch Title", COLOR_TEXT, action_launch_title},
{"Browse Save Data", COLOR_TEXT, action_browse_title_save_data},
};
#define DSIWARE_TITLES_ACTION_COUNT 2
static u32 dsiware_titles_action_count = DSIWARE_TITLES_ACTION_COUNT;
static list_item dsiware_titles_action_items[DSIWARE_TITLES_ACTION_COUNT] = {
{"Launch Title", COLOR_TEXT, action_launch_title},
{"Delete Title", COLOR_TEXT, action_delete_title},
};
#define DSIWARE_CARD_TITLES_ACTION_COUNT 1
static u32 dsiware_card_titles_action_count = DSIWARE_CARD_TITLES_ACTION_COUNT;
static list_item dsiware_card_titles_action_items[DSIWARE_CARD_TITLES_ACTION_COUNT] = {
{"Launch Title", COLOR_TEXT, action_launch_title},
};
typedef struct {
title_info* info;
bool* populated;
@ -61,7 +31,7 @@ static void titles_action_draw_top(ui_view* view, void* data, float x1, float y1
ui_draw_title_info(view, ((titles_action_data*) data)->info, x1, y1, x2, y2);
}
static void titles_action_update(ui_view* view, void* data, list_item** items, u32** itemCount, list_item* selected, bool selectedTouched) {
static void titles_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
titles_action_data* actionData = (titles_action_data*) data;
if(hidKeysDown() & KEY_B) {
@ -86,25 +56,21 @@ static void titles_action_update(ui_view* view, void* data, list_item** items, u
return;
}
if(actionData->info->mediaType == MEDIATYPE_GAME_CARD && actionData->info->twl) {
if(*itemCount != &dsiware_card_titles_action_count || *items != dsiware_card_titles_action_items) {
*itemCount = &dsiware_card_titles_action_count;
*items = dsiware_card_titles_action_items;
if(linked_list_size(items) == 0) {
linked_list_add(items, &launch_title);
if(actionData->info->mediaType != MEDIATYPE_GAME_CARD) {
linked_list_add(items, &delete_title);
}
} else if(actionData->info->mediaType == MEDIATYPE_GAME_CARD) {
if(*itemCount != &card_titles_action_count || *items != card_titles_action_items) {
*itemCount = &card_titles_action_count;
*items = card_titles_action_items;
}
} else if(actionData->info->twl) {
if(*itemCount != &dsiware_titles_action_count || *items != dsiware_titles_action_items) {
*itemCount = &dsiware_titles_action_count;
*items = dsiware_titles_action_items;
}
} else {
if(*itemCount != &titles_action_count || *items != titles_action_items) {
*itemCount = &titles_action_count;
*items = titles_action_items;
if(!actionData->info->twl) {
linked_list_add(items, &browse_save_data);
if(actionData->info->mediaType != MEDIATYPE_GAME_CARD) {
linked_list_add(items, &import_secure_value);
linked_list_add(items, &export_secure_value);
linked_list_add(items, &delete_secure_value);
}
}
}
}
@ -129,7 +95,7 @@ static void titles_draw_top(ui_view* view, void* data, float x1, float y1, float
}
}
static void titles_update(ui_view* view, void* data, list_item** items, u32** itemCount, list_item* selected, bool selectedTouched) {
static void titles_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
titles_data* listData = (titles_data*) data;
if(hidKeysDown() & KEY_B) {
@ -143,9 +109,10 @@ static void titles_update(ui_view* view, void* data, list_item** items, u32** it
}
ui_pop();
task_clear_titles(items);
list_destroy(view);
task_clear_titles(listData->items, &listData->count);
free(listData);
return;
}
@ -160,7 +127,7 @@ static void titles_update(ui_view* view, void* data, list_item** items, u32** it
listData->cancelEvent = 0;
}
listData->cancelEvent = task_populate_titles(listData->items, &listData->count, TITLES_MAX);
listData->cancelEvent = task_populate_titles(items);
listData->populated = true;
}
@ -168,11 +135,6 @@ static void titles_update(ui_view* view, void* data, list_item** items, u32** it
titles_action_open((title_info*) selected->data, &listData->populated);
return;
}
if(*itemCount != &listData->count || *items != listData->items) {
*itemCount = &listData->count;
*items = listData->items;
}
}
void titles_open() {