mirror of
https://gitlab.com/Theopse/fbi-i18n-zh.git
synced 2025-04-06 03:58:02 +08:00
Use linked lists to store UI list contents.
This commit is contained in:
parent
9c1a7c33fb
commit
d9b1527f2e
222
source/core/linkedlist.c
Normal file
222
source/core/linkedlist.c
Normal 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
40
source/core/linkedlist.h
Normal 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);
|
@ -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.");
|
||||
|
120
source/ui/list.c
120
source/ui/list.c
@ -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);
|
||||
}
|
@ -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);
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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.");
|
||||
|
@ -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() {
|
||||
|
@ -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, ©);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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();
|
||||
|
@ -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() {
|
||||
|
@ -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)) {
|
||||
|
@ -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);
|
||||
|
@ -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)) {
|
||||
|
@ -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)) {
|
||||
|
@ -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)) {
|
||||
|
@ -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)) {
|
||||
|
@ -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);
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user