Load file metadata after populating list.

This commit is contained in:
Steven Smith 2018-02-17 12:39:10 -08:00
parent 0404a33a58
commit cd42e873da
11 changed files with 129 additions and 85 deletions

View File

@ -190,7 +190,7 @@ static void action_delete_internal(linked_list* items, list_item* selected, cons
data->items = items;
file_info* targetInfo = (file_info*) selected->data;
Result targetCreateRes = task_create_file_item(&data->targetItem, targetInfo->archive, targetInfo->path, targetInfo->attributes);
Result targetCreateRes = task_create_file_item(&data->targetItem, targetInfo->archive, targetInfo->path, targetInfo->attributes, true);
if(R_FAILED(targetCreateRes)) {
error_display_res(NULL, NULL, targetCreateRes, "Failed to create target file item.");

View File

@ -309,7 +309,7 @@ static void action_install_cias_internal(linked_list* items, list_item* selected
data->items = items;
file_info* targetInfo = (file_info*) selected->data;
Result targetCreateRes = task_create_file_item(&data->targetItem, targetInfo->archive, targetInfo->path, targetInfo->attributes);
Result targetCreateRes = task_create_file_item(&data->targetItem, targetInfo->archive, targetInfo->path, targetInfo->attributes, true);
if(R_FAILED(targetCreateRes)) {
error_display_res(NULL, NULL, targetCreateRes, "Failed to create target file item.");

View File

@ -285,7 +285,7 @@ static void action_install_tickets_internal(linked_list* items, list_item* selec
data->items = items;
file_info* targetInfo = (file_info*) selected->data;
Result targetCreateRes = task_create_file_item(&data->targetItem, targetInfo->archive, targetInfo->path, targetInfo->attributes);
Result targetCreateRes = task_create_file_item(&data->targetItem, targetInfo->archive, targetInfo->path, targetInfo->attributes, true);
if(R_FAILED(targetCreateRes)) {
error_display_res(NULL, NULL, targetCreateRes, "Failed to create target file item.");

View File

@ -192,6 +192,7 @@ static Result action_install_url_open_dst(void* data, u32 index, void* initialRe
installData->ticketInfo.titleId = ticket_get_title_id((u8*) initialReadBlock);
installData->ticketInfo.inUse = false;
installData->ticketInfo.loaded = true;
AM_DeleteTicket(installData->ticketInfo.titleId);
res = AM_InstallTicketBegin(handle);

View File

@ -38,7 +38,7 @@ static void action_new_folder_onresponse(ui_view* view, void* data, SwkbdButton
if(R_SUCCEEDED(res)) {
list_item* folderItem = NULL;
if(R_SUCCEEDED(task_create_file_item(&folderItem, parentDir->archive, path, FS_ATTRIBUTE_DIRECTORY))) {
if(R_SUCCEEDED(task_create_file_item(&folderItem, parentDir->archive, path, FS_ATTRIBUTE_DIRECTORY, true))) {
linked_list_add(newFolderData->items, folderItem);
linked_list_sort(newFolderData->items, NULL, task_compare_files);
}

View File

@ -84,7 +84,7 @@ static Result action_paste_contents_make_dst_directory(void* data, u32 index) {
if(strncmp(parentPath, baseDstPath, FILE_PATH_MAX) == 0) {
list_item* dstItem = NULL;
if(R_SUCCEEDED(res) && R_SUCCEEDED(task_create_file_item(&dstItem, pasteData->target->archive, dstPath, attributes))) {
if(R_SUCCEEDED(res) && R_SUCCEEDED(task_create_file_item(&dstItem, pasteData->target->archive, dstPath, attributes, true))) {
linked_list_add(pasteData->items, dstItem);
}
}
@ -189,7 +189,7 @@ static Result action_paste_contents_close_dst(void* data, u32 index, bool succee
if(strncmp(parentPath, baseDstPath, FILE_PATH_MAX) == 0) {
list_item* dstItem = NULL;
if(R_SUCCEEDED(task_create_file_item(&dstItem, pasteData->target->archive, dstPath, ((file_info*) ((list_item*) linked_list_get(&pasteData->contents, index))->data)->attributes & ~FS_ATTRIBUTE_READ_ONLY))) {
if(R_SUCCEEDED(task_create_file_item(&dstItem, pasteData->target->archive, dstPath, ((file_info*) ((list_item*) linked_list_get(&pasteData->contents, index))->data)->attributes & ~FS_ATTRIBUTE_READ_ONLY, true))) {
linked_list_add(pasteData->items, dstItem);
}
}
@ -342,7 +342,7 @@ void action_paste_contents(linked_list* items, list_item* selected) {
data->items = items;
file_info* targetInfo = (file_info*) selected->data;
Result targetCreateRes = task_create_file_item(&data->targetItem, targetInfo->archive, targetInfo->path, targetInfo->attributes);
Result targetCreateRes = task_create_file_item(&data->targetItem, targetInfo->archive, targetInfo->path, targetInfo->attributes, true);
if(R_FAILED(targetCreateRes)) {
error_display_res(NULL, NULL, targetCreateRes, "Failed to create target file item.");

View File

@ -37,7 +37,81 @@ int task_compare_files(void* userData, const void* p1, const void* p2) {
}
}
Result task_create_file_item(list_item** out, FS_Archive archive, const char* path, u32 attributes) {
static void task_populate_files_retrieve_meta(file_info* fileInfo) {
FS_Path* fileFsPath = fs_make_path_utf8(fileInfo->path);
if(fileFsPath != NULL) {
Handle fileHandle;
if(R_SUCCEEDED(FSUSER_OpenFile(&fileHandle, fileInfo->archive, *fileFsPath, FS_OPEN_READ, 0))) {
if(fileInfo->attributes == 0 && R_FAILED(FSFILE_GetAttributes(fileHandle, &fileInfo->attributes))) {
fileInfo->attributes = 0;
}
FSFILE_GetSize(fileHandle, &fileInfo->size);
if(fileInfo->isCia) {
AM_TitleEntry titleEntry;
if(R_SUCCEEDED(AM_GetCiaFileInfo(MEDIATYPE_SD, &titleEntry, fileHandle))) {
fileInfo->ciaInfo.titleId = titleEntry.titleID;
fileInfo->ciaInfo.version = titleEntry.version;
fileInfo->ciaInfo.installedSize = titleEntry.size;
fileInfo->ciaInfo.hasMeta = false;
if(fs_get_title_destination(titleEntry.titleID) != MEDIATYPE_SD && R_SUCCEEDED(AM_GetCiaFileInfo(MEDIATYPE_NAND, &titleEntry, fileHandle))) {
fileInfo->ciaInfo.installedSize = titleEntry.size;
}
SMDH* smdh = (SMDH*) calloc(1, sizeof(SMDH));
if(smdh != NULL) {
if(R_SUCCEEDED(cia_file_get_smdh(smdh, fileHandle))) {
if(smdh->magic[0] == 'S' && smdh->magic[1] == 'M' && smdh->magic[2] == 'D' && smdh->magic[3] == 'H') {
SMDH_title* smdhTitle = smdh_select_title(smdh);
fileInfo->ciaInfo.hasMeta = true;
utf16_to_utf8((uint8_t*) fileInfo->ciaInfo.meta.shortDescription, smdhTitle->shortDescription, sizeof(fileInfo->ciaInfo.meta.shortDescription) - 1);
utf16_to_utf8((uint8_t*) fileInfo->ciaInfo.meta.longDescription, smdhTitle->longDescription, sizeof(fileInfo->ciaInfo.meta.longDescription) - 1);
utf16_to_utf8((uint8_t*) fileInfo->ciaInfo.meta.publisher, smdhTitle->publisher, sizeof(fileInfo->ciaInfo.meta.publisher) - 1);
fileInfo->ciaInfo.meta.region = smdh->region;
fileInfo->ciaInfo.meta.texture = screen_allocate_free_texture();
screen_load_texture_tiled(fileInfo->ciaInfo.meta.texture, smdh->largeIcon, sizeof(smdh->largeIcon), 48, 48, GPU_RGB565, false);
}
}
free(smdh);
}
fileInfo->ciaInfo.loaded = true;
} else {
fileInfo->isCia = false;
}
} else if(fileInfo->isTicket) {
u32 bytesRead = 0;
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)) {
fileInfo->ticketInfo.loaded = true;
fileInfo->ticketInfo.titleId = __builtin_bswap64(titleId);
fileInfo->ticketInfo.inUse = false;
} else {
fileInfo->isTicket = false;
}
} else {
fileInfo->isTicket = false;
}
}
FSFILE_Close(fileHandle);
}
fs_free_path_utf8(fileFsPath);
}
}
Result task_create_file_item(list_item** out, FS_Archive archive, const char* path, u32 attributes, bool meta) {
Result res = 0;
list_item* item = (list_item*) calloc(1, sizeof(list_item));
@ -46,13 +120,13 @@ Result task_create_file_item(list_item** out, FS_Archive archive, const char* pa
if(fileInfo != NULL) {
fileInfo->archive = archive;
string_get_path_file(fileInfo->name, path, FILE_NAME_MAX);
fileInfo->attributes = attributes != UINT32_MAX ? attributes : 0;
fileInfo->attributes = attributes;
fileInfo->size = 0;
fileInfo->isCia = false;
fileInfo->isTicket = false;
if((attributes != UINT32_MAX && (attributes & FS_ATTRIBUTE_DIRECTORY)) || fs_is_dir(archive, path)) {
if((attributes & FS_ATTRIBUTE_DIRECTORY) || fs_is_dir(archive, path)) {
item->color = COLOR_DIRECTORY;
size_t len = strlen(path);
@ -62,7 +136,7 @@ Result task_create_file_item(list_item** out, FS_Archive archive, const char* pa
strncpy(fileInfo->path, path, FILE_PATH_MAX);
}
if(attributes == UINT32_MAX) {
if(attributes == 0) {
fileInfo->attributes = FS_ATTRIBUTE_DIRECTORY;
}
} else {
@ -70,69 +144,14 @@ Result task_create_file_item(list_item** out, FS_Archive archive, const char* pa
strncpy(fileInfo->path, path, FILE_PATH_MAX);
FS_Path* fileFsPath = fs_make_path_utf8(fileInfo->path);
if(fileFsPath != NULL) {
Handle fileHandle;
if(R_SUCCEEDED(FSUSER_OpenFile(&fileHandle, archive, *fileFsPath, FS_OPEN_READ, 0))) {
if(attributes == UINT32_MAX && R_FAILED(FSFILE_GetAttributes(fileHandle, &fileInfo->attributes))) {
fileInfo->attributes = 0;
}
if(fs_filter_cias(NULL, fileInfo->path, fileInfo->attributes)) {
fileInfo->isCia = true;
} else if(fs_filter_tickets(NULL, fileInfo->path, fileInfo->attributes)) {
fileInfo->isTicket = true;
}
FSFILE_GetSize(fileHandle, &fileInfo->size);
if(fs_filter_cias(NULL, fileInfo->path, fileInfo->attributes)) {
AM_TitleEntry titleEntry;
if(R_SUCCEEDED(AM_GetCiaFileInfo(MEDIATYPE_SD, &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(fs_get_title_destination(titleEntry.titleID) != MEDIATYPE_SD && R_SUCCEEDED(AM_GetCiaFileInfo(MEDIATYPE_NAND, &titleEntry, fileHandle))) {
fileInfo->ciaInfo.installedSize = titleEntry.size;
}
SMDH* smdh = (SMDH*) calloc(1, sizeof(SMDH));
if(smdh != NULL) {
if(R_SUCCEEDED(cia_file_get_smdh(smdh, fileHandle))) {
if(smdh->magic[0] == 'S' && smdh->magic[1] == 'M' && smdh->magic[2] == 'D' && smdh->magic[3] == 'H') {
SMDH_title* smdhTitle = smdh_select_title(smdh);
fileInfo->ciaInfo.hasMeta = true;
utf16_to_utf8((uint8_t*) fileInfo->ciaInfo.meta.shortDescription, smdhTitle->shortDescription, sizeof(fileInfo->ciaInfo.meta.shortDescription) - 1);
utf16_to_utf8((uint8_t*) fileInfo->ciaInfo.meta.longDescription, smdhTitle->longDescription, sizeof(fileInfo->ciaInfo.meta.longDescription) - 1);
utf16_to_utf8((uint8_t*) fileInfo->ciaInfo.meta.publisher, smdhTitle->publisher, sizeof(fileInfo->ciaInfo.meta.publisher) - 1);
fileInfo->ciaInfo.meta.region = smdh->region;
fileInfo->ciaInfo.meta.texture = screen_allocate_free_texture();
screen_load_texture_tiled(fileInfo->ciaInfo.meta.texture, smdh->largeIcon, sizeof(smdh->largeIcon), 48, 48, GPU_RGB565, false);
}
}
free(smdh);
}
}
} else if(fs_filter_tickets(NULL, fileInfo->path, fileInfo->attributes)) {
u32 bytesRead = 0;
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)) {
fileInfo->isTicket = true;
fileInfo->ticketInfo.titleId = __builtin_bswap64(titleId);
fileInfo->ticketInfo.inUse = false;
}
}
}
FSFILE_Close(fileHandle);
}
fs_free_path_utf8(fileFsPath);
if(meta) {
task_populate_files_retrieve_meta(fileInfo);
}
}
@ -177,7 +196,7 @@ static void task_populate_files_thread(void* arg) {
Result res = 0;
list_item* baseItem = NULL;
if(R_SUCCEEDED(res = task_create_file_item(&baseItem, data->archive, data->path, UINT32_MAX))) {
if(R_SUCCEEDED(res = task_create_file_item(&baseItem, data->archive, data->path, 0, false))) {
file_info* baseInfo = (file_info*) baseItem->data;
if(baseInfo->attributes & FS_ATTRIBUTE_DIRECTORY) {
strncpy(baseItem->name, "<current directory>", LIST_ITEM_NAME_MAX);
@ -227,7 +246,7 @@ static void task_populate_files_thread(void* arg) {
snprintf(path, FILE_PATH_MAX, "%s%s", curr->path, name);
list_item* item = NULL;
if(R_SUCCEEDED(res = task_create_file_item(&item, curr->archive, path, entries[i].attributes))) {
if(R_SUCCEEDED(res = task_create_file_item(&item, curr->archive, path, entries[i].attributes, false))) {
if(data->recursive && (((file_info*) item->data)->attributes & FS_ATTRIBUTE_DIRECTORY)) {
linked_list_add(&queue, item);
} else {
@ -260,6 +279,23 @@ static void task_populate_files_thread(void* arg) {
}
}
if(R_SUCCEEDED(res)) {
linked_list_iter iter;
linked_list_iterate(data->items, &iter);
while(linked_list_iter_has_next(&iter)) {
svcWaitSynchronization(task_get_pause_event(), U64_MAX);
if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) {
break;
}
list_item* item = (list_item*) linked_list_iter_next(&iter);
file_info* fileInfo = (file_info*) item->data;
task_populate_files_retrieve_meta(fileInfo);
}
}
svcCloseHandle(data->cancelEvent);
data->result = res;

View File

@ -9,6 +9,8 @@ typedef struct linked_list_s linked_list;
typedef struct list_item_s list_item;
typedef struct cia_info_s {
bool loaded;
u64 titleId;
u16 version;
u64 installedSize;
@ -50,5 +52,5 @@ typedef struct populate_files_data_s {
int task_compare_files(void* userData, const void* p1, const void* p2);
void task_free_file(list_item* item);
void task_clear_files(linked_list* items);
Result task_create_file_item(list_item** out, FS_Archive archive, const char* path, u32 attributes);
Result task_create_file_item(list_item** out, FS_Archive archive, const char* path, u32 attributes, bool meta);
Result task_populate_files(populate_files_data* data);

View File

@ -58,6 +58,7 @@ static void task_populate_tickets_thread(void* arg) {
ticket_info* ticketInfo = (ticket_info*) calloc(1, sizeof(ticket_info));
if(ticketInfo != NULL) {
ticketInfo->titleId = ticketIds[i];
ticketInfo->loaded = true;
snprintf(item->name, LIST_ITEM_NAME_MAX, "%016llX", ticketIds[i]);
item->data = ticketInfo;

View File

@ -4,6 +4,8 @@ typedef struct linked_list_s linked_list;
typedef struct list_item_s list_item;
typedef struct ticket_info_s {
bool loaded;
u64 titleId;
bool inUse;
} ticket_info;

View File

@ -138,7 +138,7 @@ void task_draw_file_info(ui_view* view, void* data, float x1, float y1, float x2
infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Size: %.2f %s\n",
ui_get_display_size(info->size), ui_get_display_size_units(info->size));
if(info->isCia) {
if(info->isCia && info->ciaInfo.loaded) {
char regionString[64];
if(info->ciaInfo.hasMeta) {
@ -159,7 +159,7 @@ void task_draw_file_info(ui_view* view, void* data, float x1, float y1, float x2
regionString,
ui_get_display_size(info->ciaInfo.installedSize),
ui_get_display_size_units(info->ciaInfo.installedSize));
} else if(info->isTicket) {
} else if(info->isTicket && info->ticketInfo.loaded) {
infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Ticket ID: %016llX", info->ticketInfo.titleId);
}
}
@ -211,16 +211,18 @@ void task_draw_system_save_data_info(ui_view* view, void* data, float x1, float
void task_draw_ticket_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
ticket_info* info = (ticket_info*) data;
char infoText[512];
if(info->loaded) {
char infoText[512];
snprintf(infoText, sizeof(infoText), "Title ID: %016llX", info->titleId);
snprintf(infoText, sizeof(infoText), "Title ID: %016llX", info->titleId);
float infoWidth;
screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f);
float infoWidth;
screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f);
float infoX = x1 + (x2 - x1 - infoWidth) / 2;
float infoY = y1 + (y2 - y1) / 2 - 8;
screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true);
float infoX = x1 + (x2 - x1 - infoWidth) / 2;
float infoY = y1 + (y2 - y1) / 2 - 8;
screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true);
}
}
void task_draw_title_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) {