static void files_repopulate(files_data* listData) { if(listData->cancelEvent != 0) { svcSignalEvent(listData->cancelEvent); while(svcWaitSynchronization(listData->cancelEvent, 0) == 0) { svcSleepThread(1000000); } listData->cancelEvent = 0; } while(!util_is_dir(&listData->archive, listData->currDir.path)) { char parentPath[PATH_MAX]; util_get_parent_path(parentPath, listData->currDir.path, PATH_MAX); strncpy(listData->currDir.path, parentPath, PATH_MAX); util_get_path_file(listData->currDir.name, listData->currDir.path, NAME_MAX); util_get_parent_path(parentPath, listData->currDir.path, PATH_MAX); strncpy(listData->parentDir.path, parentPath, PATH_MAX); 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->populated = true; }
static void files_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { files_data* listData = (files_data*) data; while(!util_is_dir(listData->archive, listData->currDir)) { char parentDir[FILE_PATH_MAX] = {'\0'}; util_get_parent_path(parentDir, listData->currDir, FILE_PATH_MAX); files_navigate(listData, items, parentDir); } if(hidKeysDown() & KEY_B) { if(strncmp(listData->currDir, "/", FILE_PATH_MAX) == 0) { ui_pop(); files_free_data(listData); task_clear_files(items); list_destroy(view); return; } else { char parentDir[FILE_PATH_MAX] = {'\0'}; util_get_parent_path(parentDir, listData->currDir, FILE_PATH_MAX); files_navigate(listData, items, parentDir); } } if(hidKeysDown() & KEY_SELECT) { files_filters_open(listData); return; } if((hidKeysDown() & KEY_Y) && listData->dirItem != NULL) { files_action_open(items, listData->dirItem, listData); return; } if(selected != NULL && selected->data != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) { file_info* fileInfo = (file_info*) selected->data; if(fileInfo->isDirectory) { files_navigate(listData, items, fileInfo->path); } else { files_action_open(items, selected, listData); return; } } if(!listData->populated || (hidKeysDown() & KEY_X)) { files_repopulate(listData, items); } if(listData->populateData.finished && R_FAILED(listData->populateData.result)) { error_display_res(NULL, NULL, NULL, listData->populateData.result, "Failed to populate file list."); listData->populateData.result = 0; } }
static void files_update(ui_view* view, void* data, list_item** items, u32** itemCount, list_item* selected, bool selectedTouched) { files_data* listData = (files_data*) data; if(hidKeysDown() & KEY_B) { if(strcmp(listData->currDir.path, "/") == 0) { if(listData->archive.handle != 0) { FSUSER_CloseArchive(&listData->archive); listData->archive.handle = 0; } if(listData->archivePath != NULL) { free(listData->archivePath); listData->archivePath = NULL; } if(listData->cancelEvent != 0) { svcSignalEvent(listData->cancelEvent); while(svcWaitSynchronization(listData->cancelEvent, 0) == 0) { svcSleepThread(1000000); } listData->cancelEvent = 0; } ui_pop(); list_destroy(view); free(listData); return; } else { files_navigate(listData, listData->parentDir.path); } } if(hidKeysDown() & KEY_Y) { files_action_open(&listData->currDir, &listData->populated); return; } if(selected != NULL && selected->data != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) { file_info* fileInfo = (file_info*) selected->data; if(util_is_dir(&listData->archive, fileInfo->path)) { files_navigate(listData, fileInfo->path); } else { files_action_open(fileInfo, &listData->populated); return; } } if(!listData->populated || (hidKeysDown() & KEY_X)) { files_repopulate(listData); } if(*itemCount != &listData->count || *items != listData->items) { *itemCount = &listData->count; *items = listData->items; } }
void action_paste_contents(linked_list* items, list_item* selected) { if(!clipboard_has_contents()) { prompt_display("Failure", "Clipboard empty.", COLOR_TEXT, false, NULL, NULL, NULL); return; } paste_files_data* data = (paste_files_data*) calloc(1, sizeof(paste_files_data)); if(data == NULL) { error_display(NULL, NULL, "Failed to allocate paste files data."); return; } data->items = items; data->target = (file_info*) selected->data; data->pasteInfo.data = data; data->pasteInfo.op = DATAOP_COPY; data->pasteInfo.copyBufferSize = 256 * 1024; data->pasteInfo.copyEmpty = true; data->pasteInfo.isSrcDirectory = action_paste_files_is_src_directory; data->pasteInfo.makeDstDirectory = action_paste_files_make_dst_directory; data->pasteInfo.openSrc = action_paste_files_open_src; data->pasteInfo.closeSrc = action_paste_files_close_src; data->pasteInfo.getSrcSize = action_paste_files_get_src_size; data->pasteInfo.readSrc = action_paste_files_read_src; data->pasteInfo.openDst = action_paste_files_open_dst; data->pasteInfo.closeDst = action_paste_files_close_dst; data->pasteInfo.writeDst = action_paste_files_write_dst; data->pasteInfo.suspendCopy = action_paste_files_suspend_copy; data->pasteInfo.restoreCopy = action_paste_files_restore_copy; data->pasteInfo.suspend = action_paste_files_suspend; data->pasteInfo.restore = action_paste_files_restore; data->pasteInfo.error = action_paste_files_error; data->pasteInfo.finished = true; linked_list_init(&data->contents); populate_files_data popData; memset(&popData, 0, sizeof(popData)); popData.items = &data->contents; popData.archive = clipboard_get_archive(); strncpy(popData.path, clipboard_get_path(), FILE_PATH_MAX); popData.recursive = true; popData.includeBase = !clipboard_is_contents_only() || !util_is_dir(clipboard_get_archive(), clipboard_get_path()); popData.filter = NULL; popData.filterData = NULL; Result listRes = task_populate_files(&popData); if(R_FAILED(listRes)) { error_display_res(NULL, NULL, listRes, "Failed to initiate clipboard content list population."); action_paste_files_free_data(data); return; } while(!popData.finished) { svcSleepThread(1000000); } if(R_FAILED(popData.result)) { error_display_res(NULL, NULL, popData.result, "Failed to populate clipboard content list."); action_paste_files_free_data(data); return; } data->pasteInfo.total = linked_list_size(&data->contents); data->pasteInfo.processed = data->pasteInfo.total; prompt_display("Confirmation", "Paste clipboard contents to the current directory?", COLOR_TEXT, true, data, action_paste_files_draw_top, action_paste_files_onresponse); }
Result task_create_file_item(list_item** out, FS_Archive archive, const char* path) { Result res = 0; 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 = archive; util_get_path_file(fileInfo->name, path, FILE_NAME_MAX); fileInfo->attributes = 0; fileInfo->size = 0; fileInfo->isCia = false; fileInfo->isTicket = false; if(util_is_dir(archive, path)) { item->color = COLOR_DIRECTORY; size_t len = strlen(path); if(len > 1 && path[len - 1] != '/') { snprintf(fileInfo->path, FILE_PATH_MAX, "%s/", path); } else { strncpy(fileInfo->path, path, FILE_PATH_MAX); } fileInfo->attributes = FS_ATTRIBUTE_DIRECTORY; } else { item->color = COLOR_FILE; strncpy(fileInfo->path, path, FILE_PATH_MAX); FS_Path* fileFsPath = util_make_path_utf8(fileInfo->path); if(fileFsPath != NULL) { Handle fileHandle; if(R_SUCCEEDED(FSUSER_OpenFile(&fileHandle, archive, *fileFsPath, FS_OPEN_READ, 0))) { FSFILE_GetAttributes(fileHandle, &fileInfo->attributes); 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))) { 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 & 0x0000801000000002) != 0 && 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(util_get_cia_file_smdh(smdh, fileHandle))) { if(smdh->magic[0] == 'S' && smdh->magic[1] == 'M' && smdh->magic[2] == 'D' && smdh->magic[3] == 'H') { 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.region = smdh->region; fileInfo->ciaInfo.meta.texture = screen_load_texture_tiled_auto(smdh->largeIcon, sizeof(smdh->largeIcon), 48, 48, GPU_RGB565, false); } } free(smdh); } } } else if(strcasecmp(&fileInfo->path[len - 4], ".tik") == 0) { 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); } } } } FSFILE_Close(fileHandle); } util_free_path_utf8(fileFsPath); } } strncpy(item->name, fileInfo->name, LIST_ITEM_NAME_MAX); item->data = fileInfo; *out = item; } else { free(item); res = R_FBI_OUT_OF_MEMORY; } } else { res = R_FBI_OUT_OF_MEMORY; } return res; }
static void files_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { files_data* listData = (files_data*) data; if(listData->populated) { // Detect whether the current directory was renamed by an action. list_item* currDirItem = linked_list_get(items, 0); if(currDirItem != NULL && strncmp(listData->currDir, ((file_info*) currDirItem->data)->path, FILE_PATH_MAX) != 0) { strncpy(listData->currDir, ((file_info*) currDirItem->data)->path, FILE_PATH_MAX); } } while(!util_is_dir(listData->archive, listData->currDir)) { char parentDir[FILE_PATH_MAX] = {'\0'}; util_get_parent_path(parentDir, listData->currDir, FILE_PATH_MAX); files_navigate(listData, items, parentDir); } if(hidKeysDown() & KEY_B) { if(strncmp(listData->currDir, "/", FILE_PATH_MAX) == 0) { ui_pop(); files_free_data(listData); task_clear_files(items); list_destroy(view); return; } else { char parentDir[FILE_PATH_MAX] = {'\0'}; util_get_parent_path(parentDir, listData->currDir, FILE_PATH_MAX); files_navigate(listData, items, parentDir); } } if(hidKeysDown() & KEY_SELECT) { files_filters_open(listData); return; } if(selected != NULL && selected->data != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) { file_info* fileInfo = (file_info*) selected->data; if((fileInfo->attributes & FS_ATTRIBUTE_DIRECTORY) && strncmp(selected->name, "<current directory>", LIST_ITEM_NAME_MAX) != 0) { files_navigate(listData, items, fileInfo->path); } else { files_action_open(items, selected, listData); return; } } if(!listData->populated || (hidKeysDown() & KEY_X)) { files_repopulate(listData, items); } if(listData->populateData.finished && R_FAILED(listData->populateData.result)) { error_display_res(NULL, NULL, listData->populateData.result, "Failed to populate file list."); listData->populateData.result = 0; } }